[PATCH] prevent duplicate syscall rules

Amy Griffis amy.griffis at hp.com
Fri Jul 29 22:50:14 UTC 2005


The following patch against audit.81 prevents duplicate syscall rules in a
given filter list by walking the list on each rule add.

I also removed the unused struct audit_entry in audit.c and made the static
inlines in auditsc.c consistent.

Signed-off-by: Amy Griffis <amy.griffis at hp.com>

 audit.c   |    5 ---
 auditsc.c |   95 ++++++++++++++++++++++++++++++++++++--------------------------
 2 files changed, 56 insertions(+), 44 deletions(-)

diff -Nrup linux-2.6.9.orig/kernel/audit.c linux-2.6.9/kernel/audit.c
--- linux-2.6.9.orig/kernel/audit.c	2005-07-29 13:37:34.581058000 -0400
+++ linux-2.6.9/kernel/audit.c	2005-07-29 13:41:32.018555559 -0400
@@ -147,11 +147,6 @@ static void audit_set_pid(struct audit_b
 	nlh->nlmsg_pid = pid;
 }
 
-struct audit_entry {
-	struct list_head  list;
-	struct audit_rule rule;
-};
-
 static void audit_panic(const char *message)
 {
 	switch (audit_failure)
diff -Nrup linux-2.6.9.orig/kernel/auditsc.c linux-2.6.9/kernel/auditsc.c
--- linux-2.6.9.orig/kernel/auditsc.c	2005-07-29 13:37:34.572269000 -0400
+++ linux-2.6.9/kernel/auditsc.c	2005-07-29 13:53:31.988273302 -0400
@@ -198,9 +198,36 @@ struct audit_entry {
 
 extern int audit_pid;
 
+/* Copy rule from user-space to kernel-space.  Called from 
+ * audit_add_rule during AUDIT_ADD. */
+static inline int audit_copy_rule(struct audit_rule *d, struct audit_rule *s)
+{
+	int i;
+
+	if (s->action != AUDIT_NEVER
+	    && s->action != AUDIT_POSSIBLE
+	    && s->action != AUDIT_ALWAYS)
+		return -1;
+	if (s->field_count < 0 || s->field_count > AUDIT_MAX_FIELDS)
+		return -1;
+	if ((s->flags & ~AUDIT_FILTER_PREPEND) >= AUDIT_NR_FILTERS)
+		return -1;
+
+	d->flags	= s->flags;
+	d->action	= s->action;
+	d->field_count	= s->field_count;
+	for (i = 0; i < d->field_count; i++) {
+		d->fields[i] = s->fields[i];
+		d->values[i] = s->values[i];
+	}
+	for (i = 0; i < AUDIT_BITMASK_SIZE; i++) d->mask[i] = s->mask[i];
+	return 0;
+}
+
 /* Check to see if two rules are identical.  It is called from
+ * audit_add_rule during AUDIT_ADD and 
  * audit_del_rule during AUDIT_DEL. */
-static int audit_compare_rule(struct audit_rule *a, struct audit_rule *b)
+static inline int audit_compare_rule(struct audit_rule *a, struct audit_rule *b)
 {
 	int i;
 
@@ -229,18 +256,37 @@ static int audit_compare_rule(struct aud
 /* Note that audit_add_rule and audit_del_rule are called via
  * audit_receive() in audit.c, and are protected by
  * audit_netlink_sem. */
-static inline void audit_add_rule(struct audit_entry *entry,
+static inline int audit_add_rule(struct audit_rule *rule,
 				  struct list_head *list)
 {
+	struct audit_entry  *entry;
+
+	/* Do not use the _rcu iterator here, since this is the only
+	 * addition routine. */
+	list_for_each_entry(entry, list, list) {
+		if (!audit_compare_rule(rule, &entry->rule)) {
+			return -EINVAL;
+		}
+	}
+
+	if (!(entry = kmalloc(sizeof(*entry), GFP_KERNEL)))
+		return -ENOMEM;
+	if (audit_copy_rule(&entry->rule, rule)) {
+		kfree(entry);
+		return -EINVAL;
+	}
+
 	if (entry->rule.flags & AUDIT_FILTER_PREPEND) {
 		entry->rule.flags &= ~AUDIT_FILTER_PREPEND;
 		list_add_rcu(&entry->list, list);
 	} else {
 		list_add_tail_rcu(&entry->list, list);
 	}
+
+	return 0;
 }
 
-static void audit_free_rule(struct rcu_head *head)
+static inline void audit_free_rule(struct rcu_head *head)
 {
 	struct audit_entry *e = container_of(head, struct audit_entry, rcu);
 	kfree(e);
@@ -267,32 +313,6 @@ static inline int audit_del_rule(struct 
 }
 
 #ifdef CONFIG_NET
-/* Copy rule from user-space to kernel-space.  Called during
- * AUDIT_ADD. */
-static int audit_copy_rule(struct audit_rule *d, struct audit_rule *s)
-{
-	int i;
-
-	if (s->action != AUDIT_NEVER
-	    && s->action != AUDIT_POSSIBLE
-	    && s->action != AUDIT_ALWAYS)
-		return -1;
-	if (s->field_count < 0 || s->field_count > AUDIT_MAX_FIELDS)
-		return -1;
-	if ((s->flags & ~AUDIT_FILTER_PREPEND) >= AUDIT_NR_FILTERS)
-		return -1;
-
-	d->flags	= s->flags;
-	d->action	= s->action;
-	d->field_count	= s->field_count;
-	for (i = 0; i < d->field_count; i++) {
-		d->fields[i] = s->fields[i];
-		d->values[i] = s->values[i];
-	}
-	for (i = 0; i < AUDIT_BITMASK_SIZE; i++) d->mask[i] = s->mask[i];
-	return 0;
-}
-
 static int audit_list_rules(void *_dest)
 {
 	int pid, seq;
@@ -322,7 +342,6 @@ static int audit_list_rules(void *_dest)
 int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
 							uid_t loginuid)
 {
-	struct audit_entry *entry;
 	struct task_struct *tsk;
 	int *dest;
 	int		   err = 0;
@@ -349,16 +368,14 @@ int audit_receive_filter(int type, int p
 		}
 		break;
 	case AUDIT_ADD:
-		if (!(entry = kmalloc(sizeof(*entry), GFP_KERNEL)))
-			return -ENOMEM;
-		if (audit_copy_rule(&entry->rule, data)) {
-			kfree(entry);
+		listnr =((struct audit_rule *)data)->flags & ~AUDIT_FILTER_PREPEND;
+		if (listnr >= AUDIT_NR_FILTERS)
 			return -EINVAL;
-		}
-		listnr = entry->rule.flags & ~AUDIT_FILTER_PREPEND;
-		audit_add_rule(entry, &audit_filter_list[listnr]);
-		audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, 
-				"auid=%u added an audit rule\n", loginuid);
+
+		err = audit_add_rule(data, &audit_filter_list[listnr]);
+		if (!err)
+			audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+				  "auid=%u added an audit rule\n", loginuid);
 		break;
 	case AUDIT_DEL:
 		listnr =((struct audit_rule *)data)->flags & ~AUDIT_FILTER_PREPEND;




More information about the Linux-audit mailing list