PERFORCE change 95632 for review
Todd Miller
millert at FreeBSD.org
Wed Apr 19 22:05:01 UTC 2006
http://perforce.freebsd.org/chv.cgi?CH=95632
Change 95632 by millert at millert_g5tower on 2006/04/19 22:03:34
Make sedarwin vs. selinux diffs smaller. Get rid of
flask_types.h and make sure the userland sebsd.h gets used
where appropriate. Remove KERNEL/_KERNEL #ifdefs now that
userland and kernel code is separate. Remove most APPLE
and FreeBSD #ifdefs--they are not really useful.
Affected files ...
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/avc/av_inherit.h#3 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/avc/av_perm_to_string.h#8 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/avc/avc-selinux.c#2 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/avc/avc.c#10 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/avc/avc.h#5 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/avc/avc_ss.h#4 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/flask.h#7 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/flask/mkaccess_vector.sh#3 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/flask/mkflask.sh#4 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/sebsd.c#38 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/sebsd.h#7 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/sebsd_labels.h#4 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/sebsd_syscall.c#9 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/sebsd_syscalls.h#7 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/sebsd_sysctl.c#6 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/ss/avtab.c#4 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/ss/avtab.h#4 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/ss/conditional.c#3 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/ss/constraint.h#4 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/ss/ebitmap.c#5 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/ss/ebitmap.h#4 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/ss/global.h#5 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/ss/hashtab.c#4 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/ss/init.c#5 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/ss/mach_av.c#10 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/ss/mls.h#4 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/ss/mls_types.h#3 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/ss/policydb.c#6 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/ss/policydb.h#4 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/ss/queue.c#5 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/ss/security.h#5 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/ss/services.c#6 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/ss/sidtab.c#4 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/ss/sidtab.h#5 edit
.. //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/ss/symtab.c#4 edit
Differences ...
==== //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/avc/av_inherit.h#3 (text+ko) ====
@@ -3,9 +3,9 @@
typedef struct
{
- security_class_t tclass;
+ u16 tclass;
char **common_pts;
- access_vector_t common_base;
+ u32 common_base;
} av_inherit_t;
static av_inherit_t av_inherit[] = {
==== //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/avc/av_perm_to_string.h#8 (text+ko) ====
@@ -3,8 +3,8 @@
typedef struct
{
- security_class_t tclass;
- access_vector_t value;
+ u16 tclass;
+ u32 value;
char *name;
} av_perm_to_string_t;
==== //depot/projects/trustedbsd/sedarwin7/src/sedarwin/sedarwin/avc/avc-selinux.c#2 (text+ko) ====
@@ -1,56 +1,219 @@
-
-/* -*- linux-c -*- */
-
/*
- * Author: Stephen Smalley, NAI Labs, <ssmalley at nai.com>
+ * Implementation of the kernel access vector cache (AVC).
+ *
+ * Authors: Stephen Smalley, <sds at epoch.ncsc.mil>
+ * James Morris <jmorris at redhat.com>
+ *
+ * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris at redhat.com>
*
- * The access vector cache was originally written while I was employed by NSA,
- * and has undergone some revisions since I joined NAI Labs, but is largely
- * unchanged.
- */
-
-/*
- * Implementation of the kernel access vector cache (AVC).
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
*/
-
#include <linux/types.h>
-#include <linux/flask/avc.h>
-#include <linux/flask/avc_ss.h>
-#include <linux/flask/class_to_string.h>
-#include <linux/flask/common_perm_to_string.h>
-#include <linux/flask/av_inherit.h>
-#include <linux/flask/av_perm_to_string.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/dcache.h>
+#include <linux/init.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <linux/un.h>
#include <net/af_unix.h>
#include <linux/ip.h>
-#include <linux/udp.h>
-#include <linux/tcp.h>
-#include "selinux_plug.h"
+#include <linux/audit.h>
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
+#include "avc.h"
+#include "avc_ss.h"
+#ifdef CONFIG_AUDIT
+#include "class_to_string.h"
+#endif
+#include "common_perm_to_string.h"
+#include "av_inherit.h"
+#include "av_perm_to_string.h"
+#include "objsec.h"
+
+#define AVC_CACHE_SLOTS 512
+#define AVC_CACHE_MAXNODES 410
+
+struct avc_entry {
+ u32 ssid;
+ u32 tsid;
+ u16 tclass;
+ struct av_decision avd;
+ int used; /* used recently */
+};
+
+struct avc_node {
+ struct avc_entry ae;
+ struct avc_node *next;
+};
+
+struct avc_cache {
+ struct avc_node *slots[AVC_CACHE_SLOTS];
+ u32 lru_hint; /* LRU hint for reclaim scan */
+ u32 active_nodes;
+ u32 latest_notif; /* latest revocation notification */
+};
+
+struct avc_callback_node {
+ int (*callback) (u32 event, u32 ssid, u32 tsid,
+ u16 tclass, u32 perms,
+ u32 *out_retained);
+ u32 events;
+ u32 ssid;
+ u32 tsid;
+ u16 tclass;
+ u32 perms;
+ struct avc_callback_node *next;
+};
+
+static spinlock_t avc_lock = SPIN_LOCK_UNLOCKED;
+static struct avc_node *avc_node_freelist;
+static struct avc_cache avc_cache;
+static unsigned avc_cache_stats[AVC_NSTATS];
+static struct avc_callback_node *avc_callbacks;
+
+static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
+{
+ return (ssid ^ (tsid<<2) ^ (tclass<<4)) & (AVC_CACHE_SLOTS - 1);
+}
+
+#ifdef AVC_CACHE_STATS
+static inline void avc_cache_stats_incr(int type)
+{
+ avc_cache_stats[type]++;
+}
+
+static inline void avc_cache_stats_add(int type, unsigned val)
+{
+ avc_cache_stats[type] += val;
+}
+#else
+static inline void avc_cache_stats_incr(int type)
+{ }
-#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
-int avc_debug_always_allow = 1;
+static inline void avc_cache_stats_add(int type, unsigned val)
+{ }
#endif
-spinlock_t avc_lock = SPIN_LOCK_UNLOCKED;
+/**
+ * avc_dump_av - Display an access vector in human-readable form.
+ * @tclass: target security class
+ * @av: access vector
+ */
+void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
+{
+ char **common_pts = NULL;
+ u32 common_base = 0;
+ int i, i2, perm;
+
+ if (av == 0) {
+ audit_log_format(ab, " null");
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(av_inherit); i++) {
+ if (av_inherit[i].tclass == tclass) {
+ common_pts = av_inherit[i].common_pts;
+ common_base = av_inherit[i].common_base;
+ break;
+ }
+ }
+
+ audit_log_format(ab, " {");
+ i = 0;
+ perm = 1;
+ while (perm < common_base) {
+ if (perm & av)
+ audit_log_format(ab, " %s", common_pts[i]);
+ i++;
+ perm <<= 1;
+ }
+
+ while (i < sizeof(av) * 8) {
+ if (perm & av) {
+ for (i2 = 0; i2 < ARRAY_SIZE(av_perm_to_string); i2++) {
+ if ((av_perm_to_string[i2].tclass == tclass) &&
+ (av_perm_to_string[i2].value == perm))
+ break;
+ }
+ if (i2 < ARRAY_SIZE(av_perm_to_string))
+ audit_log_format(ab, " %s",
+ av_perm_to_string[i2].name);
+ }
+ i++;
+ perm <<= 1;
+ }
+
+ audit_log_format(ab, " }");
+}
+
+/**
+ * avc_dump_query - Display a SID pair and a class in human-readable form.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ */
+void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tclass)
+{
+ int rc;
+ char *scontext;
+ u32 scontext_len;
+
+ rc = security_sid_to_context(ssid, &scontext, &scontext_len);
+ if (rc)
+ audit_log_format(ab, "ssid=%d", ssid);
+ else {
+ audit_log_format(ab, "scontext=%s", scontext);
+ kfree(scontext);
+ }
+
+ rc = security_sid_to_context(tsid, &scontext, &scontext_len);
+ if (rc)
+ audit_log_format(ab, " tsid=%d", tsid);
+ else {
+ audit_log_format(ab, " tcontext=%s", scontext);
+ kfree(scontext);
+ }
+ audit_log_format(ab, " tclass=%s", class_to_string[tclass]);
+}
-unsigned avc_cache_stats[AVC_NSTATS];
+/**
+ * avc_init - Initialize the AVC.
+ *
+ * Initialize the access vector cache.
+ */
+void __init avc_init(void)
+{
+ struct avc_node *new;
+ int i;
+ for (i = 0; i < AVC_CACHE_MAXNODES; i++) {
+ new = kmalloc(sizeof(*new), GFP_ATOMIC);
+ if (!new) {
+ printk(KERN_WARNING "avc: only able to allocate "
+ "%d entries\n", i);
+ break;
+ }
+ memset(new, 0, sizeof(*new));
+ new->next = avc_node_freelist;
+ avc_node_freelist = new;
+ }
+ audit_log(current->audit_context, "AVC INITIALIZED\n");
+}
#if 0
static void avc_hash_eval(char *tag)
{
- int i, chain_len, max_chain_len, slots_used;
- avc_node_t *node;
+ int i, chain_len, max_chain_len, slots_used;
+ struct avc_node *node;
+ unsigned long flags;
- spin_lock(&avc_lock);
+ spin_lock_irqsave(&avc_lock,flags);
slots_used = 0;
max_chain_len = 0;
@@ -68,346 +231,838 @@
}
}
- spin_unlock(&avc_lock);
+ spin_unlock_irqrestore(&avc_lock,flags);
- printk("\n%s avc: %d entries and %d/%d buckets used, longest chain length %d\n",
- tag, avc_cache.activeNodes, slots_used, AVC_CACHE_SLOTS, max_chain_len);
+ printk(KERN_INFO "\n");
+ printk(KERN_INFO "%s avc: %d entries and %d/%d buckets used, longest "
+ "chain length %d\n", tag, avc_cache.active_nodes, slots_used,
+ AVC_CACHE_SLOTS, max_chain_len);
}
#else
-#define avc_hash_eval(t)
+static inline void avc_hash_eval(char *tag)
+{ }
#endif
+static inline struct avc_node *avc_reclaim_node(void)
+{
+ struct avc_node *prev, *cur;
+ int hvalue, try;
+ hvalue = avc_cache.lru_hint;
+ for (try = 0; try < 2; try++) {
+ do {
+ prev = NULL;
+ cur = avc_cache.slots[hvalue];
+ while (cur) {
+ if (!cur->ae.used)
+ goto found;
+ cur->ae.used = 0;
-#define print_ipv4_addr(_addr,_port,_name1,_name2) { \
- if ((_addr)) \
- printk(" %s=%d.%d.%d.%d", (_name1), \
- NIPQUAD((_addr))); \
- if ((_port)) \
- printk(" %s=%d", (_name2), ntohs((_port))); \
+ prev = cur;
+ cur = cur->next;
+ }
+ hvalue = (hvalue + 1) & (AVC_CACHE_SLOTS - 1);
+ } while (hvalue != avc_cache.lru_hint);
}
+ panic("avc_reclaim_node");
+
+found:
+ avc_cache.lru_hint = hvalue;
+
+ if (prev == NULL)
+ avc_cache.slots[hvalue] = cur->next;
+ else
+ prev->next = cur->next;
+
+ return cur;
+}
-/*
- * Copied from fs/dcache.c:d_path and hacked up to
- * avoid need for vfsmnt, root, and rootmnt parameters.
- */
-char * avc_d_path(struct dentry *dentry,
- char *buffer, int buflen)
+static inline struct avc_node *avc_claim_node(u32 ssid,
+ u32 tsid, u16 tclass)
{
- char * end = buffer+buflen;
- char * retval;
- int namelen;
+ struct avc_node *new;
+ int hvalue;
- *--end = '\0';
- buflen--;
- if (!IS_ROOT(dentry) && list_empty(&dentry->d_hash)) {
- buflen -= 10;
- end -= 10;
- memcpy(end, " (deleted)", 10);
+ hvalue = avc_hash(ssid, tsid, tclass);
+ if (avc_node_freelist) {
+ new = avc_node_freelist;
+ avc_node_freelist = avc_node_freelist->next;
+ avc_cache.active_nodes++;
+ } else {
+ new = avc_reclaim_node();
+ if (!new)
+ goto out;
}
- /* Get '/' right */
- retval = end-1;
- *retval = '/';
+ new->ae.used = 1;
+ new->ae.ssid = ssid;
+ new->ae.tsid = tsid;
+ new->ae.tclass = tclass;
+ new->next = avc_cache.slots[hvalue];
+ avc_cache.slots[hvalue] = new;
+
+out:
+ return new;
+}
- for (;;) {
- struct dentry * parent;
+static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid,
+ u16 tclass, int *probes)
+{
+ struct avc_node *cur;
+ int hvalue;
+ int tprobes = 1;
- if (IS_ROOT(dentry)) {
- goto global_root;
- }
- parent = dentry->d_parent;
- namelen = dentry->d_name.len;
- if (!namelen)
- goto skip;
- buflen -= namelen + 1;
- if (buflen < 0)
- break;
- end -= namelen;
- memcpy(end, dentry->d_name.name, namelen);
- *--end = '/';
- retval = end;
-skip:
- dentry = parent;
- if (!dentry)
- break;
+ hvalue = avc_hash(ssid, tsid, tclass);
+ cur = avc_cache.slots[hvalue];
+ while (cur != NULL &&
+ (ssid != cur->ae.ssid ||
+ tclass != cur->ae.tclass ||
+ tsid != cur->ae.tsid)) {
+ tprobes++;
+ cur = cur->next;
}
- return retval;
-global_root:
- namelen = dentry->d_name.len;
- buflen -= namelen;
- if (buflen >= 0) {
- retval -= namelen-1; /* hit the slash */
- memcpy(retval, dentry->d_name.name, namelen);
+
+ if (cur == NULL) {
+ /* cache miss */
+ goto out;
}
- return retval;
+
+ /* cache hit */
+ if (probes)
+ *probes = tprobes;
+
+ cur->ae.used = 1;
+
+out:
+ return cur;
}
-/*
- * Copied from net/core/utils.c:net_ratelimit and modified for
- * use by the AVC audit facility.
+/**
+ * avc_lookup - Look up an AVC entry.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ * @aeref: AVC entry reference
+ *
+ * Look up an AVC entry that is valid for the
+ * @requested permissions between the SID pair
+ * (@ssid, @tsid), interpreting the permissions
+ * based on @tclass. If a valid AVC entry exists,
+ * then this function updates @aeref to refer to the
+ * entry and returns %0. Otherwise, this function
+ * returns -%ENOENT.
*/
+int avc_lookup(u32 ssid, u32 tsid, u16 tclass,
+ u32 requested, struct avc_entry_ref *aeref)
+{
+ struct avc_node *node;
+ int probes, rc = 0;
-int avc_msg_cost = 5*HZ;
-int avc_msg_burst = 10*5*HZ;
+ avc_cache_stats_incr(AVC_CAV_LOOKUPS);
+ node = avc_search_node(ssid, tsid, tclass,&probes);
+
+ if (node && ((node->ae.avd.decided & requested) == requested)) {
+ avc_cache_stats_incr(AVC_CAV_HITS);
+ avc_cache_stats_add(AVC_CAV_PROBES,probes);
+ aeref->ae = &node->ae;
+ goto out;
+ }
+
+ avc_cache_stats_incr(AVC_CAV_MISSES);
+ rc = -ENOENT;
+out:
+ return rc;
+}
-/*
- * This enforces a rate limit: not more than one kernel message
- * every 5secs to make a denial-of-service attack impossible.
- */
-int avc_ratelimit(void)
+/**
+ * avc_insert - Insert an AVC entry.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @ae: AVC entry
+ * @aeref: AVC entry reference
+ *
+ * Insert an AVC entry for the SID pair
+ * (@ssid, @tsid) and class @tclass.
+ * The access vectors and the sequence number are
+ * normally provided by the security server in
+ * response to a security_compute_av() call. If the
+ * sequence number @ae->avd.seqno is not less than the latest
+ * revocation notification, then the function copies
+ * the access vectors into a cache entry, updates
+ * @aeref to refer to the entry, and returns %0.
+ * Otherwise, this function returns -%EAGAIN.
+ */
+int avc_insert(u32 ssid, u32 tsid, u16 tclass,
+ struct avc_entry *ae, struct avc_entry_ref *aeref)
{
- static spinlock_t ratelimit_lock = SPIN_LOCK_UNLOCKED;
- static unsigned long toks = 10*5*HZ;
- static unsigned long last_msg;
- static int missed;
- unsigned long flags;
- unsigned long now = jiffies;
+ struct avc_node *node;
+ int rc = 0;
- spin_lock_irqsave(&ratelimit_lock, flags);
- toks += now - last_msg;
- last_msg = now;
- if (toks > avc_msg_burst)
- toks = avc_msg_burst;
- if (toks >= avc_msg_cost) {
- int lost = missed;
- missed = 0;
- toks -= avc_msg_cost;
- spin_unlock_irqrestore(&ratelimit_lock, flags);
- if (lost)
- printk(KERN_WARNING "AVC: %d messages suppressed.\n", lost);
- return 1;
+ if (ae->avd.seqno < avc_cache.latest_notif) {
+ printk(KERN_WARNING "avc: seqno %d < latest_notif %d\n",
+ ae->avd.seqno, avc_cache.latest_notif);
+ rc = -EAGAIN;
+ goto out;
}
- missed++;
- spin_unlock_irqrestore(&ratelimit_lock, flags);
- return 0;
-}
+ node = avc_claim_node(ssid, tsid, tclass);
+ if (!node) {
+ rc = -ENOMEM;
+ goto out;
+ }
-#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
+ node->ae.avd.allowed = ae->avd.allowed;
+ node->ae.avd.decided = ae->avd.decided;
+ node->ae.avd.auditallow = ae->avd.auditallow;
+ node->ae.avd.auditdeny = ae->avd.auditdeny;
+ node->ae.avd.seqno = ae->avd.seqno;
+ aeref->ae = &node->ae;
+out:
+ return rc;
+}
-static inline int check_avc_ratelimit(void)
+static inline void avc_print_ipv6_addr(struct audit_buffer *ab,
+ struct in6_addr *addr, u16 port,
+ char *name1, char *name2)
{
- if (avc_debug_always_allow)
- /* If permissive, then never suppress messages. */
- return 1;
- else
- return avc_ratelimit();
+ if (!ipv6_addr_any(addr))
+ audit_log_format(ab, " %s=%04x:%04x:%04x:%04x:%04x:"
+ "%04x:%04x:%04x", name1, NIP6(*addr));
+ if (port)
+ audit_log_format(ab, " %s=%d", name2, ntohs(port));
}
-#else
-
-static inline int check_avc_ratelimit(void)
+static inline void avc_print_ipv4_addr(struct audit_buffer *ab, u32 addr,
+ u16 port, char *name1, char *name2)
{
- return avc_ratelimit();
+ if (addr)
+ audit_log_format(ab, " %s=%d.%d.%d.%d", name1, NIPQUAD(addr));
+ if (port)
+ audit_log_format(ab, " %s=%d", name2, ntohs(port));
}
-#endif
-
-
-
-/*
- * Audit the granting or denial of permissions.
+/**
+ * avc_audit - Audit the granting or denial of permissions.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions
+ * @avd: access vector decisions
+ * @result: result from avc_has_perm_noaudit
+ * @a: auxiliary audit data
+ *
+ * Audit the granting or denial of permissions in accordance
+ * with the policy. This function is typically called by
+ * avc_has_perm() after a permission check, but can also be
+ * called directly by callers who use avc_has_perm_noaudit()
+ * in order to separate the permission check from the auditing.
+ * For example, this separation is useful when the permission check must
+ * be performed under a lock, to allow the lock to be released
+ * before calling the auditing code.
*/
-void avc_audit(
- security_id_t ssid, /* IN */
- security_id_t tsid, /* IN */
- security_class_t tclass, /* IN */
- access_vector_t audited, /* IN */
- struct avc_entry *ae, /* IN */
- __u32 denied, /* IN */
- avc_audit_data_t *a) /* IN */
+void avc_audit(u32 ssid, u32 tsid,
+ u16 tclass, u32 requested,
+ struct av_decision *avd, int result, struct avc_audit_data *a)
{
- char *p;
+ struct task_struct *tsk = current;
+ struct inode *inode = NULL;
+ u32 denied, audited;
+ struct audit_buffer *ab;
- if (!check_avc_ratelimit())
- return;
+ denied = requested & ~avd->allowed;
+ if (denied) {
+ audited = denied;
+ if (!(audited & avd->auditdeny))
+ return;
+ } else if (result) {
+ audited = denied = requested;
+ } else {
+ audited = requested;
+ if (!(audited & avd->auditallow))
+ return;
+ }
- printk("\navc: %s ", denied ? "denied" : "granted");
- avc_dump_av(tclass,audited);
- printk(" for ");
- if (current && current->pid) {
- printk(" pid=%d", current->pid);
- if (current->mm) {
- struct vm_area_struct *vma = current->mm->mmap;
-
- while (vma) {
- if ((vma->vm_flags & VM_EXECUTABLE) &&
- vma->vm_file) {
- p = d_path(vma->vm_file->f_dentry,
- vma->vm_file->f_vfsmnt,
- avc_audit_buffer,
- PAGE_SIZE);
- printk(" exe=%s", p);
- break;
+ ab = audit_log_start(current->audit_context);
+ if (!ab)
+ return; /* audit_panic has been called */
+ audit_log_format(ab, "avc: %s ", denied ? "denied" : "granted");
+ avc_dump_av(ab, tclass,audited);
+ audit_log_format(ab, " for ");
+ if (a && a->tsk)
+ tsk = a->tsk;
+ if (tsk && tsk->pid) {
+ struct mm_struct *mm;
+ struct vm_area_struct *vma;
+ audit_log_format(ab, " pid=%d", tsk->pid);
+ if (tsk == current)
+ mm = current->mm;
+ else
+ mm = get_task_mm(tsk);
+ if (mm) {
+ if (down_read_trylock(&mm->mmap_sem)) {
+ vma = mm->mmap;
+ while (vma) {
+ if ((vma->vm_flags & VM_EXECUTABLE) &&
+ vma->vm_file) {
+ audit_log_d_path(ab, "exe=",
+ vma->vm_file->f_dentry,
+ vma->vm_file->f_vfsmnt);
+ break;
+ }
+ vma = vma->vm_next;
}
- vma = vma->vm_next;
+ up_read(&mm->mmap_sem);
}
+ if (tsk != current)
+ mmput(mm);
+ } else {
+ audit_log_format(ab, " comm=%s", tsk->comm);
}
}
if (a) {
switch (a->type) {
case AVC_AUDIT_DATA_IPC:
- printk(" IPCID=%d", a->u.ipc_id);
+ audit_log_format(ab, " key=%d", a->u.ipc_id);
break;
case AVC_AUDIT_DATA_CAP:
- printk(" capability=%d", a->u.cap);
+ audit_log_format(ab, " capability=%d", a->u.cap);
break;
case AVC_AUDIT_DATA_FS:
if (a->u.fs.dentry) {
- struct inode *inode = a->u.fs.dentry->d_inode;
-
- p = avc_d_path(a->u.fs.dentry,
- avc_audit_buffer,
- PAGE_SIZE);
- if (p)
- printk(" path=%s", p);
-
- if (inode) {
- printk(" dev=%s ino=%ld",
- kdevname(inode->i_dev),
- inode->i_ino);
+ struct dentry *dentry = a->u.fs.dentry;
+ if (a->u.fs.mnt) {
+ audit_log_d_path(ab, "path=", dentry,
+ a->u.fs.mnt);
+ } else {
+ audit_log_format(ab, " name=%s",
+ dentry->d_name.name);
}
- }
-
- if (a->u.fs.inode) {
- struct inode *inode = a->u.fs.inode;
- struct dentry *dentry = d_find_alias(inode);
-
+ inode = dentry->d_inode;
+ } else if (a->u.fs.inode) {
+ struct dentry *dentry;
+ inode = a->u.fs.inode;
+ dentry = d_find_alias(inode);
if (dentry) {
- p = avc_d_path(dentry,
- avc_audit_buffer,
- PAGE_SIZE);
- if (p)
- printk(" path=%s", p);
+ audit_log_format(ab, " name=%s",
+ dentry->d_name.name);
dput(dentry);
}
-
- printk(" dev=%s ino=%ld",
- kdevname(inode->i_dev),inode->i_ino);
}
+ if (inode)
+ audit_log_format(ab, " dev=%s ino=%ld",
+ inode->i_sb->s_id,
+ inode->i_ino);
break;
case AVC_AUDIT_DATA_NET:
if (a->u.net.sk) {
struct sock *sk = a->u.net.sk;
+ struct unix_sock *u;
+ int len = 0;
+ char *p = NULL;
+
+ switch (sk->sk_family) {
+ case AF_INET: {
+ struct inet_opt *inet = inet_sk(sk);
+
+ avc_print_ipv4_addr(ab, inet->rcv_saddr,
+ inet->sport,
+ "laddr", "lport");
+ avc_print_ipv4_addr(ab, inet->daddr,
+ inet->dport,
+ "faddr", "fport");
+ break;
+ }
+ case AF_INET6: {
+ struct inet_opt *inet = inet_sk(sk);
+ struct ipv6_pinfo *inet6 = inet6_sk(sk);
- switch (sk->family) {
- case AF_INET:
- print_ipv4_addr(sk->rcv_saddr,
- sk->sport,
- "laddr", "lport");
- print_ipv4_addr(sk->daddr,
- sk->dport,
- "faddr", "fport");
+ avc_print_ipv6_addr(ab, &inet6->rcv_saddr,
+ inet->sport,
+ "laddr", "lport");
+ avc_print_ipv6_addr(ab, &inet6->daddr,
+ inet->dport,
+ "faddr", "fport");
break;
- case AF_UNIX:
- if (sk->protinfo.af_unix.dentry) {
- p = d_path(sk->protinfo.af_unix.dentry,
- sk->protinfo.af_unix.mnt,
- avc_audit_buffer,
- PAGE_SIZE);
- printk(" path=%s", p);
- } else if (sk->protinfo.af_unix.addr) {
- p = avc_audit_buffer;
- memcpy(p,
- sk->protinfo.af_unix.addr->name->sun_path,
- sk->protinfo.af_unix.addr->len-sizeof(short));
- if (*p == 0) {
- *p = '@';
- p += sk->protinfo.af_unix.addr->len-sizeof(short);
- *p = 0;
- }
- printk(" path=%s",
- avc_audit_buffer);
+ }
+ case AF_UNIX:
+ u = unix_sk(sk);
+ if (u->dentry) {
+ audit_log_d_path(ab, "path=",
+ u->dentry, u->mnt);
+ break;
}
+ if (!u->addr)
+ break;
+ len = u->addr->len-sizeof(short);
+ p = &u->addr->name->sun_path[0];
+ if (*p)
+ audit_log_format(ab,
+ "path=%*.*s", len,
+ len, p);
+ else
+ audit_log_format(ab,
+ "path=@%*.*s", len-1,
+ len-1, p+1);
break;
}
}
- if (a->u.net.daddr) {
- printk(" daddr=%d.%d.%d.%d",
- NIPQUAD(a->u.net.daddr));
- if (a->u.net.port)
- printk(" dest=%d", ntohs(a->u.net.port));
- } else if (a->u.net.port)
- printk(" port=%d", ntohs(a->u.net.port));
- if (a->u.net.skb) {
- struct sk_buff *skb = a->u.net.skb;
+
+ switch (a->u.net.family) {
+ case AF_INET:
+ avc_print_ipv4_addr(ab, a->u.net.v4info.saddr,
+ a->u.net.sport,
+ "saddr", "src");
+ avc_print_ipv4_addr(ab, a->u.net.v4info.daddr,
+ a->u.net.dport,
+ "daddr", "dest");
+ break;
+ case AF_INET6:
+ avc_print_ipv6_addr(ab, &a->u.net.v6info.saddr,
+ a->u.net.sport,
+ "saddr", "src");
+ avc_print_ipv6_addr(ab, &a->u.net.v6info.daddr,
+ a->u.net.dport,
+ "daddr", "dest");
+ break;
+ }
+ if (a->u.net.netif)
+ audit_log_format(ab, " netif=%s",
+ a->u.net.netif);
+ break;
+ }
+ }
+ audit_log_format(ab, " ");
+ avc_dump_query(ab, ssid, tsid, tclass);
+ audit_log_end(ab);
+}
+
+/**
+ * avc_add_callback - Register a callback for security events.
+ * @callback: callback function
+ * @events: security events
+ * @ssid: source security identifier or %SECSID_WILD
+ * @tsid: target security identifier or %SECSID_WILD
+ * @tclass: target security class
+ * @perms: permissions
+ *
+ * Register a callback function for events in the set @events
+ * related to the SID pair (@ssid, @tsid) and
+ * and the permissions @perms, interpreting
+ * @perms based on @tclass. Returns %0 on success or
+ * -%ENOMEM if insufficient memory exists to add the callback.
+ */
+int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
+ u16 tclass, u32 perms,
+ u32 *out_retained),
+ u32 events, u32 ssid, u32 tsid,
+ u16 tclass, u32 perms)
+{
+ struct avc_callback_node *c;
+ int rc = 0;
+
+ c = kmalloc(sizeof(*c), GFP_ATOMIC);
+ if (!c) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ c->callback = callback;
+ c->events = events;
+ c->ssid = ssid;
+ c->tsid = tsid;
+ c->perms = perms;
+ c->next = avc_callbacks;
+ avc_callbacks = c;
+out:
+ return rc;
+}
- if (skb->nh.iph) {
- __u16 source = 0, dest = 0;
- __u8 protocol = skb->nh.iph->protocol;
+static inline int avc_sidcmp(u32 x, u32 y)
+{
+ return (x == y || x == SECSID_WILD || y == SECSID_WILD);
+}
+static inline void avc_update_node(u32 event, struct avc_node *node, u32 perms)
+{
+ switch (event) {
+ case AVC_CALLBACK_GRANT:
+ node->ae.avd.allowed |= perms;
+ break;
+ case AVC_CALLBACK_TRY_REVOKE:
+ case AVC_CALLBACK_REVOKE:
+ node->ae.avd.allowed &= ~perms;
+ break;
+ case AVC_CALLBACK_AUDITALLOW_ENABLE:
+ node->ae.avd.auditallow |= perms;
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the trustedbsd-cvs
mailing list