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;