Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 19 Apr 2006 22:04:02 GMT
From:      Todd Miller <millert@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 95632 for review
Message-ID:  <200604192204.k3JM42PS077248@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=95632

Change 95632 by millert@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@nai.com>
+ * Implementation of the kernel access vector cache (AVC).
+ *
+ * Authors:  Stephen Smalley, <sds@epoch.ncsc.mil>
+ *           James Morris <jmorris@redhat.com>
+ *
+ * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@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) <<<



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200604192204.k3JM42PS077248>