rpms/kernel/FC-5 0001-support-for-context-based-audit-filtering.patch, NONE, 1.1.2.1 0002-support-for-context-based-audit-filtering.patch, NONE, 1.1.2.1 0003-filesystem-location-based-auditing.patch, NONE, 1.1.2.1 kernel-2.6.spec, 1.2032.2.3, 1.2032.2.4 linux-2.6-audit-git.patch, 1.1.14.2, 1.1.14.3

fedora-cvs-commits at redhat.com fedora-cvs-commits at redhat.com
Tue Mar 21 15:17:42 UTC 2006


Author: sgrubb

Update of /cvs/dist/rpms/kernel/FC-5
In directory cvs.devel.redhat.com:/tmp/cvs-serv20289

Modified Files:
      Tag: private-lspp-11-branch
	kernel-2.6.spec linux-2.6-audit-git.patch 
Added Files:
      Tag: private-lspp-11-branch
	0001-support-for-context-based-audit-filtering.patch 
	0002-support-for-context-based-audit-filtering.patch 
	0003-filesystem-location-based-auditing.patch 
Log Message:
* Tue Mar 21 2006 Steve Grubb <sgrubb at redhat.com>
- lspp.13



0001-support-for-context-based-audit-filtering.patch:
 include/linux/audit.h          |    5 
 include/linux/selinux.h        |  112 +++++++++++++++++++
 security/selinux/Makefile      |    2 
 security/selinux/avc.c         |   13 +-
 security/selinux/exports.c     |   28 ++++
 security/selinux/ss/mls.c      |   30 +++++
 security/selinux/ss/mls.h      |    4 
 security/selinux/ss/services.c |  235 ++++++++++++++++++++++++++++++++++++++++-
 8 files changed, 419 insertions(+), 10 deletions(-)

--- NEW FILE 0001-support-for-context-based-audit-filtering.patch ---
>From nobody Mon Sep 17 00:00:00 2001
Subject: [PATCH] support for context based audit filtering
From: Darrel Goeddel <dgoeddel at trustedcs.com>
Date: 1140817445 -0600

Stephen Smalley wrote:
> On Thu, 2006-02-23 at 11:42 -0600, Darrel Goeddel wrote:
>
>>diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
>>index 640d0bf..df358be 100644
>>--- a/security/selinux/ss/mls.c
>>+++ b/security/selinux/ss/mls.c
>>@@ -385,6 +385,31 @@ out:
>> }
>>
>> /*
>>+ * Set the MLS fields in the security context structure
>>+ * `context' based on the string representation in
>>+ * the string `str'.  This function will allocate temporary memory with the
>>+ * given constraints of gfp_mask.
>>+ */
>>+int mls_from_string(char *str, struct context *context, gfp_t gfp_mask)
>>+{
>>+	char *tmpstr, *freestr;
>>+	int rc;
>
>
> Likely should be checking selinux_mls_enabled on entry and returning an
> error in that case (mls_context_to_sid will just return 0 in that case).
>
>
>>diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
>>index d877cd1..a2ad2cd 100644
>>--- a/security/selinux/ss/services.c
>>+++ b/security/selinux/ss/services.c
>
>
> Need to #include <linux/selinux.h> now to pick up the function
> prototypes for the selinux_audit_ functions to ensure that they are
> checked against the real functions.
>
>
>>+	default:
>>+		/* only the above fileds are valid */
>
>
> Nit:  Typo in comment.
>
> Otherwise, looks good.

Fixed up those two issues.  I also fixed a compilation problem when selinux
support is not compiled in, and a possible oops when selinux is compiled in
but not initialized (including being disabled at runtime).  The final
version is below.

--

The following patch provides selinux interfaces that will allow the audit
system to perform filtering based on the process context (user, role, type,
sensitivity, and clearance).  These interfaces will allow the selinux
module to perform efficient matches based on lower level selinux constructs,
rather than relying on context retrievals and string comparisons within
the audit module.  It also allows for dominance checks on the mls portion
of the contexts that are impossible with only string comparisons.

Signed-off-by: Darrel Goeddel <dgoeddel at trustedcs.com>
Signed-off-by: Al Viro <viro at zeniv.linux.org.uk>

---

 include/linux/audit.h          |    5 +
 include/linux/selinux.h        |  112 +++++++++++++++++++
 security/selinux/Makefile      |    2 
 security/selinux/avc.c         |   13 +-
 security/selinux/exports.c     |   28 +++++
 security/selinux/ss/mls.c      |   30 +++++
 security/selinux/ss/mls.h      |    4 +
 security/selinux/ss/services.c |  235 ++++++++++++++++++++++++++++++++++++++++
 8 files changed, 419 insertions(+), 10 deletions(-)
 create mode 100644 include/linux/selinux.h
 create mode 100644 security/selinux/exports.c

c938961808975be03ed5473f44301b2400af9a86
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 1c47c59..41b0813 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -145,6 +145,11 @@
 #define AUDIT_PERS	10
 #define AUDIT_ARCH	11
 #define AUDIT_MSGTYPE	12
+#define AUDIT_SE_USER	13	/* security label user */
+#define AUDIT_SE_ROLE	14	/* security label role */
+#define AUDIT_SE_TYPE	15	/* security label type */
+#define AUDIT_SE_SEN	16	/* security label sensitivity label */
+#define AUDIT_SE_CLR	17	/* security label clearance label */
 
 				/* These are ONLY useful when checking
 				 * at syscall exit time (AUDIT_AT_EXIT). */
diff --git a/include/linux/selinux.h b/include/linux/selinux.h
new file mode 100644
index 0000000..9d684b1
--- /dev/null
+++ b/include/linux/selinux.h
@@ -0,0 +1,112 @@
+/*
+ * SELinux services exported to the rest of the kernel.
+ *
+ * Author: James Morris <jmorris at redhat.com>
+ *
+ * Copyright (C) 2005 Red Hat, Inc., James Morris <jmorris at redhat.com>
+ * Copyright (C) 2006 Trusted Computer Solutions, Inc. <dgoeddel at trustedcs.com>
+ *
+ * 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.
+ */
+#ifndef _LINUX_SELINUX_H
+#define _LINUX_SELINUX_H
+
+struct selinux_audit_rule;
+struct audit_context;
+
+#ifdef CONFIG_SECURITY_SELINUX
+
+/**
+ *	selinux_audit_rule_init - alloc/init an selinux audit rule structure.
+ *	@field: the field this rule refers to
+ *	@op: the operater the rule uses
+ *	@rulestr: the text "target" of the rule
+ *	@rule: pointer to the new rule structure returned via this
+ *
+ *	Returns 0 if successful, -errno if not.  On success, the rule structure
+ *	will be allocated internally.  The caller must free this structure with
+ *	selinux_audit_rule_free() after use.
+ */
+int selinux_audit_rule_init(u32 field, u32 op, char *rulestr,
+                            struct selinux_audit_rule **rule);
+
+/**
+ *	selinux_audit_rule_free - free an selinux audit rule structure.
+ *	@rule: pointer to the audit rule to be freed
+ *
+ *	This will free all memory associated with the given rule.
+ *	If @rule is NULL, no operation is performed.
+ */
+void selinux_audit_rule_free(struct selinux_audit_rule *rule);
+
+/**
+ *	selinux_audit_rule_match - determine if a context ID matches a rule.
+ *	@ctxid: the context ID to check
+ *	@field: the field this rule refers to
+ *	@op: the operater the rule uses
+ *	@rule: pointer to the audit rule to check against
+ *	@actx: the audit context (can be NULL) associated with the check
+ *
+ *	Returns 1 if the context id matches the rule, 0 if it does not, and
+ *	-errno on failure.
+ */
+int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op,
+                             struct selinux_audit_rule *rule,
+                             struct audit_context *actx);
+
+/**
+ *	selinux_audit_set_callback - set the callback for policy reloads.
+ *	@callback: the function to call when the policy is reloaded
+ *
+ *	This sets the function callback function that will update the rules
+ *	upon policy reloads.  This callback should rebuild all existing rules
+ *	using selinux_audit_rule_init().
+ */
+void selinux_audit_set_callback(int (*callback)(void));
+
+/**
+ *	selinux_task_ctxid - determine a context ID for a process.
+ *	@tsk: the task object
+ *	@ctxid: ID value returned via this
+ *
+ *	On return, ctxid will contain an ID for the context.  This value
+ *	should only be used opaquely.
+ */
+void selinux_task_ctxid(struct task_struct *tsk, u32 *ctxid);
+
+#else
+
+static inline int selinux_audit_rule_init(u32 field, u32 op,
+                                          char *rulestr,
+                                          struct selinux_audit_rule **rule)
+{
+	return -ENOTSUPP;
+}
+
+static inline void selinux_audit_rule_free(struct selinux_audit_rule *rule)
+{
+	return;
+}
+
+static inline int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op,
+                                           struct selinux_audit_rule *rule,
+                                           struct audit_context *actx)
+{
+	return 0;
+}
+
+static inline void selinux_audit_set_callback(int (*callback)(void))
+{
+	return;
+}
+
+static inline void selinux_task_ctxid(struct task_struct *tsk, u32 *ctxid)
+{
+	*ctxid = 0;
+}
+
+#endif	/* CONFIG_SECURITY_SELINUX */
+
+#endif /* _LINUX_SELINUX_H */
diff --git a/security/selinux/Makefile b/security/selinux/Makefile
index 688c0a2..faf2e02 100644
--- a/security/selinux/Makefile
+++ b/security/selinux/Makefile
@@ -4,7 +4,7 @@
 
 obj-$(CONFIG_SECURITY_SELINUX) := selinux.o ss/
 
-selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o
+selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o exports.o
 
 selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
 
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index ac5d69b..a300702 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -800,7 +800,7 @@ out:
 int avc_ss_reset(u32 seqno)
 {
 	struct avc_callback_node *c;
-	int i, rc = 0;
+	int i, rc = 0, tmprc;
 	unsigned long flag;
 	struct avc_node *node;
 
@@ -813,15 +813,16 @@ int avc_ss_reset(u32 seqno)
 
 	for (c = avc_callbacks; c; c = c->next) {
 		if (c->events & AVC_CALLBACK_RESET) {
-			rc = c->callback(AVC_CALLBACK_RESET,
-					 0, 0, 0, 0, NULL);
-			if (rc)
-				goto out;
+			tmprc = c->callback(AVC_CALLBACK_RESET,
+			                    0, 0, 0, 0, NULL);
+			/* save the first error encountered for the return
+			   value and continue processing the callbacks */
+			if (!rc)
+				rc = tmprc;
 		}
 	}
 
 	avc_latest_notif_update(seqno, 0);
-out:
 	return rc;
 }
 
diff --git a/security/selinux/exports.c b/security/selinux/exports.c
new file mode 100644
index 0000000..333c4c7
--- /dev/null
+++ b/security/selinux/exports.c
@@ -0,0 +1,28 @@
+/*
+ * SELinux services exported to the rest of the kernel.
+ *
+ * Author: James Morris <jmorris at redhat.com>
+ *
+ * Copyright (C) 2005 Red Hat, Inc., James Morris <jmorris at redhat.com>
+ * Copyright (C) 2006 Trusted Computer Solutions, Inc. <dgoeddel at trustedcs.com>
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/selinux.h>
+
+#include "security.h"
+#include "objsec.h"
+
+void selinux_task_ctxid(struct task_struct *tsk, u32 *ctxid)
+{
+	struct task_security_struct *tsec = tsk->security;
+	if (selinux_enabled)
+		*ctxid = tsec->sid;
+	else
+		*ctxid = 0;
+}
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 640d0bf..fc34f87 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -8,7 +8,7 @@
  *
  *	Support for enhanced MLS infrastructure.
  *
- * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
  */
 
 #include <linux/kernel.h>
@@ -385,6 +385,34 @@ out:
 }
 
 /*
+ * Set the MLS fields in the security context structure
+ * `context' based on the string representation in
+ * the string `str'.  This function will allocate temporary memory with the
+ * given constraints of gfp_mask.
+ */
+int mls_from_string(char *str, struct context *context, gfp_t gfp_mask)
+{
+	char *tmpstr, *freestr;
+	int rc;
+
+	if (!selinux_mls_enabled)
+		return -EINVAL;
+
+	/* we need freestr because mls_context_to_sid will change
+	   the value of tmpstr */
+	tmpstr = freestr = kstrdup(str, gfp_mask);
+	if (!tmpstr) {
+		rc = -ENOMEM;
+	} else {
+		rc = mls_context_to_sid(':', &tmpstr, context,
+		                        NULL, SECSID_NULL);
+		kfree(freestr);
+	}
+
+	return rc;
+}
+
+/*
  * Copies the effective MLS range from `src' into `dst'.
  */
 static inline int mls_scopy_context(struct context *dst,
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h
index 03de697..fbb42f0 100644
--- a/security/selinux/ss/mls.h
+++ b/security/selinux/ss/mls.h
@@ -8,7 +8,7 @@
  *
  *	Support for enhanced MLS infrastructure.
  *
- * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
  */
 
 #ifndef _SS_MLS_H_
@@ -27,6 +27,8 @@ int mls_context_to_sid(char oldc,
 		       struct sidtab *s,
 		       u32 def_sid);
 
+int mls_from_string(char *str, struct context *context, gfp_t gfp_mask);
+
 int mls_convert_context(struct policydb *oldp,
 			struct policydb *newp,
 			struct context *context);
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index d877cd1..ce9378e 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -7,12 +7,13 @@
  * Updated: Trusted Computer Solutions, Inc. <dgoeddel at trustedcs.com>
  *
  *	Support for enhanced MLS infrastructure.
+ *	Support for context based audit filters.
  *
  * Updated: Frank Mayer <mayerf at tresys.com> and Karl MacMillan <kmacmillan at tresys.com>
  *
  * 	Added conditional policy language extensions
  *
- * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
  * Copyright (C) 2003 - 2004 Tresys Technology, LLC
  * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris at redhat.com>
  *	This program is free software; you can redistribute it and/or modify
@@ -1810,3 +1811,235 @@ out:
 	POLICY_RDUNLOCK;
 	return rc;
 }
+
+struct selinux_audit_rule {
+	u32 au_seqno;
+	struct context au_ctxt;
+};
+
+void selinux_audit_rule_free(struct selinux_audit_rule *rule)
+{
+	if (rule) {
+		context_destroy(&rule->au_ctxt);
+		kfree(rule);
+	}
+}
+
+int selinux_audit_rule_init(u32 field, u32 op, char *rulestr,
+                            struct selinux_audit_rule **rule)
+{
+	struct selinux_audit_rule *tmprule;
+	struct role_datum *roledatum;
+	struct type_datum *typedatum;
+	struct user_datum *userdatum;
+	int rc = 0;
+
+	*rule = NULL;
+
+	if (!ss_initialized)
+		return -ENOTSUPP;
+
+	switch (field) {
+	case AUDIT_SE_USER:
+	case AUDIT_SE_ROLE:
+	case AUDIT_SE_TYPE:
+		/* only 'equals' and 'not equals' fit user, role, and type */
+		if (op != AUDIT_EQUAL && op != AUDIT_NOT_EQUAL)
+			return -EINVAL;
+		break;
+	case AUDIT_SE_SEN:
+	case AUDIT_SE_CLR:
+		/* we do not allow a range, indicated by the presense of '-' */
+		if (strchr(rulestr, '-'))
+			return -EINVAL;
+		break;
+	default:
+		/* only the above fields are valid */
+		return -EINVAL;
+	}
+
+	tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL);
+	if (!tmprule)
+		return -ENOMEM;
+
+	context_init(&tmprule->au_ctxt);
+
+	POLICY_RDLOCK;
+
+	tmprule->au_seqno = latest_granting;
+
+	switch (field) {
+	case AUDIT_SE_USER:
+		userdatum = hashtab_search(policydb.p_users.table, rulestr);
+		if (!userdatum)
+			rc = -EINVAL;
+		else
+			tmprule->au_ctxt.user = userdatum->value;
+		break;
+	case AUDIT_SE_ROLE:
+		roledatum = hashtab_search(policydb.p_roles.table, rulestr);
+		if (!roledatum)
+			rc = -EINVAL;
+		else
+			tmprule->au_ctxt.role = roledatum->value;
+		break;
+	case AUDIT_SE_TYPE:
+		typedatum = hashtab_search(policydb.p_types.table, rulestr);
+		if (!typedatum)
+			rc = -EINVAL;
+		else
+			tmprule->au_ctxt.type = typedatum->value;
+		break;
+	case AUDIT_SE_SEN:
+	case AUDIT_SE_CLR:
+		rc = mls_from_string(rulestr, &tmprule->au_ctxt, GFP_ATOMIC);
+		break;
+	}
+
+	POLICY_RDUNLOCK;
+
+	if (rc) {
+		selinux_audit_rule_free(tmprule);
+		tmprule = NULL;
+	}
+
+	*rule = tmprule;
+
+	return rc;
+}
+
+int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op,
+                             struct selinux_audit_rule *rule,
+                             struct audit_context *actx)
+{
+	struct context *ctxt;
+	struct mls_level *level;
+	int match = 0;
+
+	if (!rule) {
+		audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,
+		          "selinux_audit_rule_match: missing rule\n");
+		return -ENOENT;
+	}
+
+	POLICY_RDLOCK;
+
+	if (rule->au_seqno < latest_granting) {
+		audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,
+		          "selinux_audit_rule_match: stale rule\n");
+		match = -ESTALE;
+		goto out;
+	}
+
+	ctxt = sidtab_search(&sidtab, ctxid);
+	if (!ctxt) {
+		audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,
+		          "selinux_audit_rule_match: unrecognized SID %d\n",
+		          ctxid);
+		match = -ENOENT;
+		goto out;
+	}
+
+	/* a field/op pair that is not caught here will simply fall through
+	   without a match */
+	switch (field) {
+	case AUDIT_SE_USER:
+		switch (op) {
+		case AUDIT_EQUAL:
+			match = (ctxt->user == rule->au_ctxt.user);
+			break;
+		case AUDIT_NOT_EQUAL:
+			match = (ctxt->user != rule->au_ctxt.user);
+			break;
+		}
+		break;
+	case AUDIT_SE_ROLE:
+		switch (op) {
+		case AUDIT_EQUAL:
+			match = (ctxt->role == rule->au_ctxt.role);
+			break;
+		case AUDIT_NOT_EQUAL:
+			match = (ctxt->role != rule->au_ctxt.role);
+			break;
+		}
+		break;
+	case AUDIT_SE_TYPE:
+		switch (op) {
+		case AUDIT_EQUAL:
+			match = (ctxt->type == rule->au_ctxt.type);
+			break;
+		case AUDIT_NOT_EQUAL:
+			match = (ctxt->type != rule->au_ctxt.type);
+			break;
+		}
+		break;
+	case AUDIT_SE_SEN:
+	case AUDIT_SE_CLR:
+		level = (op == AUDIT_SE_SEN ?
+		         &ctxt->range.level[0] : &ctxt->range.level[1]);
+		switch (op) {
+		case AUDIT_EQUAL:
+			match = mls_level_eq(&rule->au_ctxt.range.level[0],
+			                     level);
+			break;
+		case AUDIT_NOT_EQUAL:
+			match = !mls_level_eq(&rule->au_ctxt.range.level[0],
+			                      level);
+			break;
+		case AUDIT_LESS_THAN:
+			match = (mls_level_dom(&rule->au_ctxt.range.level[0],
+			                       level) &&
+			         !mls_level_eq(&rule->au_ctxt.range.level[0],
+			                       level));
+			break;
+		case AUDIT_LESS_THAN_OR_EQUAL:
+			match = mls_level_dom(&rule->au_ctxt.range.level[0],
+			                      level);
+			break;
+		case AUDIT_GREATER_THAN:
+			match = (mls_level_dom(level,
+			                      &rule->au_ctxt.range.level[0]) &&
+			         !mls_level_eq(level,
+			                       &rule->au_ctxt.range.level[0]));
+			break;
+		case AUDIT_GREATER_THAN_OR_EQUAL:
+			match = mls_level_dom(level,
+			                      &rule->au_ctxt.range.level[0]);
+			break;
+		}
+	}
+
+out:
+	POLICY_RDUNLOCK;
+	return match;
+}
+
+static int (*aurule_callback)(void) = NULL;
+
+static int aurule_avc_callback(u32 event, u32 ssid, u32 tsid,
+                               u16 class, u32 perms, u32 *retained)
+{
+	int err = 0;
+
+	if (event == AVC_CALLBACK_RESET && aurule_callback)
+		err = aurule_callback();
+	return err;
+}
+
+static int __init aurule_init(void)
+{
+	int err;
+
+	err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET,
+	                       SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0);
+	if (err)
+		panic("avc_add_callback() failed, error %d\n", err);
+
+	return err;
+}
+__initcall(aurule_init);
+
+void selinux_audit_set_callback(int (*callback)(void))
+{
+	aurule_callback = callback;
+}
-- 
0.99.9.GIT


0002-support-for-context-based-audit-filtering.patch:
 audit.c       |    8 +
 audit.h       |   10 +-
 auditfilter.c |  245 ++++++++++++++++++++++++++++++++++++++++++++++++++++------
 auditsc.c     |   20 ++++
 4 files changed, 256 insertions(+), 27 deletions(-)

--- NEW FILE 0002-support-for-context-based-audit-filtering.patch ---
>From nobody Mon Sep 17 00:00:00 2001
Subject: [PATCH] support for context based audit filtering
From: Darrel Goeddel <dgoeddel at trustedcs.com>
Date: 1142036046 -0600

Darrel Goeddel wrote:
<snip>
> I like 'em.  Here is a new patch that incorporates them.  It also moves the
> initialization call to selinux into the audit_init function as you had
> suggested earlier.  Look right?
>

The GFP_ATOMIC allocations are not necessary (noted on IRC). This version
switches to GFP_KERNEL and gets rid of the gfp_mask argument to
audit_init_entry().

--

Darrel

Signed-off-by: Al Viro <viro at zeniv.linux.org.uk>

---

 kernel/audit.c       |    8 ++
 kernel/audit.h       |   10 +-
 kernel/auditfilter.c |  245 +++++++++++++++++++++++++++++++++++++++++++++-----
 kernel/auditsc.c     |   20 ++++
 4 files changed, 256 insertions(+), 27 deletions(-)

1195ec220416c47699a08c8f4b7a464c380b6c00
diff --git a/kernel/audit.c b/kernel/audit.c
index 04fe2e3..65e1d03 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -55,6 +55,9 @@
 #include <net/netlink.h>
 #include <linux/skbuff.h>
 #include <linux/netlink.h>
+#include <linux/selinux.h>
+
+#include "audit.h"
 
 /* No auditing will take place until audit_initialized != 0.
  * (Initialization happens after skb_init is called.) */
@@ -564,6 +567,11 @@ static int __init audit_init(void)
 	skb_queue_head_init(&audit_skb_queue);
 	audit_initialized = 1;
 	audit_enabled = audit_default;
+
+	/* Register the callback with selinux.  This callback will be invoked
+	 * when a new policy is loaded. */
+	selinux_audit_set_callback(&selinux_audit_rule_update);
+
 	audit_log(NULL, GFP_KERNEL, AUDIT_KERNEL, "initialized");
 	return 0;
 }
diff --git a/kernel/audit.h b/kernel/audit.h
index bc53920..6f73392 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -54,9 +54,11 @@ enum audit_state {
 
 /* Rule lists */
 struct audit_field {
-	u32			type;
-	u32			val;
-	u32			op;
+	u32				type;
+	u32				val;
+	u32				op;
+	char				*se_str;
+	struct selinux_audit_rule	*se_rule;
 };
 
 struct audit_krule {
@@ -86,3 +88,5 @@ extern void		    audit_send_reply(int pi
 extern void		    audit_log_lost(const char *message);
 extern void		    audit_panic(const char *message);
 extern struct mutex audit_netlink_mutex;
+
+extern int selinux_audit_rule_update(void);
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index d3a8539..4d2023a 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -23,6 +23,7 @@
 #include <linux/audit.h>
 #include <linux/kthread.h>
 #include <linux/netlink.h>
+#include <linux/selinux.h>
 #include "audit.h"
 
 /* There are three lists of rules -- one to search at task creation
@@ -42,6 +43,13 @@ struct list_head audit_filter_list[AUDIT
 
 static inline void audit_free_rule(struct audit_entry *e)
 {
+	int i;
+	if (e->rule.fields)
+		for (i = 0; i < e->rule.field_count; i++) {
+			struct audit_field *f = &e->rule.fields[i];
+			kfree(f->se_str);
+			selinux_audit_rule_free(f->se_rule);
+		}
 	kfree(e->rule.fields);
 	kfree(e);
 }
@@ -52,9 +60,29 @@ static inline void audit_free_rule_rcu(s
 	audit_free_rule(e);
 }
 
+/* Initialize an audit filterlist entry. */
+static inline struct audit_entry *audit_init_entry(u32 field_count)
+{
+	struct audit_entry *entry;
+	struct audit_field *fields;
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (unlikely(!entry))
+		return NULL;
+
+	fields = kzalloc(sizeof(*fields) * field_count, GFP_KERNEL);
+	if (unlikely(!fields)) {
+		kfree(entry);
+		return NULL;
+	}
+	entry->rule.fields = fields;
+
+	return entry;
+}
+
 /* Unpack a filter field's string representation from user-space
  * buffer. */
-static __attribute__((unused)) char *audit_unpack_string(void **bufp, size_t *remain, size_t len)
+static char *audit_unpack_string(void **bufp, size_t *remain, size_t len)
 {
 	char *str;
 
@@ -84,7 +112,6 @@ static inline struct audit_entry *audit_
 {
 	unsigned listnr;
 	struct audit_entry *entry;
-	struct audit_field *fields;
 	int i, err;
 
 	err = -EINVAL;
@@ -108,23 +135,14 @@ static inline struct audit_entry *audit_
 		goto exit_err;
 
 	err = -ENOMEM;
-	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
-	if (unlikely(!entry))
-		goto exit_err;
-	fields = kmalloc(sizeof(*fields) * rule->field_count, GFP_KERNEL);
-	if (unlikely(!fields)) {
-		kfree(entry);
+	entry = audit_init_entry(rule->field_count);
+	if (!entry)
 		goto exit_err;
-	}
-
-	memset(&entry->rule, 0, sizeof(struct audit_krule));
-	memset(fields, 0, sizeof(struct audit_field));
 
 	entry->rule.flags = rule->flags & AUDIT_FILTER_PREPEND;
 	entry->rule.listnr = listnr;
 	entry->rule.action = rule->action;
 	entry->rule.field_count = rule->field_count;
-	entry->rule.fields = fields;
 
 	for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
 		entry->rule.mask[i] = rule->mask[i];
@@ -150,15 +168,20 @@ static struct audit_entry *audit_rule_to
 	for (i = 0; i < rule->field_count; i++) {
 		struct audit_field *f = &entry->rule.fields[i];
 
-		if (rule->fields[i] & AUDIT_UNUSED_BITS) {
-			err = -EINVAL;
-			goto exit_free;
-		}
-
 		f->op = rule->fields[i] & (AUDIT_NEGATE|AUDIT_OPERATORS);
 		f->type = rule->fields[i] & ~(AUDIT_NEGATE|AUDIT_OPERATORS);
 		f->val = rule->values[i];
 
+		if (f->type & AUDIT_UNUSED_BITS ||
+		    f->type == AUDIT_SE_USER ||
+		    f->type == AUDIT_SE_ROLE ||
+		    f->type == AUDIT_SE_TYPE ||
+		    f->type == AUDIT_SE_SEN ||
+		    f->type == AUDIT_SE_CLR) {
+			err = -EINVAL;
+			goto exit_free;
+		}
+
 		entry->rule.vers_ops = (f->op & AUDIT_OPERATORS) ? 2 : 1;
 
 		/* Support for legacy operators where
@@ -188,8 +211,9 @@ static struct audit_entry *audit_data_to
 	int err = 0;
 	struct audit_entry *entry;
 	void *bufp;
-	/* size_t remain = datasz - sizeof(struct audit_rule_data); */
+	size_t remain = datasz - sizeof(struct audit_rule_data);
 	int i;
+	char *str;
 
 	entry = audit_to_entry_common((struct audit_rule *)data);
 	if (IS_ERR(entry))
@@ -207,10 +231,35 @@ static struct audit_entry *audit_data_to
 
 		f->op = data->fieldflags[i] & AUDIT_OPERATORS;
 		f->type = data->fields[i];
+		f->val = data->values[i];
+		f->se_str = NULL;
+		f->se_rule = NULL;
 		switch(f->type) {
-		/* call type-specific conversion routines here */
-		default:
-			f->val = data->values[i];
+		case AUDIT_SE_USER:
+		case AUDIT_SE_ROLE:
+		case AUDIT_SE_TYPE:
+		case AUDIT_SE_SEN:
+		case AUDIT_SE_CLR:
+			str = audit_unpack_string(&bufp, &remain, f->val);
+			if (IS_ERR(str))
+				goto exit_free;
+			entry->rule.buflen += f->val;
+
+			err = selinux_audit_rule_init(f->type, f->op, str,
+						      &f->se_rule);
+			/* Keep currently invalid fields around in case they
+			 * become valid after a policy reload. */
+			if (err == -EINVAL) {
+				printk(KERN_WARNING "audit rule for selinux "
+				       "\'%s\' is invalid\n",  str);
+				err = 0;
+			}
+			if (err) {
+				kfree(str);
+				goto exit_free;
+			} else
+				f->se_str = str;
+			break;
 		}
 	}
 
@@ -286,7 +335,14 @@ static struct audit_rule_data *audit_kru
 		data->fields[i] = f->type;
 		data->fieldflags[i] = f->op;
 		switch(f->type) {
-		/* call type-specific conversion routines here */
+		case AUDIT_SE_USER:
+		case AUDIT_SE_ROLE:
+		case AUDIT_SE_TYPE:
+		case AUDIT_SE_SEN:
+		case AUDIT_SE_CLR:
+			data->buflen += data->values[i] =
+				audit_pack_string(&bufp, f->se_str);
+			break;
 		default:
 			data->values[i] = f->val;
 		}
@@ -314,7 +370,14 @@ static int audit_compare_rule(struct aud
 			return 1;
 
 		switch(a->fields[i].type) {
-		/* call type-specific comparison routines here */
+		case AUDIT_SE_USER:
+		case AUDIT_SE_ROLE:
+		case AUDIT_SE_TYPE:
+		case AUDIT_SE_SEN:
+		case AUDIT_SE_CLR:
+			if (strcmp(a->fields[i].se_str, b->fields[i].se_str))
+				return 1;
+			break;
 		default:
 			if (a->fields[i].val != b->fields[i].val)
 				return 1;
@@ -328,6 +391,81 @@ static int audit_compare_rule(struct aud
 	return 0;
 }
 
+/* Duplicate selinux field information.  The se_rule is opaque, so must be
+ * re-initialized. */
+static inline int audit_dupe_selinux_field(struct audit_field *df,
+					   struct audit_field *sf)
+{
+	int ret = 0;
+	char *se_str;
+
+	/* our own copy of se_str */
+	se_str = kstrdup(sf->se_str, GFP_KERNEL);
+	if (unlikely(IS_ERR(se_str)))
+	    return -ENOMEM;
+	df->se_str = se_str;
+
+	/* our own (refreshed) copy of se_rule */
+	ret = selinux_audit_rule_init(df->type, df->op, df->se_str,
+				      &df->se_rule);
+	/* Keep currently invalid fields around in case they
+	 * become valid after a policy reload. */
+	if (ret == -EINVAL) {
+		printk(KERN_WARNING "audit rule for selinux \'%s\' is "
+		       "invalid\n", df->se_str);
+		ret = 0;
+	}
+
+	return ret;
+}
+
+/* Duplicate an audit rule.  This will be a deep copy with the exception
+ * of the watch - that pointer is carried over.  The selinux specific fields
+ * will be updated in the copy.  The point is to be able to replace the old
+ * rule with the new rule in the filterlist, then free the old rule. */
+static struct audit_entry *audit_dupe_rule(struct audit_krule *old)
+{
+	u32 fcount = old->field_count;
+	struct audit_entry *entry;
+	struct audit_krule *new;
+	int i, err = 0;
+
+	entry = audit_init_entry(fcount);
+	if (unlikely(!entry))
+		return ERR_PTR(-ENOMEM);
+
+	new = &entry->rule;
+	new->vers_ops = old->vers_ops;
+	new->flags = old->flags;
+	new->listnr = old->listnr;
+	new->action = old->action;
+	for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
+		new->mask[i] = old->mask[i];
+	new->buflen = old->buflen;
+	new->field_count = old->field_count;
+	memcpy(new->fields, old->fields, sizeof(struct audit_field) * fcount);
+
+	/* deep copy this information, updating the se_rule fields, because
+	 * the originals will all be freed when the old rule is freed. */
+	for (i = 0; i < fcount; i++) {
+		switch (new->fields[i].type) {
+		case AUDIT_SE_USER:
+		case AUDIT_SE_ROLE:
+		case AUDIT_SE_TYPE:
+		case AUDIT_SE_SEN:
+		case AUDIT_SE_CLR:
+			err = audit_dupe_selinux_field(&new->fields[i],
+						       &old->fields[i]);
+		}
+		if (err) {
+			audit_free_rule(entry);
+			return ERR_PTR(err);
+		}
+	}
+
+	return entry;
+}
+
 /* Add rule to given filterlist if not a duplicate.  Protected by
  * audit_netlink_mutex. */
 static inline int audit_add_rule(struct audit_entry *entry,
@@ -628,3 +766,62 @@ unlock_and_return:
 	rcu_read_unlock();
 	return result;
 }
+
+/* Check to see if the rule contains any selinux fields.  Returns 1 if there
+   are selinux fields specified in the rule, 0 otherwise. */
+static inline int audit_rule_has_selinux(struct audit_krule *rule)
+{
+	int i;
+
+	for (i = 0; i < rule->field_count; i++) {
+		struct audit_field *f = &rule->fields[i];
+		switch (f->type) {
+		case AUDIT_SE_USER:
+		case AUDIT_SE_ROLE:
+		case AUDIT_SE_TYPE:
+		case AUDIT_SE_SEN:
+		case AUDIT_SE_CLR:
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+/* This function will re-initialize the se_rule field of all applicable rules.
+ * It will traverse the filter lists serarching for rules that contain selinux
+ * specific filter fields.  When such a rule is found, it is copied, the
+ * selinux field is re-initialized, and the old rule is replaced with the
+ * updated rule. */
+int selinux_audit_rule_update(void)
+{
+	struct audit_entry *entry, *nentry;
+	int i, err = 0;
+
+	/* audit_netlink_mutex synchronizes the writers */
+	mutex_lock(&audit_netlink_mutex);
+
+	for (i = 0; i < AUDIT_NR_FILTERS; i++) {
+		list_for_each_entry(entry, &audit_filter_list[i], list) {
+			if (!audit_rule_has_selinux(&entry->rule))
+				continue;
+
+			nentry = audit_dupe_rule(&entry->rule);
+			if (unlikely(IS_ERR(nentry))) {
+				/* save the first error encountered for the
+				 * return value */
+				if (!err)
+					err = PTR_ERR(nentry);
+				audit_panic("error updating selinux filters");
+				list_del_rcu(&entry->list);
+			} else {
+				list_replace_rcu(&entry->list, &nentry->list);
+			}
+			call_rcu(&entry->rcu, audit_free_rule_rcu);
+		}
+	}
+
+	mutex_unlock(&audit_netlink_mutex);
+
+	return err;
+}
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index b613ec8..ba9e9a3 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -58,6 +58,7 @@
 #include <linux/security.h>
 #include <linux/list.h>
 #include <linux/tty.h>
+#include <linux/selinux.h>
 
 #include "audit.h"
 
@@ -168,6 +169,9 @@ static int audit_filter_rules(struct tas
 			      enum audit_state *state)
 {
 	int i, j;
+	u32 sid;
+
+	selinux_task_ctxid(tsk, &sid);
 
 	for (i = 0; i < rule->field_count; i++) {
 		struct audit_field *f = &rule->fields[i];
@@ -257,6 +261,22 @@ static int audit_filter_rules(struct tas
 			if (ctx)
 				result = audit_comparator(ctx->loginuid, f->op, f->val);
 			break;
+		case AUDIT_SE_USER:
+		case AUDIT_SE_ROLE:
+		case AUDIT_SE_TYPE:
+		case AUDIT_SE_SEN:
+		case AUDIT_SE_CLR:
+			/* NOTE: this may return negative values indicating
+			   a temporary error.  We simply treat this as a
+			   match for now to avoid losing information that
+			   may be wanted.   An error message will also be
+			   logged upon error */
+			if (f->se_rule)
+				result = selinux_audit_rule_match(sid, f->type,
+				                                  f->op,
+				                                  f->se_rule,
+				                                  ctx);
+			break;
 		case AUDIT_ARG0:
 		case AUDIT_ARG1:
 		case AUDIT_ARG2:
-- 
0.99.9.GIT


0003-filesystem-location-based-auditing.patch:
 include/linux/audit.h |    1 
 init/Kconfig          |    2 
 kernel/audit.c        |   19 -
 kernel/audit.h        |   32 ++
 kernel/auditfilter.c  |  671 +++++++++++++++++++++++++++++++++++++++++++++++---
 kernel/auditsc.c      |   65 ++--
 6 files changed, 713 insertions(+), 77 deletions(-)

--- NEW FILE 0003-filesystem-location-based-auditing.patch ---
>From nobody Mon Sep 17 00:00:00 2001
Subject: [PATCH] filesystem location based auditing
From: Amy Griffis <amy.griffis at hp.com>
Date: 1142295485 -0500

Here is another iteration based off of audit-current.git plus the following
pre-requisites:

selinux support for context based audit filtering:
https://www.redhat.com/archives/linux-audit/2006-February/msg00160.html

context based audit filtering:
https://www.redhat.com/archives/linux-audit/2006-March/msg00107.html

inotify kernel api:
https://www.redhat.com/archives/linux-audit/2006-January/msg00084.html

This version fixes the following:

- remove extra parent put in audit_inotify_register()
- add missing unlock in audit_add_rule() error path
- replace per-filterlist spinlocks with use of audit_netlink_mutex (see below)
- remove now un-needed GFP_ATOMIC allocations
- remove now unused AUDIT_ENTRY_DEL flag - all code paths either avoid stale
  data by taking the mutex, or don't care
- take mutex to update parent data in audit_inotify_register()
- kernel enforces 1 watch per rule to avoid potential memleak
- add comments describing locking and refcounts
- miscellaneous code cleanup

The audit_netlink_mutex was previously taken/released in audit_receive() with
the following comment:

/* The netlink socket is only to be read by 1 CPU, which lets us assume
 * that list additions and deletions never happen simultaneously in
 * auditsc.c */

audit_receive() is three calls up the stack from where we need to release the
mutex for some operations in audit_add_rule() and audit_del_rule().  However,
from what I could see, it didn't seem to be protecting anything specific to the
netlink socket itself, but rather the operations on filterlists.  For that
reason I renamed it to audit_filter_mutex and modified the code to use it
explicitly around filterlist manipulations.

Please verify my analysis on this matter.  If incorrect we will need two
mutexes: audit_netlink_mutex and audit_filter_mutex.

Thanks,
Amy

Signed-off-by: Al Viro <viro at zeniv.linux.org.uk>

---

 include/linux/audit.h |    1 
 init/Kconfig          |    2 
 kernel/audit.c        |   19 +
 kernel/audit.h        |   32 ++
 kernel/auditfilter.c  |  671 ++++++++++++++++++++++++++++++++++++++++++++++---
 kernel/auditsc.c      |   65 +++--
 6 files changed, 713 insertions(+), 77 deletions(-)

aa75a8c629a3f13097cf9d128ad72cb3ece43670
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 41b0813..8350a55 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -158,6 +158,7 @@
 #define AUDIT_INODE	102
 #define AUDIT_EXIT	103
 #define AUDIT_SUCCESS   104	/* exit >= 0; value ignored */
+#define AUDIT_WATCH	105
 
 #define AUDIT_ARG0      200
 #define AUDIT_ARG1      (AUDIT_ARG0+1)
diff --git a/init/Kconfig b/init/Kconfig
index 38416a1..7fc7b20 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -177,7 +177,7 @@ config AUDIT
 
 config AUDITSYSCALL
 	bool "Enable system-call auditing support"
-	depends on AUDIT && (X86 || PPC || PPC64 || S390 || IA64 || UML || SPARC64)
+	depends on AUDIT && INOTIFY && (X86 || PPC || PPC64 || S390 || IA64 || UML || SPARC64)
 	default y if SECURITY_SELINUX
 	help
 	  Enable low-overhead system-call auditing infrastructure that
diff --git a/kernel/audit.c b/kernel/audit.c
index 65e1d03..6eff223 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -56,6 +56,7 @@
 #include <linux/skbuff.h>
 #include <linux/netlink.h>
 #include <linux/selinux.h>
+#include <linux/inotify.h>
 
 #include "audit.h"
 
@@ -102,6 +103,9 @@ static atomic_t    audit_lost = ATOMIC_I
 /* The netlink socket. */
 static struct sock *audit_sock;
 
+/* Inotify device. */
+struct inotify_device *audit_idev;
+
 /* The audit_freelist is a list of pre-allocated audit buffers (if more
  * than AUDIT_MAXFREE are in use, the audit buffer is freed instead of
  * being placed on the freelist). */
@@ -114,11 +118,6 @@ static struct task_struct *kauditd_task;
 static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait);
 static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait);
 
-/* The netlink socket is only to be read by 1 CPU, which lets us assume
- * that list additions and deletions never happen simultaneously in
- * auditsc.c */
-DEFINE_MUTEX(audit_netlink_mutex);
-
 /* AUDIT_BUFSIZ is the size of the temporary buffer used for formatting
  * audit records.  Since printk uses a 1024 byte buffer, this buffer
  * should be at least that large. */
@@ -541,14 +540,11 @@ static void audit_receive(struct sock *s
 	struct sk_buff  *skb;
 	unsigned int qlen;
 
-	mutex_lock(&audit_netlink_mutex);
-
 	for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) {
 		skb = skb_dequeue(&sk->sk_receive_queue);
 		audit_receive_skb(skb);
 		kfree_skb(skb);
 	}
-	mutex_unlock(&audit_netlink_mutex);
 }
 
 
@@ -573,6 +569,13 @@ static int __init audit_init(void)
 	selinux_audit_set_callback(&selinux_audit_rule_update);
 
 	audit_log(NULL, GFP_KERNEL, AUDIT_KERNEL, "initialized");
+
+#ifdef CONFIG_AUDITSYSCALL
+	audit_idev = inotify_init(audit_handle_ievent);
+	if (IS_ERR(audit_idev))
+		audit_panic("cannot initialize inotify device");
+#endif
+
 	return 0;
 }
 __initcall(audit_init);
diff --git a/kernel/audit.h b/kernel/audit.h
index 6f73392..423e826 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -19,10 +19,11 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <linux/mutex.h>
 #include <linux/fs.h>
 #include <linux/audit.h>
 
+struct inotify_event;
+
 /* 0 = no checking
    1 = put_count checking
    2 = verbose put_count checking
@@ -53,6 +54,27 @@ enum audit_state {
 };
 
 /* Rule lists */
+struct audit_parent {
+	atomic_t		count;	 /* reference count */
+	unsigned int		flags;	 /* flag in-process removals */
+	u32			wd;	 /* inotify watch descriptor */
+	dev_t			dev;	 /* associated superblock device */
+	unsigned long		ino;	 /* associated inode number */
+	struct list_head	mlist;	 /* entry in master_parents */
+	struct list_head	ilist;	 /* entry in inotify registration list*/
+	struct list_head	watches; /* associated watches */
+};
+
+struct audit_watch {
+	atomic_t		count;	 /* reference count */
+	char			*path;	 /* watch insertion path */
+	dev_t			dev;	 /* associated superblock device */
+	unsigned long		ino;	 /* associated inode number */
+	struct audit_parent	*parent; /* associated parent */
+	struct list_head	wlist;	 /* entry in audit_parent.watches list*/
+	struct list_head	rules;	 /* associated rules */
+};
+
 struct audit_field {
 	u32				type;
 	u32				val;
@@ -70,6 +92,8 @@ struct audit_krule {
 	u32			buflen; /* for data alloc on list rules */
 	u32			field_count;
 	struct audit_field	*fields;
+	struct audit_watch	*watch;	 /* associated watch */
+	struct list_head	rlist;	 /* entry in audit_watch.rules list */
 };
 
 struct audit_entry {
@@ -81,12 +105,14 @@ struct audit_entry {
 
 extern int audit_pid;
 extern int audit_comparator(const u32 left, const u32 op, const u32 right);
-
+extern int audit_compare_dname_path(const char *dname, const char *path);
 extern void		    audit_send_reply(int pid, int seq, int type,
 					     int done, int multi,
 					     void *payload, int size);
 extern void		    audit_log_lost(const char *message);
 extern void		    audit_panic(const char *message);
-extern struct mutex audit_netlink_mutex;
 
 extern int selinux_audit_rule_update(void);
+extern void audit_handle_ievent(struct inotify_event *event,
+				const char *dname, struct inode * inode,
+				void *ptr);
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 4d2023a..3966a49 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -22,13 +22,45 @@
 #include <linux/kernel.h>
 #include <linux/audit.h>
 #include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
 #include <linux/netlink.h>
+#include <linux/inotify.h>
 #include <linux/selinux.h>
 #include "audit.h"
 
-/* There are three lists of rules -- one to search at task creation
- * time, one to search at syscall entry time, and another to search at
- * syscall exit time. */
+/*
+ * Locking model:
+ *
+ * audit_filter_mutex:
+ * 		Synchronizes writes and blocking reads of audit's filterlist
+ * 		data.  Rcu is used to traverse the filterlist and access
+ * 		contents of structs audit_entry, audit_watch and opaque
+ * 		selinux rules during filtering.  If modified, these structures
+ * 		must be copied and replace their counterparts in the filterlist.
+ * 		An audit_parent struct is not accessed during filtering, so may
+ * 		be written directly provided audit_filter_mutex is held.
+ *
+ * 	master_parents_lock: (spinlock)
+ * 		Protects master_parents list.
+ */
+
+/*
+ * Reference counting:
+ *
+ * audit_parent: lifetime is from audit_init_parent() to audit_remove_parent().
+ * 	Each audit_watch holds a reference to its associated parent.
+ *
+ * audit_watch: if added to lists, lifetime is from audit_init_watch() to one
+ * 	of: audit_remove_watch() [user removes], audit_update_watch() [kernel
+ * 	replaces], or audit_remove_parent_watches() [kernel removes].
+ * 	Additionally, an audit_watch may exist temporarily to assist in
+ * 	searching existing filter data.  Each audit_krule holds a reference to
+ * 	its associated watch.
+ */
+
+/* Audit filter lists, defined in <linux/audit.h> */
 struct list_head audit_filter_list[AUDIT_NR_FILTERS] = {
 	LIST_HEAD_INIT(audit_filter_list[0]),
 	LIST_HEAD_INIT(audit_filter_list[1]),
@@ -41,9 +73,55 @@ struct list_head audit_filter_list[AUDIT
 #endif
 };
 
+DEFINE_MUTEX(audit_filter_mutex);
+
+static LIST_HEAD(master_parents);
+static DEFINE_SPINLOCK(master_parents_lock);
+
+/* Inotify device. */
+extern struct inotify_device *audit_idev;
+
+/* Inotify events we care about. */
+#define AUDIT_IN_WATCH IN_MOVE|IN_CREATE|IN_DELETE|IN_DELETE_SELF|IN_MOVE_SELF
+#define AUDIT_IN_SELF  IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT
+
+static inline void audit_get_parent(struct audit_parent *parent)
+{
+	atomic_inc(&parent->count);
+}
+
+static inline void audit_put_parent(struct audit_parent *parent)
+{
+	if (atomic_dec_and_test(&parent->count)) {
+		WARN_ON(!list_empty(&parent->watches));
+		kfree(parent);
+	}
+}
+
+static inline void audit_get_watch(struct audit_watch *watch)
+{
+	atomic_inc(&watch->count);
+}
+
+static inline void audit_put_watch(struct audit_watch *watch)
+{
+	if (atomic_dec_and_test(&watch->count)) {
+		WARN_ON(!list_empty(&watch->rules));
+		/* watches that were never added don't have a parent */
+		if (watch->parent)
+			audit_put_parent(watch->parent);
+		kfree(watch->path);
+		kfree(watch);
+	}
+}
+
 static inline void audit_free_rule(struct audit_entry *e)
 {
 	int i;
+
+	/* some rules don't have associated watches */
+	if (e->rule.watch)
+		audit_put_watch(e->rule.watch);
 	if (e->rule.fields)
 		for (i = 0; i < e->rule.field_count; i++) {
 			struct audit_field *f = &e->rule.fields[i];
@@ -60,6 +138,43 @@ static inline void audit_free_rule_rcu(s
 	audit_free_rule(e);
 }
 
+/* Initialize a parent watch entry. */
+static inline struct audit_parent *audit_init_parent(void)
+{
+	struct audit_parent *parent;
+
+	parent = kzalloc(sizeof(*parent), GFP_KERNEL);
+	if (unlikely(!parent))
+		return ERR_PTR(-ENOMEM);
+
+	INIT_LIST_HEAD(&parent->watches);
+	atomic_set(&parent->count, 1);
+
+	spin_lock(&master_parents_lock);
+	list_add(&parent->mlist, &master_parents);
+	spin_unlock(&master_parents_lock);
+
+	return parent;
+}
+
+/* Initialize a watch entry. */
+static inline struct audit_watch *audit_init_watch(char *path)
+{
+	struct audit_watch *watch;
+
+	watch = kzalloc(sizeof(*watch), GFP_KERNEL);
+	if (unlikely(!watch))
+		return ERR_PTR(-ENOMEM);
+
+	INIT_LIST_HEAD(&watch->rules);
+	atomic_set(&watch->count, 1);
+	watch->path = path;
+	watch->dev = (dev_t)-1;
+	watch->ino = (unsigned long)-1;
+
+	return watch;
+}
+
 /* Initialize an audit filterlist entry. */
 static inline struct audit_entry *audit_init_entry(u32 field_count)
 {
@@ -107,6 +222,28 @@ static char *audit_unpack_string(void **
 	return str;
 }
 
+/* Translate a watch string to kernel respresentation. */
+static int audit_to_watch(struct audit_krule *krule, char *path, int len,
+			  u32 op)
+{
+	struct audit_watch *watch;
+
+	if (path[0] != '/' || path[len-1] == '/' ||
+	    krule->listnr != AUDIT_FILTER_EXIT ||
+	    op & ~AUDIT_EQUAL ||
+	    krule->watch) /* allow only 1 watch per rule */
+		return -EINVAL;
+
+	watch = audit_init_watch(path);
+	if (unlikely(IS_ERR(watch)))
+		return PTR_ERR(watch);
+
+	audit_get_watch(watch);
+	krule->watch = watch;
+
+	return 0;
+}
+
 /* Common user-space to kernel rule translation. */
 static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule)
 {
@@ -177,7 +314,8 @@ static struct audit_entry *audit_rule_to
 		    f->type == AUDIT_SE_ROLE ||
 		    f->type == AUDIT_SE_TYPE ||
 		    f->type == AUDIT_SE_SEN ||
-		    f->type == AUDIT_SE_CLR) {
+		    f->type == AUDIT_SE_CLR ||
+		    f->type == AUDIT_WATCH) {
 			err = -EINVAL;
 			goto exit_free;
 		}
@@ -260,6 +398,18 @@ static struct audit_entry *audit_data_to
 			} else
 				f->se_str = str;
 			break;
+		case AUDIT_WATCH:
+			str = audit_unpack_string(&bufp, &remain, f->val);
+			if (IS_ERR(str))
+				goto exit_free;
+			entry->rule.buflen += f->val;
+
+			err = audit_to_watch(&entry->rule, str, f->val, f->op);
+			if (err) {
+				kfree(str);
+				goto exit_free;
+			}
+			break;
 		}
 	}
 
@@ -343,6 +493,10 @@ static struct audit_rule_data *audit_kru
 			data->buflen += data->values[i] =
 				audit_pack_string(&bufp, f->se_str);
 			break;
+		case AUDIT_WATCH:
+			data->buflen += data->values[i] =
+				audit_pack_string(&bufp, krule->watch->path);
+			break;
 		default:
 			data->values[i] = f->val;
 		}
@@ -378,6 +532,10 @@ static int audit_compare_rule(struct aud
 			if (strcmp(a->fields[i].se_str, b->fields[i].se_str))
 				return 1;
 			break;
+		case AUDIT_WATCH:
+			if (strcmp(a->watch->path, b->watch->path))
+				return 1;
+			break;
 		default:
 			if (a->fields[i].val != b->fields[i].val)
 				return 1;
@@ -391,6 +549,31 @@ static int audit_compare_rule(struct aud
 	return 0;
 }
 
+/* Duplicate the given audit watch.  The new watch's rules list is initialized
+ * to an empty list and wlist is undefined. */
+static inline struct audit_watch *audit_dupe_watch(struct audit_watch *old)
+{
+	char *path;
+	struct audit_watch *new;
+
+	path = kstrdup(old->path, GFP_KERNEL);
+	if (unlikely(!path))
+		return ERR_PTR(-ENOMEM);
+
+	new = audit_init_watch(path);
+	if (unlikely(!new)) {
+		kfree(path);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	new->dev = old->dev;
+	new->ino = old->ino;
+	audit_get_parent(old->parent);
+	new->parent = old->parent;
+
+	return new;
+}
+
 /* Duplicate selinux field information.  The se_rule is opaque, so must be
  * re-initialized. */
 static inline int audit_dupe_selinux_field(struct audit_field *df,
@@ -422,8 +605,11 @@ static inline int audit_dupe_selinux_fie
 /* Duplicate an audit rule.  This will be a deep copy with the exception
  * of the watch - that pointer is carried over.  The selinux specific fields
  * will be updated in the copy.  The point is to be able to replace the old
- * rule with the new rule in the filterlist, then free the old rule. */
-static struct audit_entry *audit_dupe_rule(struct audit_krule *old)
+ * rule with the new rule in the filterlist, then free the old rule.
+ * The rlist element is undefined; list manipulations are handled apart from
+ * the initial copy. */
+static struct audit_entry *audit_dupe_rule(struct audit_krule *old,
+					   struct audit_watch *watch)
 {
 	u32 fcount = old->field_count;
 	struct audit_entry *entry;
@@ -442,6 +628,7 @@ static struct audit_entry *audit_dupe_ru
 	for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
 		new->mask[i] = old->mask[i];
 	new->buflen = old->buflen;
+	new->watch = NULL;
 	new->field_count = old->field_count;
 	memcpy(new->fields, old->fields, sizeof(struct audit_field) * fcount);
 
@@ -463,48 +650,393 @@ static struct audit_entry *audit_dupe_ru
 		}
 	}
 
+	if (watch) {
+		audit_get_watch(watch);
+		new->watch = watch;
+	}
+
 	return entry;
 }
 
-/* Add rule to given filterlist if not a duplicate.  Protected by
- * audit_netlink_mutex. */
-static inline int audit_add_rule(struct audit_entry *entry,
-				  struct list_head *list)
+/* Update inode numbers in audit rules based on filesystem event. */
+static inline void audit_update_watch(struct audit_parent *parent,
+				      const char *dname, dev_t dev,
+				      unsigned long ino)
+{
+	struct audit_watch *owatch, *nwatch, *nextw;
+	struct audit_krule *r, *nextr;
+	struct audit_entry *oentry, *nentry;
+	struct audit_buffer *ab;
+
+	mutex_lock(&audit_filter_mutex);
+	list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
+		if (audit_compare_dname_path(dname, owatch->path))
+			continue;
+
+		nwatch = audit_dupe_watch(owatch);
+		if (unlikely(IS_ERR(nwatch))) {
+			mutex_unlock(&audit_filter_mutex);
+			audit_panic("error updating watch, skipping");
+			return;
+		}
+		nwatch->dev = dev;
+		nwatch->ino = ino;
+
+		list_for_each_entry_safe(r, nextr, &owatch->rules, rlist) {
+			oentry = container_of(r, struct audit_entry, rule);
+
+			nentry = audit_dupe_rule(&oentry->rule, nwatch);
+			if (unlikely(IS_ERR(nentry))) {
+				audit_panic("error updating watch, removing");
+				list_del(&oentry->rule.rlist);
+				list_del_rcu(&oentry->list);
+			} else {
+				list_add(&nentry->rule.rlist, &nwatch->rules);
+				list_del(&oentry->rule.rlist);
+				list_replace_rcu(&oentry->list, &nentry->list);
+			}
+			call_rcu(&oentry->rcu, audit_free_rule_rcu);
+		}
+
+		ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
+		audit_log_format(ab, "audit updated rules specifying watch=");
+		audit_log_untrustedstring(ab, owatch->path);
+		audit_log_format(ab, " with dev=%u ino=%lu\n", dev, ino);
+		audit_log_end(ab);
+
+		list_del(&owatch->wlist);
+		audit_put_watch(owatch); /* matches initial get */
+		goto add_watch_to_parent; /* event applies to a single watch */
+	}
+	mutex_unlock(&audit_filter_mutex);
+	return;
+
+add_watch_to_parent:
+	list_add(&nwatch->wlist, &parent->watches);
+	mutex_unlock(&audit_filter_mutex);
+	return;
+}
+
+/* Remove all watches & rules associated with a parent that is going away. */
+static inline void audit_remove_parent_watches(struct audit_parent *parent)
 {
+	struct audit_watch *w, *nextw;
+	struct audit_krule *r, *nextr;
 	struct audit_entry *e;
 
-	/* Do not use the _rcu iterator here, since this is the only
-	 * addition routine. */
+	mutex_lock(&audit_filter_mutex);
+	list_for_each_entry_safe(w, nextw, &parent->watches, wlist) {
+		list_for_each_entry_safe(r, nextr, &w->rules, rlist) {
+			e = container_of(r, struct audit_entry, rule);
+			list_del(&r->rlist);
+			list_del_rcu(&e->list);
+			call_rcu(&e->rcu, audit_free_rule_rcu);
+
+			audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+				 "audit implicitly removed rule from list=%d\n",
+				  AUDIT_FILTER_EXIT);
+		}
+		list_del(&w->wlist);
+		audit_put_watch(w); /* matches initial get */
+	}
+	mutex_unlock(&audit_filter_mutex);
+}
+
+/* Actually remove the parent; inotify has acknowleged the removal. */
+static inline void audit_remove_parent(struct audit_parent *parent)
+{
+	WARN_ON(!list_empty(&parent->watches));
+	spin_lock(&master_parents_lock);
+	list_del(&parent->mlist);
+	audit_put_parent(parent);
+	spin_unlock(&master_parents_lock);
+}
+
+/* Register inotify watches for parents on in_list. */
+static int audit_inotify_register(struct nameidata *nd,
+				  struct list_head *in_list)
+{
+	struct audit_parent *p;
+	s32 wd;
+	int ret = 0;
+
+	list_for_each_entry(p, in_list, ilist) {
+		/* Grab a ref while calling inotify_add_watch(), so parent
+		 * can't be removed until we've updated its data. */
+		audit_get_parent(p);
+
+		if (!audit_idev)
+			wd = -EOPNOTSUPP;
+		else
+			wd = inotify_add_watch(audit_idev, nd->dentry->d_inode,
+					       AUDIT_IN_WATCH, p);
+		if (wd < 0) {
+			audit_remove_parent_watches(p);
+			audit_remove_parent(p);
+			/* save the first error for return value */
+			if (!ret)
+				ret = wd;
+		} else {
+			struct inode *inode = nd->dentry->d_inode;
+
+			mutex_lock(&audit_filter_mutex);
+			p->wd = wd;
+			p->dev = inode->i_sb->s_dev;
+			p->ino = inode->i_ino;
+			mutex_unlock(&audit_filter_mutex);
+		}
+
+		audit_put_parent(p);
+	}
+
+	return ret;
+}
+
+/* Unregister inotify watches for parents on in_list.
+ * Generates an IN_IGNORED event. */
+static void audit_inotify_unregister(struct list_head *in_list)
+{
+	struct audit_parent *p;
+
+	list_for_each_entry(p, in_list, ilist) {
+		if (audit_idev)
+			inotify_ignore(audit_idev, p->wd);
+		/* matches get in audit_remove_watch() */
+		audit_put_parent(p);
+	}
+}
+
+/* Get path information necessary for adding watches. */
+static int audit_get_nd(char *path, struct nameidata **ndp,
+			struct nameidata **ndw)
+{
+	struct nameidata *ndparent, *ndwatch;
+	int err;
+
+	ndparent = kmalloc(sizeof(*ndparent), GFP_KERNEL);
+	if (unlikely(!ndparent))
+		return -ENOMEM;
+
+	ndwatch = kmalloc(sizeof(*ndwatch), GFP_KERNEL);
+	if (unlikely(!ndwatch)) {
+		kfree(ndparent);
+		return -ENOMEM;
+	}
+
+	err = path_lookup(path, LOOKUP_PARENT, ndparent);
+	if (err) {
+		kfree(ndparent);
+		kfree(ndwatch);
+		return err;
+	}
+
+	err = path_lookup(path, 0, ndwatch);
+	if (err) {
+		kfree(ndwatch);
+		ndwatch = NULL;
+	}
+
+	*ndp = ndparent;
+	*ndw = ndwatch;
+
+	return 0;
+}
+
+/* Release resources used for watch path information. */
+static inline void audit_put_nd(struct nameidata *ndp, struct nameidata *ndw)
+{
+	if (ndp) {
+		path_release(ndp);
+		kfree(ndp);
+	}
+	if (ndw) {
+		path_release(ndw);
+		kfree(ndw);
+	}
+}
+
+/* Find an existing parent entry for this watch, or create a new one.
+ * Caller must hold audit_filter_mutex. */
+static inline struct audit_parent *audit_find_parent(struct nameidata *nd,
+						     struct list_head *in_list)
+{
+	struct audit_parent *p, *parent, *next;
+	struct inode *inode = nd->dentry->d_inode;
+
+	list_for_each_entry_safe(p, next, &master_parents, mlist) {
+		if (p->ino != inode->i_ino ||
+		    p->dev != inode->i_sb->s_dev)
+			continue;
+
+		parent = p;
+		goto out;
+	}
+
+	parent = audit_init_parent();
+	if (IS_ERR(parent))
+		goto out;
+	/* add new parent to inotify registration list */
+	list_add(&parent->ilist, in_list);
+
+out:
+	return parent;
+}
+
+/* Find a matching watch entry, or add this one.
+ * Caller must hold audit_filter_mutex. */
+static inline int audit_add_watch(struct audit_krule *krule,
+				  struct nameidata *ndp, struct nameidata *ndw,
+				  struct list_head *list)
+{
+	struct audit_parent *parent;
+	struct audit_watch *w, *watch = krule->watch;
+
+	parent = audit_find_parent(ndp, list);
+	if (IS_ERR(parent))
+		return PTR_ERR(parent);
+
+	list_for_each_entry(w, &parent->watches, wlist) {
+		if (strcmp(watch->path, w->path))
+			continue;
+
+		audit_put_watch(watch); /* tmp watch, krule's ref */
+		audit_put_watch(watch); /* tmp watch, matches initial get */
+
+		audit_get_watch(w);
+		krule->watch = watch = w;
+		goto add_rule;
+	}
+
+	audit_get_parent(parent);
+	watch->parent = parent;
+	list_add(&watch->wlist, &parent->watches);
+
+add_rule:
+	list_add(&krule->rlist, &watch->rules);
+
+	if (ndw) {
+		watch->dev = ndw->dentry->d_inode->i_sb->s_dev;
+		watch->ino = ndw->dentry->d_inode->i_ino;
+	}
+
+	return 0;
+}
+
+/* Add rule to given filterlist if not a duplicate. */
+static inline int audit_add_rule(struct audit_entry *entry,
+				 struct list_head *list)
+{
+	struct audit_entry *e;
+	struct audit_watch *watch = entry->rule.watch;
+	struct nameidata *ndp, *ndw;
+	LIST_HEAD(inotify_list);
+	int err;
+
+	/* Taking audit_filter_mutex protects from stale rule data and
+	 * writes to an audit_parent. */
+	mutex_lock(&audit_filter_mutex);
 	list_for_each_entry(e, list, list) {
-		if (!audit_compare_rule(&entry->rule, &e->rule))
-			return -EEXIST;
+		if (!audit_compare_rule(&entry->rule, &e->rule)) {
+			err = -EEXIST;
+			mutex_unlock(&audit_filter_mutex);
+			goto error;
+		}
+	}
+	mutex_unlock(&audit_filter_mutex);
+
+	/* Avoid calling path_lookup under audit_filter_mutex. */
+	if (watch) {
+		err = audit_get_nd(watch->path, &ndp, &ndw);
+		if (err)
+			goto error;
 	}
 
+	mutex_lock(&audit_filter_mutex);
+	if (watch) {
+		err = audit_add_watch(&entry->rule, ndp, ndw, &inotify_list);
+		if (err) {
+			mutex_unlock(&audit_filter_mutex);
+			audit_put_nd(ndp, ndw);
+			goto error;
+		}
+	}
 	if (entry->rule.flags & AUDIT_FILTER_PREPEND) {
 		list_add_rcu(&entry->list, list);
 	} else {
 		list_add_tail_rcu(&entry->list, list);
 	}
+	mutex_unlock(&audit_filter_mutex);
+
+	if (watch) {
+		err = audit_inotify_register(ndp, &inotify_list);
+		if (err)
+			goto error;
+		audit_put_nd(ndp, ndw);
+	}
 
 	return 0;
+
+error:
+	if (watch)
+		audit_put_watch(watch); /* tmp watch, matches initial get */
+	return err;
+}
+
+/* Remove given krule from its associated watch's rules list and clean up any
+ * last instances of associated watch and parent.
+ * Caller must hold audit_filter_mutex. */
+static inline void audit_remove_watch(struct audit_krule *krule,
+				      struct list_head *in_list)
+{
+	struct audit_watch *watch = krule->watch;
+	struct audit_parent *parent = watch->parent;
+
+	list_del(&krule->rlist);
+	if (list_empty(&watch->rules)) {
+		list_del(&watch->wlist);
+		audit_put_watch(watch); /* matches initial get */
+
+		if (list_empty(&parent->watches)) {
+			/* Put parent on the inotify un-registration list.
+			 * Grab a reference before releasing audit_filter_mutex,
+			 * to be released in audit_inotify_unregister(). */
+			list_add(&parent->ilist, in_list);
+			audit_get_parent(parent);
+		}
+	}
 }
 
-/* Remove an existing rule from filterlist.  Protected by
- * audit_netlink_mutex. */
+/* Remove an existing rule from filterlist. */
 static inline int audit_del_rule(struct audit_entry *entry,
 				 struct list_head *list)
 {
 	struct audit_entry  *e;
+	LIST_HEAD(inotify_list);
 
-	/* Do not use the _rcu iterator here, since this is the only
-	 * deletion routine. */
+	mutex_lock(&audit_filter_mutex);
 	list_for_each_entry(e, list, list) {
-		if (!audit_compare_rule(&entry->rule, &e->rule)) {
-			list_del_rcu(&e->list);
-			call_rcu(&e->rcu, audit_free_rule_rcu);
-			return 0;
+		if (audit_compare_rule(&entry->rule, &e->rule))
+			continue;
+
+		if (e->rule.watch) {
+			audit_remove_watch(&e->rule, &inotify_list);
+			/* match initial get for tmp watch */
+			audit_put_watch(entry->rule.watch);
 		}
-	}
+
+		list_del_rcu(&e->list);
+		call_rcu(&e->rcu, audit_free_rule_rcu);
+		mutex_unlock(&audit_filter_mutex);
+
+		if (e->rule.watch)
+			audit_inotify_unregister(&inotify_list);
+
+		return 0;
+	}
+	mutex_unlock(&audit_filter_mutex);
+	/* match initial get for tmp watch */
+	if (entry->rule.watch)
+		audit_put_watch(entry->rule.watch);
 	return -ENOENT;		/* No matching rule */
 }
 
@@ -521,10 +1053,10 @@ static int audit_list(void *_dest)
 	seq = dest[1];
 	kfree(dest);
 
-	mutex_lock(&audit_netlink_mutex);
+	mutex_lock(&audit_filter_mutex);
 
-	/* The *_rcu iterators not needed here because we are
-	   always called with audit_netlink_mutex held. */
+	/* This is a blocking read, so use audit_filter_mutex instead of rcu
+	 * iterator to sync with list writers. */
 	for (i=0; i<AUDIT_NR_FILTERS; i++) {
 		list_for_each_entry(entry, &audit_filter_list[i], list) {
 			struct audit_rule *rule;
@@ -539,7 +1071,7 @@ static int audit_list(void *_dest)
 	}
 	audit_send_reply(pid, seq, AUDIT_LIST, 1, 1, NULL, 0);
 	
-	mutex_unlock(&audit_netlink_mutex);
+	mutex_unlock(&audit_filter_mutex);
 	return 0;
 }
 
@@ -555,10 +1087,10 @@ static int audit_list_rules(void *_dest)
 	seq = dest[1];
 	kfree(dest);
 
-	mutex_lock(&audit_netlink_mutex);
+	mutex_lock(&audit_filter_mutex);
 
-	/* The *_rcu iterators not needed here because we are
-	   always called with audit_netlink_mutex held. */
+	/* This is a blocking read, so use audit_filter_mutex instead of rcu
+	 * iterator to sync with list writers. */
 	for (i=0; i<AUDIT_NR_FILTERS; i++) {
 		list_for_each_entry(e, &audit_filter_list[i], list) {
 			struct audit_rule_data *data;
@@ -567,13 +1099,13 @@ static int audit_list_rules(void *_dest)
 			if (unlikely(!data))
 				break;
 			audit_send_reply(pid, seq, AUDIT_LIST_RULES, 0, 1,
-					 data, sizeof(*data));
+					 data, sizeof(*data) + data->buflen);
 			kfree(data);
 		}
 	}
 	audit_send_reply(pid, seq, AUDIT_LIST_RULES, 1, 1, NULL, 0);
 
-	mutex_unlock(&audit_netlink_mutex);
+	mutex_unlock(&audit_filter_mutex);
 	return 0;
 }
 
@@ -662,6 +1194,32 @@ int audit_receive_filter(int type, int p
 	return err;
 }
 
+/**
+ * audit_handle_ievent - handler for Inotify events
+ * @event: information about the event
+ * @dname: dentry name associated with event
+ * @inode: inode associated with event
+ * @ptr: kernel's version of a watch descriptor
+ */
+void audit_handle_ievent(struct inotify_event *event, const char *dname,
+			  struct inode *inode, void *ptr)
+{
+	struct audit_parent *parent = (struct audit_parent *)ptr;
+
+	if (event->mask & (IN_CREATE|IN_MOVED_TO) && inode)
+		audit_update_watch(parent, dname, inode->i_sb->s_dev,
+				   inode->i_ino);
+	else if (event->mask & (IN_DELETE|IN_MOVED_FROM))
+		audit_update_watch(parent, dname, (dev_t)-1, (unsigned long)-1);
+	/* Note: Inotify doesn't remove the watch for the IN_MOVE_SELF event.
+	 * Work around this by leaving the parent around with an empty
+	 * watchlist.  It will be re-used if new watches are added. */
+	else if (event->mask & (AUDIT_IN_SELF))
+		audit_remove_parent_watches(parent);
+	else if (event->mask & IN_IGNORED)
+		audit_remove_parent(parent);
+}
+
 int audit_comparator(const u32 left, const u32 op, const u32 right)
 {
 	switch (op) {
@@ -682,7 +1240,39 @@ int audit_comparator(const u32 left, con
 	return 0;
 }
 
+/* Compare given dentry name with last component in given path,
+ * return of 0 indicates a match. */
+int audit_compare_dname_path(const char *dname, const char *path)
+{
+	int dlen, plen;
+	const char *p;
+
+	if (!dname || !path)
+		return 1;
+
+	dlen = strlen(dname);
+	plen = strlen(path);
+	if (plen < dlen)
+		return 1;
+
+	/* disregard trailing slashes */
+	p = path + plen - 1;
+	while ((*p == '/') && (p > path))
+		p--;
+
+	/* find last path component */
+	p = p - dlen + 1;
+	if (p < path)
+		return 1;
+	else if (p > path) {
+		if (*--p != '/')
+			return 1;
+		else
+			p++;
+	}
 
+	return strncmp(p, dname, dlen);
+}
 
 static int audit_filter_user_rules(struct netlink_skb_parms *cb,
 				   struct audit_krule *rule,
@@ -796,32 +1386,41 @@ static inline int audit_rule_has_selinux
 int selinux_audit_rule_update(void)
 {
 	struct audit_entry *entry, *nentry;
+	struct audit_watch *watch;
 	int i, err = 0;
 
-	/* audit_netlink_mutex synchronizes the writers */
-	mutex_lock(&audit_netlink_mutex);
+	/* audit_filter_mutex synchronizes the writers */
+	mutex_lock(&audit_filter_mutex);
 
 	for (i = 0; i < AUDIT_NR_FILTERS; i++) {
 		list_for_each_entry(entry, &audit_filter_list[i], list) {
 			if (!audit_rule_has_selinux(&entry->rule))
 				continue;
 
-			nentry = audit_dupe_rule(&entry->rule);
+			watch = entry->rule.watch;
+			nentry = audit_dupe_rule(&entry->rule, watch);
 			if (unlikely(IS_ERR(nentry))) {
 				/* save the first error encountered for the
 				 * return value */
 				if (!err)
 					err = PTR_ERR(nentry);
 				audit_panic("error updating selinux filters");
+				if (watch)
+					list_del(&entry->rule.rlist);
 				list_del_rcu(&entry->list);
 			} else {
+				if (watch) {
+					list_add(&nentry->rule.rlist,
+						 &watch->rules);
+					list_del(&entry->rule.rlist);
+				}
 				list_replace_rcu(&entry->list, &nentry->list);
 			}
 			call_rcu(&entry->rcu, audit_free_rule_rcu);
 		}
 	}
 
-	mutex_unlock(&audit_netlink_mutex);
+	mutex_unlock(&audit_filter_mutex);
 
 	return err;
 }
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index ba9e9a3..0f56c69 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -160,6 +160,27 @@ struct audit_context {
 #endif
 };
 
+/* Determine if any context name data matches a rule's watch data */
+static inline int audit_match_watch(struct audit_context *ctx,
+				    struct audit_watch *watch)
+{
+	int i;
+
+	if (!ctx)
+		return  0;
+
+	if (watch->ino == (unsigned long)-1)
+		return  0;
+
+	for (i = 0; i < ctx->name_count; i++) {
+		if (ctx->names[i].dev == watch->dev &&
+		    (ctx->names[i].ino == watch->ino ||
+		     ctx->names[i].pino == watch->ino))
+			return 1;
+	}
+
+	return 0;
+}
 
 /* Compare a task_struct with an audit_rule.  Return 1 on match, 0
  * otherwise. */
@@ -256,6 +277,9 @@ static int audit_filter_rules(struct tas
 				}
 			}
 			break;
+		case AUDIT_WATCH:
+			result = audit_match_watch(ctx, rule->watch);
+			break;
 		case AUDIT_LOGINUID:
 			result = 0;
 			if (ctx)
@@ -1067,37 +1091,20 @@ void __audit_inode_child(const char *dna
 		return;
 
 	/* determine matching parent */
-	if (dname)
-		for (idx = 0; idx < context->name_count; idx++)
-			if (context->names[idx].pino == pino) {
-				const char *n;
-				const char *name = context->names[idx].name;
-				int dlen = strlen(dname);
-				int nlen = name ? strlen(name) : 0;
-
-				if (nlen < dlen)
-					continue;
-				
-				/* disregard trailing slashes */
-				n = name + nlen - 1;
-				while ((*n == '/') && (n > name))
-					n--;
-
-				/* find last path component */
-				n = n - dlen + 1;
-				if (n < name)
-					continue;
-				else if (n > name) {
-					if (*--n != '/')
-						continue;
-					else
-						n++;
-				}
+	if (!dname)
+		goto no_match;
+	for (idx = 0; idx < context->name_count; idx++)
+		if (context->names[idx].pino == pino) {
+			const char *name = context->names[idx].name;
 
-				if (strncmp(n, dname, dlen) == 0)
-					goto update_context;
-			}
+			if (!name)
+				continue;
+
+			if (audit_compare_dname_path(dname, name) == 0)
+				goto update_context;
+		}
 
+no_match:
 	/* catch-all in case match not found */
 	idx = context->name_count++;
 	context->names[idx].name  = NULL;
-- 
0.99.9.GIT



Index: kernel-2.6.spec
===================================================================
RCS file: /cvs/dist/rpms/kernel/FC-5/kernel-2.6.spec,v
retrieving revision 1.2032.2.3
retrieving revision 1.2032.2.4
diff -u -r1.2032.2.3 -r1.2032.2.4
--- kernel-2.6.spec	10 Mar 2006 20:19:37 -0000	1.2032.2.3
+++ kernel-2.6.spec	21 Mar 2006 15:17:39 -0000	1.2032.2.4
@@ -24,7 +24,7 @@
 %define sublevel 15
 %define kversion 2.6.%{sublevel}
 %define rpmversion 2.6.%{sublevel}
-%define rhbsys  .lspp.12
+%define rhbsys  .lspp.13
 %define release %(R="$Revision$"; RR="${R##: }"; echo ${RR%%?})_FC5%{rhbsys}
 %define signmodules 0
 %define make_target bzImage
@@ -425,6 +425,9 @@
 # Audit & lspp patches
 Patch20100: linux-2.6-audit-git.patch
 Patch20101: linux-2.6-audit-slab-leak-tracking.patch
+Patch20102: 0001-support-for-context-based-audit-filtering.patch
+Patch20103: 0002-support-for-context-based-audit-filtering.patch
+Patch20104: 0003-filesystem-location-based-auditing.patch
 
 # END OF PATCH DEFINITIONS
 
@@ -1070,6 +1073,9 @@
 # Audit patches
 %patch20100 -p1
 %patch20101 -p1
+%patch20102 -p1
+%patch20103 -p1
+%patch20104 -p1
 
 # END OF PATCH APPLICATIONS
 
@@ -1662,6 +1668,9 @@
 %endif
 
 %changelog
+* Tue Mar 21 2006 Steve Grubb <sgrubb at redhat.com>
+- lspp.13
+
 * Fri Mar 10 2006 Steve Grubb <sgrubb at redhat.com>
 - lspp.12
 

linux-2.6-audit-git.patch:
 arch/i386/kernel/vm86.c        |   12 
 arch/ia64/kernel/ptrace.c      |   10 
 fs/namei.c                     |   11 
 fs/open.c                      |    8 
 fs/xattr.c                     |   11 
 include/linux/audit.h          |  130 +++++-
 include/linux/fsnotify.h       |   14 
 include/linux/security.h       |   33 +
 ipc/msg.c                      |    5 
 ipc/sem.c                      |    5 
 ipc/shm.c                      |    4 
 kernel/Makefile                |    2 
 kernel/audit.c                 |  175 ++++++--
 kernel/audit.h                 |   88 ++++
 kernel/auditfilter.c           |  630 +++++++++++++++++++++++++++++++
 kernel/auditsc.c               |  832 +++++++++++++++++++++--------------------
 net/core/dev.c                 |    7 
 security/dummy.c               |   14 
 security/selinux/hooks.c       |   98 ++--
 security/selinux/nlmsgtab.c    |    9 
 security/selinux/selinuxfs.c   |   11 
 security/selinux/ss/services.c |   15 
 22 files changed, 1579 insertions(+), 545 deletions(-)

Index: linux-2.6-audit-git.patch
===================================================================
RCS file: /cvs/dist/rpms/kernel/FC-5/Attic/linux-2.6-audit-git.patch,v
retrieving revision 1.1.14.2
retrieving revision 1.1.14.3
diff -u -r1.1.14.2 -r1.1.14.3
--- linux-2.6-audit-git.patch	10 Mar 2006 20:19:38 -0000	1.1.14.2
+++ linux-2.6-audit-git.patch	21 Mar 2006 15:17:39 -0000	1.1.14.3
@@ -1,40 +1,3 @@
-diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
-index 5c1fb6a..4caeee9 100644
---- a/arch/i386/kernel/ptrace.c
-+++ b/arch/i386/kernel/ptrace.c
-@@ -670,9 +670,11 @@ int do_syscall_trace(struct pt_regs *reg
- 		secure_computing(regs->orig_eax);
- 
- 	if (unlikely(current->audit_context)) {
--		if (entryexit)
--			audit_syscall_exit(current, AUDITSC_RESULT(regs->eax),
--						regs->eax);
-+		if (entryexit) {
-+			if (audit_invoke_exit())
-+				audit_syscall_exit(current, AUDITSC_RESULT(regs->eax),
-+							regs->eax);
-+		}
- 		/* Debug traps, when using PTRACE_SINGLESTEP, must be sent only
- 		 * on the syscall exit path. Normally, when TIF_SYSCALL_AUDIT is
- 		 * not used, entry.S will call us only on syscall exit, not
-@@ -719,14 +721,14 @@ int do_syscall_trace(struct pt_regs *reg
- 	}
- 	ret = is_sysemu;
- out:
--	if (unlikely(current->audit_context) && !entryexit)
-+	if (audit_invoke_entry() && !entryexit)
- 		audit_syscall_entry(current, AUDIT_ARCH_I386, regs->orig_eax,
--				    regs->ebx, regs->ecx, regs->edx, regs->esi);
-+					regs->ebx, regs->ecx, regs->edx, regs->esi);
- 	if (ret == 0)
- 		return 0;
- 
- 	regs->orig_eax = -1; /* force skip of syscall restarting */
--	if (unlikely(current->audit_context))
-+	if (audit_invoke_exit())
- 		audit_syscall_exit(current, AUDITSC_RESULT(regs->eax),
- 				regs->eax);
- 	return 1;
 diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c
 index f51c894..aee14fa 100644
 --- a/arch/i386/kernel/vm86.c
@@ -78,25 +41,16 @@
  }
  
 diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
-index eaed14a..bc3fdc0 100644
+index eaed14a..9887c87 100644
 --- a/arch/ia64/kernel/ptrace.c
 +++ b/arch/ia64/kernel/ptrace.c
-@@ -1632,7 +1632,7 @@ syscall_trace_enter (long arg0, long arg
- 	    && (current->ptrace & PT_PTRACED))
- 		syscall_trace();
- 
--	if (unlikely(current->audit_context)) {
-+	if (audit_invoke_entry()) {
- 		long syscall;
- 		int arch;
- 
 @@ -1656,8 +1656,14 @@ syscall_trace_leave (long arg0, long arg
  		     long arg4, long arg5, long arg6, long arg7,
  		     struct pt_regs regs)
  {
 -	if (unlikely(current->audit_context))
 -		audit_syscall_exit(current, AUDITSC_RESULT(regs.r10), regs.r8);
-+	if (audit_invoke_exit()) {
++	if (unlikely(current->audit_context)) {
 +		int success = AUDITSC_RESULT(regs.r10);
 +		long result = regs.r8;
 +
@@ -107,188 +61,8 @@
  
  	if (test_thread_flag(TIF_SYSCALL_TRACE)
  	    && (current->ptrace & PT_PTRACED))
-diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
-index f838b36..f3da86d 100644
---- a/arch/mips/kernel/ptrace.c
-+++ b/arch/mips/kernel/ptrace.c
-@@ -468,7 +468,7 @@ static inline int audit_arch(void)
-  */
- asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
- {
--	if (unlikely(current->audit_context) && entryexit)
-+	if (audit_invoke_exit() && entryexit)
- 		audit_syscall_exit(current, AUDITSC_RESULT(regs->regs[2]),
- 		                   regs->regs[2]);
- 
-@@ -492,7 +492,7 @@ asmlinkage void do_syscall_trace(struct 
- 		current->exit_code = 0;
- 	}
-  out:
--	if (unlikely(current->audit_context) && !entryexit)
-+	if (audit_invoke_entry() && !entryexit)
- 		audit_syscall_entry(current, audit_arch(), regs->regs[2],
- 				    regs->regs[4], regs->regs[5],
- 				    regs->regs[6], regs->regs[7]);
-diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
-index bcb8357..0ca4ce5 100644
---- a/arch/powerpc/kernel/ptrace.c
-+++ b/arch/powerpc/kernel/ptrace.c
-@@ -537,16 +537,16 @@ void do_syscall_trace_enter(struct pt_re
- 	    && (current->ptrace & PT_PTRACED))
- 		do_syscall_trace();
- 
--	if (unlikely(current->audit_context))
-+	if (audit_invoke_entry())
- 		audit_syscall_entry(current,
- #ifdef CONFIG_PPC32
--				    AUDIT_ARCH_PPC,
-+		AUDIT_ARCH_PPC,
- #else
--				    test_thread_flag(TIF_32BIT)?AUDIT_ARCH_PPC:AUDIT_ARCH_PPC64,
-+		test_thread_flag(TIF_32BIT)?AUDIT_ARCH_PPC:AUDIT_ARCH_PPC64,
- #endif
--				    regs->gpr[0],
--				    regs->gpr[3], regs->gpr[4],
--				    regs->gpr[5], regs->gpr[6]);
-+		regs->gpr[0],
-+		regs->gpr[3], regs->gpr[4],
-+		regs->gpr[5], regs->gpr[6]);
- }
- 
- void do_syscall_trace_leave(struct pt_regs *regs)
-@@ -555,10 +555,10 @@ void do_syscall_trace_leave(struct pt_re
- 	secure_computing(regs->gpr[0]);
- #endif
- 
--	if (unlikely(current->audit_context))
-+	if (audit_invoke_exit())
- 		audit_syscall_exit(current,
--				   (regs->ccr&0x1000)?AUDITSC_FAILURE:AUDITSC_SUCCESS,
--				   regs->result);
-+				(regs->ccr&0x1000)?AUDITSC_FAILURE:AUDITSC_SUCCESS,
-+				regs->result);
- 
- 	if ((test_thread_flag(TIF_SYSCALL_TRACE)
- 	     || test_thread_flag(TIF_SINGLESTEP))
-diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
-index 37dfe33..a7e94f4 100644
---- a/arch/s390/kernel/ptrace.c
-+++ b/arch/s390/kernel/ptrace.c
-@@ -733,7 +733,7 @@ out:
- asmlinkage void
- syscall_trace(struct pt_regs *regs, int entryexit)
- {
--	if (unlikely(current->audit_context) && entryexit)
-+	if (audit_invoke_exit() && entryexit)
- 		audit_syscall_exit(current, AUDITSC_RESULT(regs->gprs[2]), regs->gprs[2]);
- 
- 	if (!test_thread_flag(TIF_SYSCALL_TRACE))
-@@ -760,7 +760,7 @@ syscall_trace(struct pt_regs *regs, int 
- 		current->exit_code = 0;
- 	}
-  out:
--	if (unlikely(current->audit_context) && !entryexit)
-+	if (audit_invoke_entry() && !entryexit)
- 		audit_syscall_entry(current, 
- 				    test_thread_flag(TIF_31BIT)?AUDIT_ARCH_S390:AUDIT_ARCH_S390X,
- 				    regs->gprs[2], regs->orig_gpr2, regs->gprs[3],
-diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
-index 3f9746f..5516f2c 100644
---- a/arch/sparc64/kernel/ptrace.c
-+++ b/arch/sparc64/kernel/ptrace.c
-@@ -620,7 +620,7 @@ asmlinkage void syscall_trace(struct pt_
- 	/* do the secure computing check first */
- 	secure_computing(regs->u_regs[UREG_G1]);
- 
--	if (unlikely(current->audit_context) && syscall_exit_p) {
-+	if (audit_invoke_exit() && syscall_exit_p) {
- 		unsigned long tstate = regs->tstate;
- 		int result = AUDITSC_SUCCESS;
- 
-@@ -650,7 +650,7 @@ asmlinkage void syscall_trace(struct pt_
- 	}
- 
- out:
--	if (unlikely(current->audit_context) && !syscall_exit_p)
-+	if (audit_invoke_entry() && !syscall_exit_p)
- 		audit_syscall_entry(current,
- 				    (test_thread_flag(TIF_32BIT) ?
- 				     AUDIT_ARCH_SPARC :
-diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c
-index 98e0939..26dde51 100644
---- a/arch/um/kernel/ptrace.c
-+++ b/arch/um/kernel/ptrace.c
-@@ -267,19 +267,19 @@ void syscall_trace(union uml_pt_regs *re
- 	int is_singlestep = (current->ptrace & PT_DTRACE) && entryexit;
- 	int tracesysgood;
- 
--	if (unlikely(current->audit_context)) {
--		if (!entryexit)
-+	if (!entryexit)
-+		if(audit_invoke_entry())
- 			audit_syscall_entry(current,
--                                            HOST_AUDIT_ARCH,
--					    UPT_SYSCALL_NR(regs),
--					    UPT_SYSCALL_ARG1(regs),
--					    UPT_SYSCALL_ARG2(regs),
--					    UPT_SYSCALL_ARG3(regs),
--					    UPT_SYSCALL_ARG4(regs));
--		else audit_syscall_exit(current,
--                                        AUDITSC_RESULT(UPT_SYSCALL_RET(regs)),
--                                        UPT_SYSCALL_RET(regs));
--	}
-+					HOST_AUDIT_ARCH,
-+					UPT_SYSCALL_NR(regs),
-+					UPT_SYSCALL_ARG1(regs),
-+					UPT_SYSCALL_ARG2(regs),
-+					UPT_SYSCALL_ARG3(regs),
-+					UPT_SYSCALL_ARG4(regs));
-+	else if (audit_invoke_exit())
-+		audit_syscall_exit(current,
-+				AUDITSC_RESULT(UPT_SYSCALL_RET(regs)),
-+				UPT_SYSCALL_RET(regs));
- 
- 	/* Fake a debug trap */
- 	if (is_singlestep)
-diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c
-index 5320562..c669c78 100644
---- a/arch/x86_64/kernel/ptrace.c
-+++ b/arch/x86_64/kernel/ptrace.c
-@@ -603,24 +603,24 @@ asmlinkage void syscall_trace_enter(stru
- 	    && (current->ptrace & PT_PTRACED))
- 		syscall_trace(regs);
- 
--	if (unlikely(current->audit_context)) {
-+	if (audit_invoke_entry()) {
- 		if (test_thread_flag(TIF_IA32)) {
- 			audit_syscall_entry(current, AUDIT_ARCH_I386,
--					    regs->orig_rax,
--					    regs->rbx, regs->rcx,
--					    regs->rdx, regs->rsi);
-+						regs->orig_rax,
-+						regs->rbx, regs->rcx,
-+						regs->rdx, regs->rsi);
- 		} else {
- 			audit_syscall_entry(current, AUDIT_ARCH_X86_64,
--					    regs->orig_rax,
--					    regs->rdi, regs->rsi,
--					    regs->rdx, regs->r10);
-+						regs->orig_rax,
-+						regs->rdi, regs->rsi,
-+						regs->rdx, regs->r10);
- 		}
- 	}
- }
- 
- asmlinkage void syscall_trace_leave(struct pt_regs *regs)
- {
--	if (unlikely(current->audit_context))
-+	if (audit_invoke_exit())
- 		audit_syscall_exit(current, AUDITSC_RESULT(regs->rax), regs->rax);
- 
- 	if ((test_thread_flag(TIF_SYSCALL_TRACE)
 diff --git a/fs/namei.c b/fs/namei.c
-index 557dcf3..012ba5d 100644
+index 8dc2b03..51cfc9c 100644
 --- a/fs/namei.c
 +++ b/fs/namei.c
 @@ -1353,6 +1353,7 @@ static int may_delete(struct inode *dir,
@@ -424,7 +198,7 @@
  	return error;
  }
 diff --git a/include/linux/audit.h b/include/linux/audit.h
-index da3c019..5443dbb 100644
+index da3c019..1c47c59 100644
 --- a/include/linux/audit.h
 +++ b/include/linux/audit.h
 @@ -33,27 +33,42 @@
@@ -477,12 +251,7 @@
   
  #define AUDIT_DAEMON_START      1200    /* Daemon startup record */
  #define AUDIT_DAEMON_END        1201    /* Daemon normal stop record */
-@@ -68,10 +83,18 @@
- #define AUDIT_CONFIG_CHANGE	1305	/* Audit system configuration change */
- #define AUDIT_SOCKADDR		1306	/* sockaddr copied as syscall arg */
- #define AUDIT_CWD		1307	/* Current working directory */
-+#define AUDIT_SYSCALL_PARTIAL  1310    /* Partial syscall event */
- 
+@@ -72,6 +87,13 @@
  #define AUDIT_AVC		1400	/* SE Linux avc denial or grant */
  #define AUDIT_SELINUX_ERR	1401	/* Internal SE Linux Errors */
  #define AUDIT_AVC_PATH		1402	/* dentry, vfsmount pair from avc */
@@ -496,7 +265,7 @@
  
  #define AUDIT_KERNEL		2000	/* Asynchronous audit record. NOT A REQUEST. */
  
-@@ -81,8 +104,9 @@
+@@ -81,8 +103,9 @@
  #define AUDIT_FILTER_ENTRY	0x02	/* Apply rule at syscall entry */
  #define AUDIT_FILTER_WATCH	0x03	/* Apply rule to file system watches */
  #define AUDIT_FILTER_EXIT	0x04	/* Apply rule at syscall exit */
@@ -507,7 +276,7 @@
  
  #define AUDIT_FILTER_PREPEND	0x10	/* Prepend to front of list */
  
-@@ -98,6 +122,13 @@
+@@ -98,6 +121,13 @@
  #define AUDIT_WORD(nr) ((__u32)((nr)/32))
  #define AUDIT_BIT(nr)  (1 << ((nr) - AUDIT_WORD(nr)*32))
  
@@ -521,7 +290,7 @@
  /* Rule fields */
  				/* These are useful when checking the
  				 * task structure at task creation time
-@@ -114,6 +145,7 @@
+@@ -114,6 +144,7 @@
  #define AUDIT_LOGINUID	9
  #define AUDIT_PERS	10
  #define AUDIT_ARCH	11
@@ -529,7 +298,7 @@
  
  				/* These are ONLY useful when checking
  				 * at syscall exit time (AUDIT_AT_EXIT). */
-@@ -128,8 +160,28 @@
+@@ -128,8 +159,28 @@
  #define AUDIT_ARG2      (AUDIT_ARG0+2)
  #define AUDIT_ARG3      (AUDIT_ARG0+3)
  
@@ -559,7 +328,7 @@
  
  /* Status symbols */
  				/* Mask values */
-@@ -186,6 +238,26 @@ struct audit_status {
+@@ -186,6 +237,26 @@ struct audit_status {
  	__u32		backlog;	/* messages waiting in queue */
  };
  
@@ -586,7 +355,7 @@
  struct audit_rule {		/* for AUDIT_LIST, AUDIT_ADD, and AUDIT_DEL */
  	__u32		flags;	/* AUDIT_PER_{TASK,CALL}, AUDIT_PREPEND */
  	__u32		action;	/* AUDIT_NEVER, AUDIT_POSSIBLE, AUDIT_ALWAYS */
-@@ -222,22 +294,47 @@ extern void audit_syscall_entry(struct t
+@@ -222,22 +293,33 @@ extern void audit_syscall_entry(struct t
  extern void audit_syscall_exit(struct task_struct *task, int failed, long return_code);
  extern void audit_getname(const char *name);
  extern void audit_putname(const char *name);
@@ -622,24 +391,10 @@
  extern void audit_signal_info(int sig, struct task_struct *t);
 -extern int audit_filter_user(struct netlink_skb_parms *cb, int type);
 +extern int audit_set_macxattr(const char *name);
-+extern int audit_n_rules;
-+static inline int audit_invoke_entry(void)
-+{
-+	if (likely(!current->audit_context))
-+		return 0;
-+	return (*((int *)current->audit_context) = audit_n_rules);
-+}
-+
-+static inline int audit_invoke_exit(void)
-+{
-+	if (likely(!current->audit_context))
-+		return 0;
-+	return (*(int *)current->audit_context);
-+}
  #else
  #define audit_alloc(t) ({ 0; })
  #define audit_free(t) do { ; } while (0)
-@@ -245,16 +342,21 @@ extern int audit_filter_user(struct netl
+@@ -245,16 +327,18 @@ extern int audit_filter_user(struct netl
  #define audit_syscall_exit(t,f,r) do { ; } while (0)
  #define audit_getname(n) do { ; } while (0)
  #define audit_putname(n) do { ; } while (0)
@@ -658,13 +413,10 @@
  #define audit_signal_info(s,t) do { ; } while (0)
 -#define audit_filter_user(cb,t) ({ 1; })
 +#define audit_set_macxattr(n) do { ; } while (0)
-+#define audit_n_rules 0
-+#define audit_invoke_entry() ({ 0; })
-+#define audit_invoke_exit() ({ 0; })
  #endif
  
  #ifdef CONFIG_AUDIT
-@@ -278,12 +380,11 @@ extern void		    audit_log_d_path(struct
+@@ -278,12 +362,11 @@ extern void		    audit_log_d_path(struct
  					     const char *prefix,
  					     struct dentry *dentry,
  					     struct vfsmount *vfsmnt);
@@ -682,7 +434,7 @@
  #else
  #define audit_log(c,g,t,f,...) do { ; } while (0)
  #define audit_log_start(c,g,t) ({ NULL; })
-@@ -293,6 +394,7 @@ extern struct semaphore audit_netlink_se
+@@ -293,6 +376,7 @@ extern struct semaphore audit_netlink_se
  #define audit_log_hex(a,b,l) do { ; } while (0)
  #define audit_log_untrustedstring(a,s) do { ; } while (0)
  #define audit_log_d_path(b,p,d,v) do { ; } while (0)
@@ -1405,10 +1157,10 @@
 +extern struct mutex audit_netlink_mutex;
 diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
 new file mode 100644
-index 0000000..45f3001
+index 0000000..d3a8539
 --- /dev/null
 +++ b/kernel/auditfilter.c
-@@ -0,0 +1,651 @@
+@@ -0,0 +1,630 @@
 +/* auditfilter.c -- filtering of audit events
 + *
 + * Copyright 2003-2004 Red Hat, Inc.
@@ -1745,9 +1497,6 @@
 +				  struct list_head *list)
 +{
 +	struct audit_entry *e;
-+#ifdef CONFIG_AUDITSYSCALL
-+	int dont_count = 0;
-+#endif
 +
 +	/* Do not use the _rcu iterator here, since this is the only
 +	 * addition routine. */
@@ -1756,21 +1505,11 @@
 +			return -EEXIST;
 +	}
 +
-+	/* If either of these, don't count towards total */
-+#ifdef CONFIG_AUDITSYSCALL
-+	if (entry->rule.listnr == AUDIT_FILTER_USER ||
-+		entry->rule.listnr == AUDIT_FILTER_TYPE)
-+		dont_count = 1;
-+#endif
 +	if (entry->rule.flags & AUDIT_FILTER_PREPEND) {
 +		list_add_rcu(&entry->list, list);
 +	} else {
 +		list_add_tail_rcu(&entry->list, list);
 +	}
-+#ifdef CONFIG_AUDITSYSCALL
-+	if (!dont_count)
-+		audit_n_rules++;
-+#endif
 +
 +	return 0;
 +}
@@ -1787,15 +1526,7 @@
 +	list_for_each_entry(e, list, list) {
 +		if (!audit_compare_rule(&entry->rule, &e->rule)) {
 +			list_del_rcu(&e->list);
-+#ifdef CONFIG_AUDITSYSCALL
-+			if (entry->rule.listnr == AUDIT_FILTER_USER ||
-+				entry->rule.listnr == AUDIT_FILTER_TYPE)
-+				audit_n_rules++;	
-+#endif
 +			call_rcu(&e->rcu, audit_free_rule_rcu);
-+#ifdef CONFIG_AUDITSYSCALL
-+			audit_n_rules--;
-+#endif
 +			return 0;
 +		}
 +	}
@@ -2061,7 +1792,7 @@
 +	return result;
 +}
 diff --git a/kernel/auditsc.c b/kernel/auditsc.c
-index d7e7e63..6297d96 100644
+index d7e7e63..b613ec8 100644
 --- a/kernel/auditsc.c
 +++ b/kernel/auditsc.c
 @@ -2,6 +2,8 @@
@@ -2119,7 +1850,7 @@
  
  /* No syscall auditing will take place unless audit_enabled != 0. */
  extern int audit_enabled;
-@@ -62,28 +75,8 @@ extern int audit_enabled;
+@@ -62,29 +75,6 @@ extern int audit_enabled;
   * path_lookup. */
  #define AUDIT_NAMES_RESERVED 7
  
@@ -2145,12 +1876,11 @@
 -				 * time, and always write out the audit
 -				 * record at syscall exit time.  */
 -};
-+/* number of audit rules */
-+int audit_n_rules;
- 
+-
  /* When fs/namei.c:getname() is called, we store the pointer in name and
   * we don't let putname() free it (instead we free all of the saved
-@@ -93,12 +86,13 @@ enum audit_state {
+  * pointers at syscall exit time).
+@@ -93,12 +83,13 @@ enum audit_state {
  struct audit_names {
  	const char	*name;
  	unsigned long	ino;
@@ -2165,7 +1895,7 @@
  };
  
  struct audit_aux_data {
-@@ -115,6 +109,7 @@ struct audit_aux_data_ipcctl {
+@@ -115,6 +106,7 @@ struct audit_aux_data_ipcctl {
  	uid_t			uid;
  	gid_t			gid;
  	mode_t			mode;
@@ -2173,17 +1903,7 @@
  };
  
  struct audit_aux_data_socketcall {
-@@ -137,6 +132,9 @@ struct audit_aux_data_path {
- 
- /* The per-task audit context. */
- struct audit_context {
-+	int		    invoke_audit; /* 1 if we should do syscall auditing, important:
-+						implementation relies on this item being the
-+						first one in the data structure */	
- 	int		    in_syscall;	/* 1 if task is in a syscall */
- 	enum audit_state    state;
- 	unsigned int	    serial;     /* serial number for record */
-@@ -167,290 +165,72 @@ struct audit_context {
+@@ -167,290 +159,72 @@ struct audit_context {
  #endif
  };
  
@@ -2494,7 +2214,7 @@
  						++result;
  						break;
  					}
-@@ -460,7 +240,7 @@ static int audit_filter_rules(struct tas
+@@ -460,7 +234,7 @@ static int audit_filter_rules(struct tas
  		case AUDIT_DEVMINOR:
  			if (ctx) {
  				for (j = 0; j < ctx->name_count; j++) {
@@ -2503,7 +2223,7 @@
  						++result;
  						break;
  					}
-@@ -470,7 +250,8 @@ static int audit_filter_rules(struct tas
+@@ -470,7 +244,8 @@ static int audit_filter_rules(struct tas
  		case AUDIT_INODE:
  			if (ctx) {
  				for (j = 0; j < ctx->name_count; j++) {
@@ -2513,7 +2233,7 @@
  						++result;
  						break;
  					}
-@@ -480,19 +261,17 @@ static int audit_filter_rules(struct tas
+@@ -480,19 +255,17 @@ static int audit_filter_rules(struct tas
  		case AUDIT_LOGINUID:
  			result = 0;
  			if (ctx)
@@ -2535,7 +2255,7 @@
  		if (!result)
  			return 0;
  	}
-@@ -527,7 +306,7 @@ static enum audit_state audit_filter_tas
+@@ -527,7 +300,7 @@ static enum audit_state audit_filter_tas
  /* At syscall entry and exit time, this filter is called if the
   * audit_state is not low enough that auditing cannot take place, but is
   * also not high enough that we already know we have to write an audit
@@ -2544,7 +2264,7 @@
   */
  static enum audit_state audit_filter_syscall(struct task_struct *tsk,
  					     struct audit_context *ctx,
-@@ -541,77 +320,19 @@ static enum audit_state audit_filter_sys
+@@ -541,77 +314,19 @@ static enum audit_state audit_filter_sys
  
  	rcu_read_lock();
  	if (!list_empty(list)) {
@@ -2562,9 +2282,7 @@
 -	rcu_read_unlock();
 -	return AUDIT_BUILD_CONTEXT;
 -}
-+		int word = AUDIT_WORD(ctx->major);
-+		int bit  = AUDIT_BIT(ctx->major);
- 
+-
 -static int audit_filter_user_rules(struct netlink_skb_parms *cb,
 -			      struct audit_rule *rule,
 -			      enum audit_state *state)
@@ -2590,7 +2308,9 @@
 -			result = (cb->loginuid == value);
 -			break;
 -		}
--
++		int word = AUDIT_WORD(ctx->major);
++		int bit  = AUDIT_BIT(ctx->major);
+ 
 -		if (rule->fields[i] & AUDIT_NEGATE)
 -			result = !result;
 -		if (!result)
@@ -2631,7 +2351,7 @@
  }
  
  /* This should be called with task_lock() held. */
-@@ -654,17 +375,18 @@ static inline void audit_free_names(stru
+@@ -654,17 +369,18 @@ static inline void audit_free_names(stru
  #if AUDIT_DEBUG == 2
  	if (context->auditable
  	    ||context->put_count + context->ino_count != context->name_count) {
@@ -2654,7 +2374,7 @@
  		dump_stack();
  		return;
  	}
-@@ -674,9 +396,13 @@ static inline void audit_free_names(stru
+@@ -674,9 +390,13 @@ static inline void audit_free_names(stru
  	context->ino_count  = 0;
  #endif
  
@@ -2669,7 +2389,7 @@
  	context->name_count = 0;
  	if (context->pwd)
  		dput(context->pwd);
-@@ -696,6 +422,12 @@ static inline void audit_free_aux(struct
+@@ -696,6 +416,12 @@ static inline void audit_free_aux(struct
  			dput(axi->dentry);
  			mntput(axi->mnt);
  		}
@@ -2682,7 +2402,7 @@
  		context->aux = aux->next;
  		kfree(aux);
  	}
-@@ -721,10 +453,15 @@ static inline struct audit_context *audi
+@@ -721,10 +447,15 @@ static inline struct audit_context *audi
  	return context;
  }
  
@@ -2700,7 +2420,7 @@
  int audit_alloc(struct task_struct *tsk)
  {
  	struct audit_context *context;
-@@ -775,7 +512,37 @@ static inline void audit_free_context(st
+@@ -775,7 +506,37 @@ static inline void audit_free_context(st
  		printk(KERN_ERR "audit: freed %d contexts\n", count);
  }
  
@@ -2739,7 +2459,7 @@
  {
  	char name[sizeof(current->comm)];
  	struct mm_struct *mm = current->mm;
-@@ -788,6 +555,10 @@ static void audit_log_task_info(struct a
+@@ -788,6 +549,10 @@ static void audit_log_task_info(struct a
  	if (!mm)
  		return;
  
@@ -2750,7 +2470,7 @@
  	down_read(&mm->mmap_sem);
  	vma = mm->mmap;
  	while (vma) {
-@@ -801,6 +572,7 @@ static void audit_log_task_info(struct a
+@@ -801,6 +566,7 @@ static void audit_log_task_info(struct a
  		vma = vma->vm_next;
  	}
  	up_read(&mm->mmap_sem);
@@ -2758,87 +2478,43 @@
  }
  
  static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask)
-@@ -808,35 +580,59 @@ static void audit_log_exit(struct audit_
+@@ -808,6 +574,7 @@ static void audit_log_exit(struct audit_
  	int i;
  	struct audit_buffer *ab;
  	struct audit_aux_data *aux;
 +	const char *tty;
  
--	ab = audit_log_start(context, gfp_mask, AUDIT_SYSCALL);
-+	ab = audit_log_start(context, gfp_mask,
-+			context->in_syscall ? AUDIT_SYSCALL: AUDIT_SYSCALL_PARTIAL);
+ 	ab = audit_log_start(context, gfp_mask, AUDIT_SYSCALL);
  	if (!ab)
- 		return;		/* audit_panic has been called */
--	audit_log_format(ab, "arch=%x syscall=%d",
--			 context->arch, context->major);
-+	if (context->in_syscall) {
-+		audit_log_format(ab, "arch=%x syscall=%d",
-+			context->arch, context->major);
-+	}
- 	if (context->personality != PER_LINUX)
- 		audit_log_format(ab, " per=%lx", context->personality);
- 	if (context->return_valid)
+@@ -820,11 +587,15 @@ static void audit_log_exit(struct audit_
  		audit_log_format(ab, " success=%s exit=%ld", 
  				 (context->return_valid==AUDITSC_SUCCESS)?"yes":"no",
  				 context->return_code);
--	audit_log_format(ab,
--		  " a0=%lx a1=%lx a2=%lx a3=%lx items=%d"
--		  " pid=%d auid=%u uid=%u gid=%u"
--		  " euid=%u suid=%u fsuid=%u"
--		  " egid=%u sgid=%u fsgid=%u",
--		  context->argv[0],
--		  context->argv[1],
--		  context->argv[2],
--		  context->argv[3],
--		  context->name_count,
--		  context->pid,
--		  context->loginuid,
--		  context->uid,
--		  context->gid,
--		  context->euid, context->suid, context->fsuid,
--		  context->egid, context->sgid, context->fsgid);
--	audit_log_task_info(ab);
 +	if (current->signal->tty && current->signal->tty->name)
 +		tty = current->signal->tty->name;
 +	else
 +		tty = "(none)";
-+	if (context->in_syscall) {
-+		audit_log_format(ab,
-+			  " a0=%lx a1=%lx a2=%lx a3=%lx items=%d"
-+			  " pid=%d auid=%u uid=%u gid=%u"
-+		 	 " euid=%u suid=%u fsuid=%u"
-+			  " egid=%u sgid=%u fsgid=%u tty=%s",
-+		 	 context->argv[0],
-+			  context->argv[1],
-+			  context->argv[2],
-+		 	 context->argv[3],
-+		  	context->name_count,
-+		  	context->pid,
-+		  	context->loginuid,
-+		  	context->uid,
-+		  	context->gid,
-+		  	context->euid, context->suid, context->fsuid,
-+		  	context->egid, context->sgid, context->fsgid, tty);
-+	} else {
-+		audit_log_format(ab,
-+			" items=%d"
-+			" pid=%d auid=%u uid=%u gid=%u"
-+			" euid=%u suid=%u fsuid=%u"
-+			" egid=%u sgid=%u fsgid=%u tty=%s",
-+			context->name_count,
-+			context->pid,
-+			context->loginuid,
-+			context->uid,
-+			context->gid,
-+			context->euid, context->suid, context->fsuid,
-+			context->egid, context->sgid, context->fsgid, tty);
-+	}
-+
+ 	audit_log_format(ab,
+ 		  " a0=%lx a1=%lx a2=%lx a3=%lx items=%d"
+ 		  " pid=%d auid=%u uid=%u gid=%u"
+ 		  " euid=%u suid=%u fsuid=%u"
+-		  " egid=%u sgid=%u fsgid=%u",
++		  " egid=%u sgid=%u fsgid=%u tty=%s",
+ 		  context->argv[0],
+ 		  context->argv[1],
+ 		  context->argv[2],
+@@ -835,8 +606,8 @@ static void audit_log_exit(struct audit_
+ 		  context->uid,
+ 		  context->gid,
+ 		  context->euid, context->suid, context->fsuid,
+-		  context->egid, context->sgid, context->fsgid);
+-	audit_log_task_info(ab);
++		  context->egid, context->sgid, context->fsgid, tty);
 +	audit_log_task_info(ab, gfp_mask);
  	audit_log_end(ab);
  
  	for (aux = context->aux; aux; aux = aux->next) {
-@@ -849,8 +645,8 @@ static void audit_log_exit(struct audit_
+@@ -849,8 +620,8 @@ static void audit_log_exit(struct audit_
  		case AUDIT_IPC: {
  			struct audit_aux_data_ipcctl *axi = (void *)aux;
  			audit_log_format(ab, 
@@ -2849,7 +2525,7 @@
  			break; }
  
  		case AUDIT_SOCKETCALL: {
-@@ -885,42 +681,62 @@ static void audit_log_exit(struct audit_
+@@ -885,42 +656,62 @@ static void audit_log_exit(struct audit_
  		}
  	}
  	for (i = 0; i < context->name_count; i++) {
@@ -2932,7 +2608,7 @@
  	if (likely(!context))
  		return;
  
-@@ -934,13 +750,24 @@ void audit_free(struct task_struct *tsk)
+@@ -934,13 +725,24 @@ void audit_free(struct task_struct *tsk)
  	audit_free_context(context);
  }
  
@@ -2959,7 +2635,7 @@
  void audit_syscall_entry(struct task_struct *tsk, int arch, int major,
  			 unsigned long a1, unsigned long a2,
  			 unsigned long a3, unsigned long a4)
-@@ -950,7 +777,8 @@ void audit_syscall_entry(struct task_str
+@@ -950,7 +752,8 @@ void audit_syscall_entry(struct task_str
  
  	BUG_ON(!context);
  
@@ -2969,7 +2645,7 @@
  	 * calls in kernel_thread via the entry.S interface, instead of
  	 * with direct calls.  (If you are porting to a new
  	 * architecture, hitting this condition can indicate that you
-@@ -966,11 +794,6 @@ void audit_syscall_entry(struct task_str
+@@ -966,11 +769,6 @@ void audit_syscall_entry(struct task_str
  	if (context->in_syscall) {
  		struct audit_context *newctx;
  
@@ -2981,7 +2657,7 @@
  #if AUDIT_DEBUG
  		printk(KERN_ERR
  		       "audit(:%d) pid=%d in syscall=%d;"
-@@ -1014,11 +837,18 @@ void audit_syscall_entry(struct task_str
+@@ -1014,11 +812,18 @@ void audit_syscall_entry(struct task_str
  	context->auditable  = !!(state == AUDIT_RECORD_CONTEXT);
  }
  
@@ -3002,16 +2678,7 @@
  void audit_syscall_exit(struct task_struct *tsk, int valid, long return_code)
  {
  	struct audit_context *context;
-@@ -1033,7 +863,7 @@ void audit_syscall_exit(struct task_stru
- 	if (likely(!context))
- 		goto out;
- 
--	if (context->in_syscall && context->auditable)
-+	if (context->auditable)
- 		audit_log_exit(context, GFP_KERNEL);
- 
- 	context->in_syscall = 0;
-@@ -1053,7 +883,13 @@ void audit_syscall_exit(struct task_stru
+@@ -1053,7 +858,13 @@ void audit_syscall_exit(struct task_stru
  	put_task_struct(tsk);
  }
  
@@ -3026,7 +2693,7 @@
  void audit_getname(const char *name)
  {
  	struct audit_context *context = current->audit_context;
-@@ -1082,10 +918,13 @@ void audit_getname(const char *name)
+@@ -1082,10 +893,13 @@ void audit_getname(const char *name)
  		
  }
  
@@ -3044,7 +2711,7 @@
  void audit_putname(const char *name)
  {
  	struct audit_context *context = current->audit_context;
-@@ -1100,7 +939,7 @@ void audit_putname(const char *name)
+@@ -1100,7 +914,7 @@ void audit_putname(const char *name)
  			for (i = 0; i < context->name_count; i++)
  				printk(KERN_ERR "name[%d] = %p = %s\n", i,
  				       context->names[i].name,
@@ -3053,7 +2720,7 @@
  		}
  #endif
  		__putname(name);
-@@ -1122,9 +961,52 @@ void audit_putname(const char *name)
+@@ -1122,9 +936,52 @@ void audit_putname(const char *name)
  #endif
  }
  
@@ -3109,7 +2776,7 @@
  {
  	int idx;
  	struct audit_context *context = current->audit_context;
-@@ -1150,15 +1032,105 @@ void audit_inode(const char *name, const
+@@ -1150,15 +1007,105 @@ void audit_inode(const char *name, const
  		++context->ino_count;
  #endif
  	}
@@ -3129,8 +2796,8 @@
 +		context->names[idx].ino   = inode->i_ino;
 +		context->names[idx].pino  = (unsigned long)-1;
 +	}
-+}
-+
+ }
+ 
 +/**
 + * audit_inode_child - collect inode info for created/removed objects
 + * @dname: inode's dentry name
@@ -3204,8 +2871,8 @@
 +		context->names[idx].rdev  = inode->i_rdev;
 +		audit_inode_context(idx, inode);
 +	}
- }
- 
++}
++
 +/**
 + * auditsc_get_stamp - get local copies of audit_context values
 + * @ctx: audit_context for the task
@@ -3217,11 +2884,8 @@
  void auditsc_get_stamp(struct audit_context *ctx,
  		       struct timespec *t, unsigned int *serial)
  {
-@@ -1168,8 +1140,18 @@ void auditsc_get_stamp(struct audit_cont
- 	t->tv_nsec = ctx->ctime.tv_nsec;
- 	*serial    = ctx->serial;
+@@ -1170,6 +1117,15 @@ void auditsc_get_stamp(struct audit_cont
  	ctx->auditable = 1;
-+	ctx->invoke_audit = 1;
  }
  
 +/**
@@ -3236,7 +2900,7 @@
  int audit_set_loginuid(struct task_struct *task, uid_t loginuid)
  {
  	if (task->audit_context) {
-@@ -1188,12 +1170,59 @@ int audit_set_loginuid(struct task_struc
+@@ -1188,12 +1144,59 @@ int audit_set_loginuid(struct task_struc
  	return 0;
  }
  
@@ -3297,7 +2961,7 @@
  {
  	struct audit_aux_data_ipcctl *ax;
  	struct audit_context *context = current->audit_context;
-@@ -1201,7 +1230,7 @@ int audit_ipc_perms(unsigned long qbytes
+@@ -1201,7 +1204,7 @@ int audit_ipc_perms(unsigned long qbytes
  	if (likely(!context))
  		return 0;
  
@@ -3306,7 +2970,7 @@
  	if (!ax)
  		return -ENOMEM;
  
-@@ -1209,6 +1238,7 @@ int audit_ipc_perms(unsigned long qbytes
+@@ -1209,6 +1212,7 @@ int audit_ipc_perms(unsigned long qbytes
  	ax->uid = uid;
  	ax->gid = gid;
  	ax->mode = mode;
@@ -3314,7 +2978,7 @@
  
  	ax->d.type = AUDIT_IPC;
  	ax->d.next = context->aux;
-@@ -1216,6 +1246,13 @@ int audit_ipc_perms(unsigned long qbytes
+@@ -1216,6 +1220,13 @@ int audit_ipc_perms(unsigned long qbytes
  	return 0;
  }
  
@@ -3328,7 +2992,7 @@
  int audit_socketcall(int nargs, unsigned long *args)
  {
  	struct audit_aux_data_socketcall *ax;
-@@ -1237,6 +1274,13 @@ int audit_socketcall(int nargs, unsigned
+@@ -1237,6 +1248,13 @@ int audit_socketcall(int nargs, unsigned
  	return 0;
  }
  
@@ -3342,7 +3006,7 @@
  int audit_sockaddr(int len, void *a)
  {
  	struct audit_aux_data_sockaddr *ax;
-@@ -1258,6 +1302,15 @@ int audit_sockaddr(int len, void *a)
+@@ -1258,6 +1276,15 @@ int audit_sockaddr(int len, void *a)
  	return 0;
  }
  
@@ -3358,7 +3022,7 @@
  int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt)
  {
  	struct audit_aux_data_path *ax;
-@@ -1279,6 +1332,14 @@ int audit_avc_path(struct dentry *dentry
+@@ -1279,6 +1306,14 @@ int audit_avc_path(struct dentry *dentry
  	return 0;
  }
  
@@ -3373,7 +3037,7 @@
  void audit_signal_info(int sig, struct task_struct *t)
  {
  	extern pid_t audit_sig_pid;
-@@ -1295,4 +1356,3 @@ void audit_signal_info(int sig, struct t
+@@ -1295,4 +1330,3 @@ void audit_signal_info(int sig, struct t
  		}
  	}
  }
@@ -3457,7 +3121,7 @@
  	set_to_dummy_if_null(ops, msg_msg_free_security);
  	set_to_dummy_if_null(ops, msg_queue_alloc_security);
 diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
-index b7773bf..0c7fdbf 100644
+index b65c201..81b726b 100644
 --- a/security/selinux/hooks.c
 +++ b/security/selinux/hooks.c
 @@ -117,6 +117,32 @@ static struct security_operations *secon




More information about the fedora-cvs-commits mailing list