From: Juraj Hlista <[email protected]>

Add support for reactive rules. An audit rule can contain more than one 
reaction. The reactions are identified by numbers in the kernel and by strings 
in the user space.

Signed-off-by: Juraj Hlista <[email protected]>
---
 include/linux/audit.h |    9 ++++++++
 kernel/audit.c        |    8 +++++++
 kernel/audit_tree.c   |    1 +
 kernel/audit_watch.c  |    1 +
 kernel/auditfilter.c  |   52 ++++++++++++++++++++++++++++++++++++++++++------
 kernel/auditsc.c      |   23 +++++++++++++++++++++
 6 files changed, 87 insertions(+), 7 deletions(-)

diff --git a/include/linux/audit.h b/include/linux/audit.h
index f391d45..0325516 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -102,6 +102,7 @@
 #define AUDIT_EOE              1320    /* End of multi-record event */
 #define AUDIT_BPRM_FCAPS       1321    /* Information about fcaps increasing 
perms */
 #define AUDIT_CAPSET           1322    /* Record showing argument to 
sys_capset */
+#define AUDIT_REACT_RULE       1323    /* Reactive rule */
 
 #define AUDIT_AVC              1400    /* SE Linux avc denial or grant */
 #define AUDIT_SELINUX_ERR      1401    /* Internal SE Linux Errors */
@@ -156,6 +157,7 @@
  * AUDIT_LIST commands must be implemented. */
 #define AUDIT_MAX_FIELDS   64
 #define AUDIT_MAX_KEY_LEN  256
+#define AUDIT_MAX_REACTS   8
 #define AUDIT_BITMASK_SIZE 64
 #define AUDIT_WORD(nr) ((__u32)((nr)/32))
 #define AUDIT_BIT(nr)  (1 << ((nr) - AUDIT_WORD(nr)*32))
@@ -227,6 +229,8 @@
 
 #define AUDIT_FILTERKEY        210
 
+#define AUDIT_REACTION 220
+
 #define AUDIT_NEGATE                   0x80000000
 
 /* These are the supported operators.
@@ -384,6 +388,8 @@ struct audit_krule {
        u32                     action;
        u32                     mask[AUDIT_BITMASK_SIZE];
        u32                     buflen; /* for data alloc on list rules */
+       u32                     react_count;
+       u32                     react[AUDIT_MAX_REACTS];
        u32                     field_count;
        char                    *filterkey; /* ties events to rules */
        struct audit_field      *fields;
@@ -600,6 +606,8 @@ extern void             audit_log_d_path(struct 
audit_buffer *ab,
                                             struct path *path);
 extern void                audit_log_key(struct audit_buffer *ab,
                                          char *key);
+extern void                audit_log_react(struct audit_buffer *ab,
+                                           u32 count, u32 *react);
 extern void                audit_log_lost(const char *message);
 extern int                 audit_update_lsm_rules(void);
 
@@ -623,6 +631,7 @@ extern int audit_enabled;
 #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_react(b, c, r) do { ; } while (0)
 #define audit_enabled 0
 #endif
 #endif
diff --git a/kernel/audit.c b/kernel/audit.c
index 05a32f0..6f4fd3b 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1450,6 +1450,14 @@ void audit_log_key(struct audit_buffer *ab, char *key)
                audit_log_format(ab, "(null)");
 }
 
+void audit_log_react(struct audit_buffer *ab, u32 count, u32 *react)
+{
+       unsigned int i;
+       for (i = 0; i < count; i++)
+               audit_log_format(ab, " react=%u", react[i]);
+
+}
+
 /**
  * audit_log_end - end one audit record
  * @ab: the audit_buffer
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
index 28e5b20..b63faa5 100644
--- a/kernel/audit_tree.c
+++ b/kernel/audit_tree.c
@@ -468,6 +468,7 @@ static void kill_rules(struct audit_tree *tree)
                        audit_log_format(ab, " dir=");
                        audit_log_untrustedstring(ab, rule->tree->pathname);
                        audit_log_key(ab, rule->filterkey);
+                       audit_log_react(ab, rule->react_count, rule->react);
                        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 7499397..565fbad 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -249,6 +249,7 @@ static void audit_watch_log_rule_change(struct audit_krule 
*r, struct audit_watc
                audit_log_format(ab, " path=");
                audit_log_untrustedstring(ab, w->path);
                audit_log_key(ab, r->filterkey);
+               audit_log_react(ab, r->react_count, r->react);
                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 eb76754..f0eb220 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -229,6 +229,7 @@ static inline struct audit_entry 
*audit_to_entry_common(struct audit_rule *rule)
        unsigned listnr;
        struct audit_entry *entry;
        int i, err;
+       int r_count = 0;
 
        err = -EINVAL;
        listnr = rule->flags & ~AUDIT_FILTER_PREPEND;
@@ -253,15 +254,23 @@ 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_REACTION)
+                       ++r_count;
+               if (unlikely(r_count > AUDIT_MAX_REACTS))
+                       goto exit_err;
+       }
+
        err = -ENOMEM;
-       entry = audit_init_entry(rule->field_count);
+       entry = audit_init_entry(rule->field_count - r_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 - r_count;
+       entry->rule.react_count = r_count;
 
        for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
                entry->rule.mask[i] = rule->mask[i];
@@ -415,7 +424,8 @@ static struct audit_entry *audit_data_to_entry(struct 
audit_rule_data *data,
        struct audit_entry *entry;
        void *bufp;
        size_t remain = datasz - sizeof(struct audit_rule_data);
-       int i;
+       int i, j = 0;
+       int k;
        char *str;
 
        entry = audit_to_entry_common((struct audit_rule *)data);
@@ -425,7 +435,7 @@ 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 = &entry->rule.fields[i - j];
 
                err = -EINVAL;
 
@@ -433,6 +443,18 @@ static struct audit_entry *audit_data_to_entry(struct 
audit_rule_data *data,
                if (f->op == Audit_bad)
                        goto exit_free;
 
+               if (data->fields[i] == AUDIT_REACTION) {
+                       for (k = 0; k < j; k++) {
+                               /* reactions must differ */
+                               if (entry->rule.react[k] == data->values[i])
+                                       goto exit_free;
+                       }
+                       entry->rule.react[j] = data->values[i];
+                       ++j;
+                       entry->rule.react_count = j;
+                       continue;
+               }
+
                f->type = data->fields[i];
                f->val = data->values[i];
                f->lsm_str = NULL;
@@ -601,7 +623,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))
@@ -610,9 +632,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->react_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;
@@ -649,6 +671,13 @@ static struct audit_rule_data *audit_krule_to_data(struct 
audit_krule *krule)
                        data->values[i] = f->val;
                }
        }
+       j = i;
+       for (i = 0; i < krule->react_count; i++, j++) {
+               data->fields[j] = AUDIT_REACTION;
+               data->fieldflags[j] = AUDIT_EQUAL;
+               data->values[j] = krule->react[i];
+       }
+
        for (i = 0; i < AUDIT_BITMASK_SIZE; i++) data->mask[i] = krule->mask[i];
 
        return data;
@@ -663,6 +692,7 @@ 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->react_count != b->react_count ||
            a->field_count != b->field_count)
                return 1;
 
@@ -705,6 +735,10 @@ static int audit_compare_rule(struct audit_krule *a, 
struct audit_krule *b)
                                return 1;
                }
        }
+       for (i = 0; i < a->react_count; i++) {
+               if (a->react[i] != b->react[i])
+                       return 1;
+       }
 
        for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
                if (a->mask[i] != b->mask[i])
@@ -769,6 +803,9 @@ 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->react_count = old->react_count;
+       for (i = 0; i < new->react_count; i++)
+               new->react[i] = old->react[i];
        new->field_count = old->field_count;
 
        /*
@@ -1075,6 +1112,7 @@ 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);
+       audit_log_react(ab, rule->react_count, rule->react);
        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 bc2b57a..57ad669 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -176,6 +176,8 @@ struct audit_context {
        int                 return_valid; /* return code is valid */
        int                 name_count;
        struct audit_names  names[AUDIT_NAMES];
+       int                 react_count;
+       u32                 react[AUDIT_MAX_REACTS];
        char *              filterkey;  /* key for rule that triggered record */
        struct path         pwd;
        struct audit_context *previous; /* For nested syscalls */
@@ -622,6 +624,7 @@ static int audit_filter_rules(struct task_struct *tsk,
                                result = 
audit_comparator(ctx->argv[f->type-AUDIT_ARG0], f->op, f->val);
                        break;
                case AUDIT_FILTERKEY:
+               case AUDIT_REACTION:
                        /* ignore this field for filtering */
                        result = 1;
                        break;
@@ -642,6 +645,9 @@ static int audit_filter_rules(struct task_struct *tsk,
        if (ctx) {
                if (rule->prio <= ctx->prio)
                        return 0;
+               ctx->react_count = rule->react_count;
+               for (i = 0; i < ctx->react_count; i++)
+                       ctx->react[i] = rule->react[i];
                if (rule->filterkey) {
                        kfree(ctx->filterkey);
                        ctx->filterkey = kstrdup(rule->filterkey, GFP_ATOMIC);
@@ -1332,6 +1338,19 @@ static void audit_log_exit(struct audit_context 
*context, struct task_struct *ts
        context->fsgid = cred->fsgid;
        context->personality = tsk->personality;
 
+       if (context->react_count) {
+               ab = audit_log_start(context, GFP_KERNEL, AUDIT_REACT_RULE);
+               if (!ab)
+                       return;
+               for (i = 0; i < context->react_count; i++) {
+                       if (!i)
+                               audit_log_format(ab, "react=%u", 
context->react[i]);
+                       else
+                               audit_log_format(ab, " react=%u", 
context->react[i]);
+               }
+               audit_log_end(ab);
+       }
+
        ab = audit_log_start(context, GFP_KERNEL, AUDIT_SYSCALL);
        if (!ab)
                return;         /* audit_panic has been called */
@@ -1645,6 +1664,7 @@ void audit_syscall_entry(int arch, int major,
 
 void audit_finish_fork(struct task_struct *child)
 {
+       int i;
        struct audit_context *ctx = current->audit_context;
        struct audit_context *p = child->audit_context;
        if (!p || !ctx)
@@ -1658,6 +1678,9 @@ void audit_finish_fork(struct task_struct *child)
        p->dummy = ctx->dummy;
        p->in_syscall = ctx->in_syscall;
        p->filterkey = kstrdup(ctx->filterkey, GFP_KERNEL);
+       p->react_count = ctx->react_count;
+       for (i = 0; i < p->react_count; i++)
+               p->react[i] = ctx->react[i];
        p->ppid = current->pid;
        p->prio = ctx->prio;
        p->current_state = ctx->current_state;
-- 
1.6.4.4

--
Linux-audit mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/linux-audit

Reply via email to