lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:	Wed, 10 Mar 2010 18:24:50 +0100
From:	Juraj Hlista <juro.hlista@...il.com>
To:	viro@...iv.linux.org.uk, eparis@...hat.com, mitr@...hat.com
Cc:	linux-audit@...hat.com, linux-kernel@...r.kernel.org
Subject: [PATCH] audit keys: support for multiple audit keys

An audit rule can have more than 1 key, the keys can be of
different types (only AUDIT_FILTERKEY for now)

For example, it is possible to create a rule such as:
    auditctl -a exit,always -F path=/file -F key=k1 -F key=k2 -F key=k3


Kernel patch:
---
 include/linux/audit.h |   11 ++-
 kernel/audit.c        |   12 ++--
 kernel/audit_tree.c   |    4 +-
 kernel/audit_watch.c  |    5 +-
 kernel/auditfilter.c  |  167 +++++++++++++++++++++++++++++++++++--------------
 kernel/auditsc.c      |   81 ++++++++++++++++++------
 6 files changed, 204 insertions(+), 76 deletions(-)

diff --git a/include/linux/audit.h b/include/linux/audit.h
index f391d45..bc77a9f 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -152,10 +152,12 @@
 #define AUDIT_POSSIBLE 1	/* Build context if rule matches  */
 #define AUDIT_ALWAYS   2	/* Generate audit record if rule matches */

+
 /* Rule structure sizes -- if these change, different AUDIT_ADD and
  * AUDIT_LIST commands must be implemented. */
 #define AUDIT_MAX_FIELDS   64
 #define AUDIT_MAX_KEY_LEN  256
+#define AUDIT_MAX_KEYS	   8
 #define AUDIT_BITMASK_SIZE 64
 #define AUDIT_WORD(nr) ((__u32)((nr)/32))
 #define AUDIT_BIT(nr)  (1 << ((nr) - AUDIT_WORD(nr)*32))
@@ -384,8 +386,9 @@ struct audit_krule {
 	u32			action;
 	u32			mask[AUDIT_BITMASK_SIZE];
 	u32			buflen; /* for data alloc on list rules */
+	u32			keyfield_count;
 	u32			field_count;
-	char			*filterkey; /* ties events to rules */
+	struct audit_field	*keyfields;
 	struct audit_field	*fields;
 	struct audit_field	*arch_f; /* quick access to arch field */
 	struct audit_field	*inode_f; /* quick access to an inode field */
@@ -598,8 +601,8 @@ extern void		    audit_log_untrustedstring(struct
audit_buffer *ab,
 extern void		    audit_log_d_path(struct audit_buffer *ab,
 					     const char *prefix,
 					     struct path *path);
-extern void		    audit_log_key(struct audit_buffer *ab,
-					  char *key);
+extern void		    audit_log_key(struct audit_buffer *ab, int type,
+					 	char *key);
 extern void		    audit_log_lost(const char *message);
 extern int		    audit_update_lsm_rules(void);

@@ -622,7 +625,7 @@ extern int audit_enabled;
 #define audit_log_n_untrustedstring(a,n,s) do { ; } while (0)
 #define audit_log_untrustedstring(a,s) do { ; } while (0)
 #define audit_log_d_path(b, p, d) do { ; } while (0)
-#define audit_log_key(b, k) do { ; } while (0)
+#define audit_log_key(b, t, k) do { ; } while (0)
 #define audit_enabled 0
 #endif
 #endif
diff --git a/kernel/audit.c b/kernel/audit.c
index c3b6cb5..18090c0 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1440,13 +1440,15 @@ void audit_log_d_path(struct audit_buffer *ab,
const char *prefix,
 	kfree(pathname);
 }

-void audit_log_key(struct audit_buffer *ab, char *key)
+void audit_log_key(struct audit_buffer *ab, int type, char *key)
 {
-	audit_log_format(ab, " key=");
-	if (key)
+	if (!key) {
+		audit_log_format(ab, " key=(null)");
+		return;
+	} else if (type == AUDIT_FILTERKEY) {
+		audit_log_format(ab, " key=");
 		audit_log_untrustedstring(ab, key);
-	else
-		audit_log_format(ab, "(null)");
+	}
 }

 /**
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
index f671d6b..f45c4d0 100644
--- a/kernel/audit_tree.c
+++ b/kernel/audit_tree.c
@@ -454,6 +454,7 @@ static void kill_rules(struct audit_tree *tree)
 	struct audit_krule *rule, *next;
 	struct audit_entry *entry;
 	struct audit_buffer *ab;
+	int i;

 	list_for_each_entry_safe(rule, next, &tree->rules, rlist) {
 		entry = container_of(rule, struct audit_entry, rule);
@@ -466,7 +467,8 @@ static void kill_rules(struct audit_tree *tree)
 			audit_log_string(ab, "remove rule");
 			audit_log_format(ab, " dir=");
 			audit_log_untrustedstring(ab, rule->tree->pathname);
-			audit_log_key(ab, rule->filterkey);
+			for (i = 0; i < rule->keyfield_count; i++)
+				audit_log_key(ab, rule->keyfields[i].type, rule->keyfields[i].lsm_str);
 			audit_log_format(ab, " list=%d res=1", rule->listnr);
 			audit_log_end(ab);
 			rule->tree = NULL;
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index 31f9be8..5a306e5 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -240,6 +240,8 @@ static void audit_watch_log_rule_change(struct
audit_krule *r, struct audit_watc
 {
 	if (audit_enabled) {
 		struct audit_buffer *ab;
+		int i;
+
 		ab = audit_log_start(NULL, GFP_NOFS, AUDIT_CONFIG_CHANGE);
 		audit_log_format(ab, "auid=%u ses=%u op=",
 				 audit_get_loginuid(current),
@@ -247,7 +249,8 @@ static void audit_watch_log_rule_change(struct
audit_krule *r, struct audit_watc
 		audit_log_string(ab, op);
 		audit_log_format(ab, " path=");
 		audit_log_untrustedstring(ab, w->path);
-		audit_log_key(ab, r->filterkey);
+		for (i = 0; i < r->keyfield_count; i++)
+			audit_log_key(ab, r->keyfields[i].type, r->keyfields[i].lsm_str);
 		audit_log_format(ab, " list=%d res=1", r->listnr);
 		audit_log_end(ab);
 	}
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index f5e4cae..79c4978 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -74,14 +74,24 @@ static inline void audit_free_rule(struct audit_entry *e)
 	/* some rules don't have associated watches */
 	if (erule->watch)
 		audit_put_watch(erule->watch);
-	if (erule->fields)
+	if (erule->fields) {
 		for (i = 0; i < erule->field_count; i++) {
 			struct audit_field *f = &erule->fields[i];
 			kfree(f->lsm_str);
 			security_audit_rule_free(f->lsm_rule);
 		}
+	}
 	kfree(erule->fields);
-	kfree(erule->filterkey);
+
+	if (erule->keyfields) {
+		for (i = 0; i < erule->keyfield_count; i++) {
+			struct audit_field *f = &erule->keyfields[i];
+			kfree(f->lsm_str);
+			security_audit_rule_free(f->lsm_rule);
+		}
+	}
+	kfree(erule->keyfields);
+
 	kfree(e);
 }

@@ -92,10 +102,11 @@ void audit_free_rule_rcu(struct rcu_head *head)
 }

 /* Initialize an audit filterlist entry. */
-static inline struct audit_entry *audit_init_entry(u32 field_count)
+static inline struct audit_entry *audit_init_entry(u32 field_count,
u32 keyfield_count)
 {
 	struct audit_entry *entry;
 	struct audit_field *fields;
+	struct audit_field *keyfields;

 	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
 	if (unlikely(!entry))
@@ -108,6 +119,14 @@ static inline struct audit_entry
*audit_init_entry(u32 field_count)
 	}
 	entry->rule.fields = fields;

+	keyfields = kzalloc(sizeof(*keyfields) * keyfield_count, GFP_KERNEL);
+	if (unlikely(!keyfields)) {
+		kfree(entry);
+		kfree(fields);
+		return NULL;
+	}
+	entry->rule.keyfields = keyfields;
+
 	return entry;
 }

@@ -151,6 +170,15 @@ static inline int audit_to_inode(struct audit_krule *krule,
 	return 0;
 }

+static inline int audit_to_key(struct audit_krule *krule,
+			       struct audit_field *f)
+{
+	if (krule->listnr != AUDIT_FILTER_EXIT ||
+	    f->op != Audit_equal)
+		return -EINVAL;
+
+	return 0;
+}
 static __u32 *classes[AUDIT_SYSCALL_CLASSES];

 int __init audit_register_class(int class, unsigned *list)
@@ -227,6 +255,7 @@ static inline struct audit_entry
*audit_to_entry_common(struct audit_rule *rule)
 {
 	unsigned listnr;
 	struct audit_entry *entry;
+	int kf_count = 0;
 	int i, err;

 	err = -EINVAL;
@@ -252,15 +281,24 @@ static inline struct audit_entry
*audit_to_entry_common(struct audit_rule *rule)
 	if (rule->field_count > AUDIT_MAX_FIELDS)
 		goto exit_err;

+	for (i = 0; i < rule->field_count; i++) {
+		if (rule->fields[i] == AUDIT_FILTERKEY)
+			kf_count++;
+	}
+
+	if (kf_count > AUDIT_MAX_KEYS)
+		goto exit_err;
+
 	err = -ENOMEM;
-	entry = audit_init_entry(rule->field_count);
+	entry = audit_init_entry(rule->field_count - kf_count, kf_count);
 	if (!entry)
 		goto exit_err;

 	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.field_count = rule->field_count - kf_count;
+	entry->rule.keyfield_count = kf_count;

 	for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
 		entry->rule.mask[i] = rule->mask[i];
@@ -411,10 +449,11 @@ static struct audit_entry
*audit_data_to_entry(struct audit_rule_data *data,
 					       size_t datasz)
 {
 	int err = 0;
-	struct audit_entry *entry;
+	struct audit_entry *entry = NULL;
 	void *bufp;
 	size_t remain = datasz - sizeof(struct audit_rule_data);
 	int i;
+	int f_count = 0, kf_count = 0;
 	char *str;

 	entry = audit_to_entry_common((struct audit_rule *)data);
@@ -424,7 +463,11 @@ static struct audit_entry
*audit_data_to_entry(struct audit_rule_data *data,
 	bufp = data->buf;
 	entry->rule.vers_ops = 2;
 	for (i = 0; i < data->field_count; i++) {
-		struct audit_field *f = &entry->rule.fields[i];
+		struct audit_field *f = NULL;
+		if (data->fields[i] == AUDIT_FILTERKEY)
+			f = &entry->rule.keyfields[kf_count++];
+		else
+			f = &entry->rule.fields[f_count++];

 		err = -EINVAL;

@@ -522,13 +565,20 @@ static struct audit_entry
*audit_data_to_entry(struct audit_rule_data *data,
 			break;
 		case AUDIT_FILTERKEY:
 			err = -EINVAL;
-			if (entry->rule.filterkey || f->val > AUDIT_MAX_KEY_LEN)
+			if (f->val > AUDIT_MAX_KEY_LEN)
 				goto exit_free;
 			str = audit_unpack_string(&bufp, &remain, f->val);
 			if (IS_ERR(str))
 				goto exit_free;
 			entry->rule.buflen += f->val;
-			entry->rule.filterkey = str;
+
+			err = audit_to_key(&entry->rule, f);
+			if (err) {
+				kfree(str);
+				goto exit_free;
+			} else {
+				f->lsm_str = str;
+			}
 			break;
 		case AUDIT_PERM:
 			if (f->val & ~15)
@@ -565,6 +615,18 @@ static inline size_t audit_pack_string(void
**bufp, const char *str)
 	return len;
 }

+
+static inline void audit_op_translate(struct audit_krule *krule,
struct audit_rule *rule, int j)
+{
+	if (krule->vers_ops == 1) {
+		if (krule->fields[j].op == Audit_not_equal)
+				rule->fields[j] |= AUDIT_NEGATE;
+		} else {
+			rule->fields[j] |= audit_ops[krule->fields[j].op];
+	}
+}
+
+
 /* Translate kernel rule respresentation to struct audit_rule.
  * Exists for backward compatibility with userspace. */
 static struct audit_rule *audit_krule_to_rule(struct audit_krule *krule)
@@ -578,19 +640,20 @@ static struct audit_rule
*audit_krule_to_rule(struct audit_krule *krule)

 	rule->flags = krule->flags | krule->listnr;
 	rule->action = krule->action;
-	rule->field_count = krule->field_count;
-	for (i = 0; i < rule->field_count; i++) {
+	rule->field_count = krule->field_count + krule->keyfield_count;
+	for (i = 0; i < krule->field_count; i++) {
 		rule->values[i] = krule->fields[i].val;
 		rule->fields[i] = krule->fields[i].type;
-
-		if (krule->vers_ops == 1) {
-			if (krule->fields[i].op == Audit_not_equal)
-				rule->fields[i] |= AUDIT_NEGATE;
-		} else {
-			rule->fields[i] |= audit_ops[krule->fields[i].op];
-		}
+		audit_op_translate(krule, rule, i);
 	}
-	for (i = 0; i < AUDIT_BITMASK_SIZE; i++) rule->mask[i] = krule->mask[i];
+	for (i = 0; i < krule->keyfield_count; i++) {
+		rule->values[i] = krule->keyfields[i].val;
+		rule->fields[i] = krule->keyfields[i].type;
+		audit_op_translate(krule, rule, i);
+	}
+
+	for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
+		rule->mask[i] = krule->mask[i];

 	return rule;
 }
@@ -600,7 +663,7 @@ static struct audit_rule_data
*audit_krule_to_data(struct audit_krule *krule)
 {
 	struct audit_rule_data *data;
 	void *bufp;
-	int i;
+	int i, j;

 	data = kmalloc(sizeof(*data) + krule->buflen, GFP_KERNEL);
 	if (unlikely(!data))
@@ -609,9 +672,9 @@ static struct audit_rule_data
*audit_krule_to_data(struct audit_krule *krule)

 	data->flags = krule->flags | krule->listnr;
 	data->action = krule->action;
-	data->field_count = krule->field_count;
+	data->field_count = krule->field_count + krule->keyfield_count;
 	bufp = data->buf;
-	for (i = 0; i < data->field_count; i++) {
+	for (i = 0; i < krule->field_count; i++) {
 		struct audit_field *f = &krule->fields[i];

 		data->fields[i] = f->type;
@@ -640,15 +703,20 @@ static struct audit_rule_data
*audit_krule_to_data(struct audit_krule *krule)
 				audit_pack_string(&bufp,
 						  audit_tree_path(krule->tree));
 			break;
-		case AUDIT_FILTERKEY:
-			data->buflen += data->values[i] =
-				audit_pack_string(&bufp, krule->filterkey);
-			break;
 		default:
 			data->values[i] = f->val;
 		}
 	}
-	for (i = 0; i < AUDIT_BITMASK_SIZE; i++) data->mask[i] = krule->mask[i];
+	j = i;
+	for (i = 0; i < krule->keyfield_count; i++, j++) {
+		struct audit_field *f = &krule->keyfields[i];
+
+		data->fields[j] = f->type;
+		data->fieldflags[j] = audit_ops[f->op];
+		data->buflen += data->values[j] = audit_pack_string(&bufp, f->lsm_str);
+	}
+	for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
+		data->mask[i] = krule->mask[i];

 	return data;
 }
@@ -662,7 +730,8 @@ static int audit_compare_rule(struct audit_krule
*a, struct audit_krule *b)
 	if (a->flags != b->flags ||
 	    a->listnr != b->listnr ||
 	    a->action != b->action ||
-	    a->field_count != b->field_count)
+	    a->field_count != b->field_count ||
+	    a->keyfield_count != b->keyfield_count)
 		return 1;

 	for (i = 0; i < a->field_count; i++) {
@@ -694,17 +763,17 @@ static int audit_compare_rule(struct audit_krule
*a, struct audit_krule *b)
 				   audit_tree_path(b->tree)))
 				return 1;
 			break;
-		case AUDIT_FILTERKEY:
-			/* both filterkeys exist based on above type compare */
-			if (strcmp(a->filterkey, b->filterkey))
-				return 1;
-			break;
 		default:
 			if (a->fields[i].val != b->fields[i].val)
 				return 1;
 		}
 	}
-
+	for (i = 0; i < a->keyfield_count; i++) {
+		if (a->keyfields[i].type != b->keyfields[i].type ||
+		    a->keyfields[i].op != b->keyfields[i].op ||
+		    strcmp(a->keyfields[i].lsm_str, b->keyfields[i].lsm_str))
+			return 1;
+	}
 	for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
 		if (a->mask[i] != b->mask[i])
 			return 1;
@@ -748,13 +817,13 @@ static inline int audit_dupe_lsm_field(struct
audit_field *df,
  * the initial copy. */
 struct audit_entry *audit_dupe_rule(struct audit_krule *old)
 {
-	u32 fcount = old->field_count;
+	u32 f_count = old->field_count;
+	u32 kf_count = old->keyfield_count;
 	struct audit_entry *entry;
 	struct audit_krule *new;
-	char *fk;
 	int i, err = 0;

-	entry = audit_init_entry(fcount);
+	entry = audit_init_entry(f_count, kf_count);
 	if (unlikely(!entry))
 		return ERR_PTR(-ENOMEM);

@@ -768,6 +837,7 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old)
 	new->prio = old->prio;
 	new->buflen = old->buflen;
 	new->inode_f = old->inode_f;
+	new->keyfield_count = old->keyfield_count;
 	new->field_count = old->field_count;

 	/*
@@ -778,11 +848,12 @@ struct audit_entry *audit_dupe_rule(struct
audit_krule *old)
 	 * the beginning of list scan.
 	 */
 	new->tree = old->tree;
-	memcpy(new->fields, old->fields, sizeof(struct audit_field) * fcount);
+	memcpy(new->keyfields, old->keyfields, sizeof(struct audit_field) * kf_count);
+	memcpy(new->fields, old->fields, sizeof(struct audit_field) * f_count);

 	/* deep copy this information, updating the lsm_rule fields, because
 	 * the originals will all be freed when the old rule is freed. */
-	for (i = 0; i < fcount; i++) {
+	for (i = 0; i < f_count; i++) {
 		switch (new->fields[i].type) {
 		case AUDIT_SUBJ_USER:
 		case AUDIT_SUBJ_ROLE:
@@ -797,19 +868,21 @@ struct audit_entry *audit_dupe_rule(struct
audit_krule *old)
 			err = audit_dupe_lsm_field(&new->fields[i],
 						       &old->fields[i]);
 			break;
-		case AUDIT_FILTERKEY:
-			fk = kstrdup(old->filterkey, GFP_KERNEL);
-			if (unlikely(!fk))
-				err = -ENOMEM;
-			else
-				new->filterkey = fk;
 		}
 		if (err) {
 			audit_free_rule(entry);
 			return ERR_PTR(err);
 		}
 	}
+	for (i = 0; i < kf_count; i++) {
+		err = audit_dupe_lsm_field(&new->keyfields[i],
+					       &old->keyfields[i]);

+		if (err) {
+			audit_free_rule(entry);
+			return ERR_PTR(err);
+		}
+	}
 	if (old->watch) {
 		audit_get_watch(old->watch);
 		new->watch = old->watch;
@@ -1053,6 +1126,7 @@ static void audit_log_rule_change(uid_t
loginuid, u32 sessionid, u32 sid,
 				  int res)
 {
 	struct audit_buffer *ab;
+	int i;

 	if (!audit_enabled)
 		return;
@@ -1073,7 +1147,8 @@ static void audit_log_rule_change(uid_t
loginuid, u32 sessionid, u32 sid,
 	}
 	audit_log_format(ab, " op=");
 	audit_log_string(ab, action);
-	audit_log_key(ab, rule->filterkey);
+	for (i = 0; i < rule->keyfield_count; i++)
+		audit_log_key(ab, rule->keyfields[i].type, rule->keyfields[i].lsm_str);
 	audit_log_format(ab, " list=%d res=%d", rule->listnr, res);
 	audit_log_end(ab);
 }
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index f286982..1760dcd 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -161,6 +161,11 @@ struct audit_tree_refs {
 	struct audit_chunk *c[31];
 };

+struct audit_keys {
+	int type;
+	char *key;
+};
+
 /* The per-task audit context. */
 struct audit_context {
 	int		    dummy;	/* must be the first element */
@@ -175,7 +180,8 @@ struct audit_context {
 	int		    return_valid; /* return code is valid */
 	int		    name_count;
 	struct audit_names  names[AUDIT_NAMES];
-	char *		    filterkey;	/* key for rule that triggered record */
+	int		    key_count;
+	struct audit_keys   keys[AUDIT_MAX_KEYS];
 	struct path	    pwd;
 	struct audit_context *previous; /* For nested syscalls */
 	struct audit_aux_data *aux;
@@ -641,9 +647,14 @@ static int audit_filter_rules(struct task_struct *tsk,
 	if (ctx) {
 		if (rule->prio <= ctx->prio)
 			return 0;
-		if (rule->filterkey) {
-			kfree(ctx->filterkey);
-			ctx->filterkey = kstrdup(rule->filterkey, GFP_ATOMIC);
+		ctx->key_count = rule->keyfield_count;
+		for (i = 0; i < ctx->key_count; i++) {
+			ctx->keys[i].type = rule->keyfields[i].type;
+			if (rule->keyfields[i].lsm_str) {
+				if (ctx->keys[i].key)
+					kfree(ctx->keys[i].key);
+			}
+			ctx->keys[i].key = kstrdup(rule->keyfields[i].lsm_str, GFP_ATOMIC);
 		}
 		ctx->prio = rule->prio;
 	}
@@ -659,16 +670,24 @@ static int audit_filter_rules(struct task_struct *tsk,
  * completely disabled for this task.  Since we only have the task
  * structure at this point, we can only check uid and gid.
  */
-static enum audit_state audit_filter_task(struct task_struct *tsk, char **key)
+static enum audit_state audit_filter_task(struct task_struct *tsk,
struct audit_keys *k, int *count)
 {
 	struct audit_entry *e;
 	enum audit_state   state;
+	int i, key_count;

 	rcu_read_lock();
 	list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_TASK], list) {
 		if (audit_filter_rules(tsk, &e->rule, NULL, NULL, &state)) {
-			if (state == AUDIT_RECORD_CONTEXT)
-				*key = kstrdup(e->rule.filterkey, GFP_ATOMIC);
+			if (state == AUDIT_RECORD_CONTEXT) {
+				key_count = e->rule.keyfield_count;
+
+				for (i = 0; key_count; i++) {
+					k[i].type = e->rule.keyfields[i].type;
+					k[i].key = kstrdup(e->rule.keyfields[i].lsm_str, GFP_ATOMIC);
+				}
+				*count = key_count;
+			}
 			rcu_read_unlock();
 			return state;
 		}
@@ -822,6 +841,16 @@ static inline void audit_free_names(struct
audit_context *context)
 	context->pwd.mnt = NULL;
 }

+static inline void audit_free_keys(struct audit_context *context)
+{
+	int i;
+
+	for (i = 0; i < context->key_count; i++) {
+		kfree(context->keys[i].key);
+		context->keys[i].key = NULL;
+	}
+}
+
 static inline void audit_free_aux(struct audit_context *context)
 {
 	struct audit_aux_data *aux;
@@ -868,21 +897,29 @@ int audit_alloc(struct task_struct *tsk)
 {
 	struct audit_context *context;
 	enum audit_state     state;
-	char *key = NULL;
+	struct audit_keys keys[AUDIT_MAX_KEYS];
+	int i, key_count = 0;
+
+	memset(&keys, 0, AUDIT_MAX_KEYS * sizeof(struct audit_keys));

 	if (likely(!audit_ever_enabled))
 		return 0; /* Return if not auditing. */

-	state = audit_filter_task(tsk, &key);
+	state = audit_filter_task(tsk, keys, &key_count);
 	if (likely(state == AUDIT_DISABLED))
 		return 0;

 	if (!(context = audit_alloc_context(state))) {
-		kfree(key);
+		for (i = 0; i < key_count; i++)
+			kfree(keys[i].key);
 		audit_log_lost("out of memory in audit_alloc");
 		return -ENOMEM;
 	}
-	context->filterkey = key;
+	context->key_count = key_count;
+	for (i = 0; i < key_count; i++) {
+		context->keys[i].type = keys[i].type;
+		context->keys[i].key = keys[i].key;
+	}

 	tsk->audit_context  = context;
 	set_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
@@ -907,7 +944,7 @@ static inline void audit_free_context(struct
audit_context *context)
 		unroll_tree_refs(context, NULL, 0);
 		free_tree_refs(context);
 		audit_free_aux(context);
-		kfree(context->filterkey);
+		audit_free_keys(context);
 		kfree(context->sockaddr);
 		kfree(context);
 		context  = previous;
@@ -1369,9 +1406,12 @@ static void audit_log_exit(struct audit_context
*context, struct task_struct *ts
 		  context->egid, context->sgid, context->fsgid, tty,
 		  tsk->sessionid);

-
 	audit_log_task_info(ab, tsk);
-	audit_log_key(ab, context->filterkey);
+
+	for (i = 0; i < context->key_count; i++)
+		audit_log_key(ab, context->keys[i].type, context->keys[i].key);
+	if (!i)
+		audit_log_key(ab, 0, NULL);
 	audit_log_end(ab);

 	for (aux = context->aux; aux; aux = aux->next) {
@@ -1646,6 +1686,8 @@ void audit_finish_fork(struct task_struct *child)
 {
 	struct audit_context *ctx = current->audit_context;
 	struct audit_context *p = child->audit_context;
+	int i;
+
 	if (!p || !ctx)
 		return;
 	if (!ctx->in_syscall || ctx->current_state != AUDIT_RECORD_CONTEXT)
@@ -1656,7 +1698,10 @@ void audit_finish_fork(struct task_struct *child)
 	p->ctime = ctx->ctime;
 	p->dummy = ctx->dummy;
 	p->in_syscall = ctx->in_syscall;
-	p->filterkey = kstrdup(ctx->filterkey, GFP_KERNEL);
+	for (i = 0; i < ctx->key_count; i++) {
+		p->keys[i].type = ctx->keys[i].type;
+		p->keys[i].key = kstrdup(ctx->keys[i].key, GFP_KERNEL);
+	}
 	p->ppid = current->pid;
 	p->prio = ctx->prio;
 	p->current_state = ctx->current_state;
@@ -1708,10 +1753,8 @@ void audit_syscall_exit(int valid, long return_code)
 		context->sockaddr_len = 0;
 		context->type = 0;
 		context->fds[0] = -1;
-		if (context->state != AUDIT_RECORD_CONTEXT) {
-			kfree(context->filterkey);
-			context->filterkey = NULL;
-		}
+		if (context->state != AUDIT_RECORD_CONTEXT)
+			audit_free_keys(context);
 		tsk->audit_context = context;
 	}
 }
-- 
1.6.4.4





User space audit patch:

Index: src/auditctl.c
===================================================================
--- src/auditctl.c	(revision 392)
+++ src/auditctl.c	(working copy)
@@ -73,6 +73,7 @@
 /* External vars */
 extern int audit_archadded;
 extern int audit_syscalladded;
+extern int audit_keyadded;
 extern unsigned int audit_elf;
 extern int audit_permadded;

@@ -84,6 +85,7 @@
 {
 	list_requested = 0;
 	audit_syscalladded = 0;
+	audit_keyadded = 0;
 	audit_permadded = 0;
 	audit_archadded = 0;
 	audit_elf = 0;
@@ -818,6 +820,9 @@
 							AUDIT_MAX_KEY_LEN) {
 			fprintf(stderr, "key option exceeds size limit\n");
 			retval = -1;
+		} else if (audit_keyadded >= AUDIT_MAX_KEYS) {
+			fprintf(stderr, "too many kyes (ctl)\n");
+			retval = -1;
 		} else {
 			if (strncmp(optarg, "ids-", 4) == 0) {
 				if (check_ids_key(optarg)) {
@@ -834,6 +839,7 @@
 			}
 			strncat(key, optarg, keylen);
 			keylen = AUDIT_MAX_KEY_LEN - strlen(key);
+			audit_keyadded++;
 		}
 		break;
 	case 'p':
Index: lib/libaudit.h
===================================================================
--- lib/libaudit.h	(revision 392)
+++ lib/libaudit.h	(working copy)
@@ -203,6 +203,9 @@
 /* This is related to the filterkey patch */
 #define AUDIT_KEY_SEPARATOR 0x01

+/* Max number of audit keys */
+#define AUDIT_MAX_KEYS		8
+
 /* These are used in filter control */
 #define AUDIT_FILTER_EXCLUDE	AUDIT_FILTER_TYPE
 #define AUDIT_FILTER_MASK	0x07	/* Mask to get actual filter */
Index: lib/errormsg.h
===================================================================
--- lib/errormsg.h	(revision 392)
+++ lib/errormsg.h	(working copy)
@@ -54,5 +54,6 @@
     { -19,    0,    "Key field needs a watch or syscall given prior to it" },
     { -20,    2,    "-F missing value after operation for" },
     { -21,    2,    "-F value should be number for" },
-    { -22,    2,    "-F missing field name before operator for" }
+    { -22,    2,    "-F missing field name before operator for" },
+    { -23,    2,    "too many keys" }
 };
Index: lib/libaudit.c
===================================================================
--- lib/libaudit.c	(revision 392)
+++ lib/libaudit.c	(working copy)
@@ -80,6 +80,7 @@
 int audit_permadded hidden = 0;
 int audit_archadded hidden = 0;
 int audit_syscalladded hidden = 0;
+int audit_keyadded hidden = 0;
 unsigned int audit_elf hidden = 0U;
 static struct libaudit_conf config;

@@ -943,14 +944,18 @@
 		case AUDIT_SUBJ_SEN:
 		case AUDIT_SUBJ_CLR:
 		case AUDIT_FILTERKEY:
-			if (field == AUDIT_FILTERKEY && !(audit_syscalladded || audit_permadded))
-                                return -19;
 			vlen = strlen(v);
-			if (field == AUDIT_FILTERKEY &&
-					vlen > AUDIT_MAX_KEY_LEN)
+			if (field == AUDIT_FILTERKEY) {
+				if (!(audit_syscalladded || audit_permadded))
+	                                return -19;
+				else if (vlen > AUDIT_MAX_KEY_LEN)
+					return -11;
+				else if (audit_keyadded >= AUDIT_MAX_KEYS)
+					return -23;
+				audit_keyadded++;
+			} else if (vlen > PATH_MAX) {
 				return -11;
-			else if (vlen > PATH_MAX)
-				return -11;
+			}
 			rule->values[rule->field_count] = vlen;
 			offset = rule->buflen;
 			rule->buflen += vlen;
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ