diff --git a/include/linux/audit.h b/include/linux/audit.h index 739b954cb24283a0b41ac1bc18f2f0391da20654..8fa1a8fbc04d49e601d6237437d26df17a733429 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -92,8 +92,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 */ +#define AUDIT_FILTER_TYPE 0x05 /* Apply rule at audit_log_start */ -#define AUDIT_NR_FILTERS 5 +#define AUDIT_NR_FILTERS 6 #define AUDIT_FILTER_PREPEND 0x10 /* Prepend to front of list */ @@ -132,6 +133,7 @@ #define AUDIT_LOGINUID 9 #define AUDIT_PERS 10 #define AUDIT_ARCH 11 +#define AUDIT_MSGTYPE 12 /* These are ONLY useful when checking * at syscall exit time (AUDIT_AT_EXIT). */ @@ -289,6 +291,7 @@ extern int audit_sockaddr(int len, void *addr); extern int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt); 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_filter_type(int type); #else #define audit_alloc(t) ({ 0; }) #define audit_free(t) do { ; } while (0) diff --git a/kernel/audit.c b/kernel/audit.c index 6d61dd79a605a008c67db393b333acf1a77c4b2e..1c3eb1b12bfc873d5bb743762aa777d7d4d0c21b 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -702,6 +702,9 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, if (!audit_initialized) return NULL; + if (unlikely(audit_filter_type(type))) + return NULL; + if (gfp_mask & __GFP_WAIT) reserve = 0; else diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 73f932b7deb69d64b1d00529a7d23c9e4ce5ff9d..31917ac730aff2603ecaf1b4376d241d726fdccd 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -187,7 +187,8 @@ static struct list_head audit_filter_list[AUDIT_NR_FILTERS] = { LIST_HEAD_INIT(audit_filter_list[2]), LIST_HEAD_INIT(audit_filter_list[3]), LIST_HEAD_INIT(audit_filter_list[4]), -#if AUDIT_NR_FILTERS != 5 + LIST_HEAD_INIT(audit_filter_list[5]), +#if AUDIT_NR_FILTERS != 6 #error Fix audit_filter_list initialiser #endif }; @@ -663,6 +664,38 @@ int audit_filter_user(struct netlink_skb_parms *cb, int type) return ret; /* Audit by default */ } +int audit_filter_type(int type) +{ + struct audit_entry *e; + int result = 0; + + rcu_read_lock(); + if (list_empty(&audit_filter_list[AUDIT_FILTER_TYPE])) + goto unlock_and_return; + + list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_TYPE], + list) { + struct audit_rule *rule = &e->rule; + int i; + for (i = 0; i < rule->field_count; i++) { + u32 field = rule->fields[i] & ~AUDIT_OPERATORS; + u32 op = rule->fields[i] & AUDIT_OPERATORS; + u32 value = rule->values[i]; + if ( field == AUDIT_MSGTYPE ) { + result = audit_comparator(type, op, value); + if (!result) + break; + } + } + if (result) + goto unlock_and_return; + } +unlock_and_return: + rcu_read_unlock(); + return result; +} + + /* This should be called with task_lock() held. */ static inline struct audit_context *audit_get_context(struct task_struct *tsk, int return_valid,