Merge tag 'audit-pr-20171113' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoor...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 15 Nov 2017 21:28:48 +0000 (13:28 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 15 Nov 2017 21:28:48 +0000 (13:28 -0800)
Pull audit updates from Paul Moore:
 "Another relatively small pull request for audit, nine patches total.

  The only real new bit of functionality is the patch from Richard which
  adds the ability to filter records based on the filesystem type.

  The remainder are bug fixes and cleanups; the bug fix highlights
  include:

   - ensuring that we properly audit init/PID-1 (me)

   - allowing the audit daemon to shutdown the kernel/auditd connection
     cleanly by setting the audit PID to zero (Steve)"

* tag 'audit-pr-20171113' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit:
  audit: filter PATH records keyed on filesystem magic
  Audit: remove unused audit_log_secctx function
  audit: Allow auditd to set pid to 0 to end auditing
  audit: Add new syscalls to the perm=w filter
  audit: use audit_set_enabled() in audit_enable()
  audit: convert audit_ever_enabled to a boolean
  audit: don't use simple_strtol() anymore
  audit: initialize the audit subsystem as early as possible
  audit: ensure that 'audit=1' actually enables audit for PID 1

include/asm-generic/audit_dir_write.h
include/asm-generic/audit_write.h
include/linux/audit.h
include/uapi/linux/audit.h
kernel/audit.c
kernel/audit.h
kernel/auditfilter.c
kernel/auditsc.c

index 8fb83b43006ac7953468e62d6565cb0ef7b27a95..da09fb986459ef9c68e35eb5833025992984c357 100644 (file)
@@ -31,3 +31,6 @@ __NR_renameat,
 __NR_linkat,
 __NR_symlinkat,
 #endif
+#ifdef __NR_renameat2
+__NR_renameat2,
+#endif
index dfc52b3c103f5c79e3d658d3f67e01db2222d558..f9f1d0ae11d9cb31ad33bf0d8f6ae21407da9bb8 100644 (file)
@@ -20,3 +20,6 @@ __NR_ftruncate64,
 #ifdef __NR_bind
 __NR_bind,             /* bind can affect fs object only in one way... */
 #endif
+#ifdef __NR_fallocate
+__NR_fallocate,
+#endif
index d66220dac3648602899423454095fadaff4f2e1e..af410d9fbf2da9f904bac6e8309c2b097142fea9 100644 (file)
@@ -149,12 +149,6 @@ extern void                    audit_log_key(struct audit_buffer *ab,
 extern void                audit_log_link_denied(const char *operation,
                                                  const struct path *link);
 extern void                audit_log_lost(const char *message);
-#ifdef CONFIG_SECURITY
-extern void                audit_log_secctx(struct audit_buffer *ab, u32 secid);
-#else
-static inline void         audit_log_secctx(struct audit_buffer *ab, u32 secid)
-{ }
-#endif
 
 extern int audit_log_task_context(struct audit_buffer *ab);
 extern void audit_log_task_info(struct audit_buffer *ab,
@@ -203,8 +197,6 @@ static inline void audit_log_key(struct audit_buffer *ab, char *key)
 static inline void audit_log_link_denied(const char *string,
                                         const struct path *link)
 { }
-static inline void audit_log_secctx(struct audit_buffer *ab, u32 secid)
-{ }
 static inline int audit_log_task_context(struct audit_buffer *ab)
 {
        return 0;
index 626e76d109b9481aa3f79a67d99a673da62f364e..4e61a9e051325e1bf7a679af0d55ce73bfd652c8 100644 (file)
 #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_FILTER_FS                0x06    /* Apply rule at __audit_inode_child */
 
-#define AUDIT_NR_FILTERS       6
+#define AUDIT_NR_FILTERS       7
 
 #define AUDIT_FILTER_PREPEND   0x10    /* Prepend to front of list */
 
 #define AUDIT_OBJ_LEV_HIGH     23
 #define AUDIT_LOGINUID_SET     24
 #define AUDIT_SESSIONID        25      /* Session ID */
+#define AUDIT_FSTYPE   26      /* FileSystem Type */
 
                                /* These are ONLY useful when checking
                                 * at syscall exit time (AUDIT_AT_EXIT). */
@@ -337,13 +339,15 @@ enum {
 #define AUDIT_FEATURE_BITMAP_EXCLUDE_EXTEND    0x00000008
 #define AUDIT_FEATURE_BITMAP_SESSIONID_FILTER  0x00000010
 #define AUDIT_FEATURE_BITMAP_LOST_RESET                0x00000020
+#define AUDIT_FEATURE_BITMAP_FILTER_FS         0x00000040
 
 #define AUDIT_FEATURE_BITMAP_ALL (AUDIT_FEATURE_BITMAP_BACKLOG_LIMIT | \
                                  AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME | \
                                  AUDIT_FEATURE_BITMAP_EXECUTABLE_PATH | \
                                  AUDIT_FEATURE_BITMAP_EXCLUDE_EXTEND | \
                                  AUDIT_FEATURE_BITMAP_SESSIONID_FILTER | \
-                                 AUDIT_FEATURE_BITMAP_LOST_RESET)
+                                 AUDIT_FEATURE_BITMAP_LOST_RESET | \
+                                 AUDIT_FEATURE_BITMAP_FILTER_FS)
 
 /* deprecated: AUDIT_VERSION_* */
 #define AUDIT_VERSION_LATEST           AUDIT_FEATURE_BITMAP_ALL
index be1c28fd4d575d824606f10860f766fc09f8a0c1..227db99b0f19a8f4797c424fa2957741bccf1ce5 100644 (file)
@@ -85,13 +85,13 @@ static int  audit_initialized;
 #define AUDIT_OFF      0
 #define AUDIT_ON       1
 #define AUDIT_LOCKED   2
-u32            audit_enabled;
-u32            audit_ever_enabled;
+u32            audit_enabled = AUDIT_OFF;
+bool           audit_ever_enabled = !!AUDIT_OFF;
 
 EXPORT_SYMBOL_GPL(audit_enabled);
 
 /* Default state when kernel boots without any parameters. */
-static u32     audit_default;
+static u32     audit_default = AUDIT_OFF;
 
 /* If auditing cannot proceed, audit_failure selects what happens. */
 static u32     audit_failure = AUDIT_FAIL_PRINTK;
@@ -1197,25 +1197,28 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                        pid_t auditd_pid;
                        struct pid *req_pid = task_tgid(current);
 
-                       /* sanity check - PID values must match */
-                       if (new_pid != pid_vnr(req_pid))
+                       /* Sanity check - PID values must match. Setting
+                        * pid to 0 is how auditd ends auditing. */
+                       if (new_pid && (new_pid != pid_vnr(req_pid)))
                                return -EINVAL;
 
                        /* test the auditd connection */
                        audit_replace(req_pid);
 
                        auditd_pid = auditd_pid_vnr();
-                       /* only the current auditd can unregister itself */
-                       if ((!new_pid) && (new_pid != auditd_pid)) {
-                               audit_log_config_change("audit_pid", new_pid,
-                                                       auditd_pid, 0);
-                               return -EACCES;
-                       }
-                       /* replacing a healthy auditd is not allowed */
-                       if (auditd_pid && new_pid) {
-                               audit_log_config_change("audit_pid", new_pid,
-                                                       auditd_pid, 0);
-                               return -EEXIST;
+                       if (auditd_pid) {
+                               /* replacing a healthy auditd is not allowed */
+                               if (new_pid) {
+                                       audit_log_config_change("audit_pid",
+                                                       new_pid, auditd_pid, 0);
+                                       return -EEXIST;
+                               }
+                               /* only current auditd can unregister itself */
+                               if (pid_vnr(req_pid) != auditd_pid) {
+                                       audit_log_config_change("audit_pid",
+                                                       new_pid, auditd_pid, 0);
+                                       return -EACCES;
+                               }
                        }
 
                        if (new_pid) {
@@ -1549,8 +1552,6 @@ static int __init audit_init(void)
        register_pernet_subsys(&audit_net_ops);
 
        audit_initialized = AUDIT_INITIALIZED;
-       audit_enabled = audit_default;
-       audit_ever_enabled |= !!audit_default;
 
        kauditd_task = kthread_run(kauditd_thread, NULL, "kauditd");
        if (IS_ERR(kauditd_task)) {
@@ -1564,14 +1565,21 @@ static int __init audit_init(void)
 
        return 0;
 }
-__initcall(audit_init);
+postcore_initcall(audit_init);
 
 /* Process kernel command-line parameter at boot time.  audit=0 or audit=1. */
 static int __init audit_enable(char *str)
 {
-       audit_default = !!simple_strtol(str, NULL, 0);
-       if (!audit_default)
+       long val;
+
+       if (kstrtol(str, 0, &val))
+               panic("audit: invalid 'audit' parameter value (%s)\n", str);
+       audit_default = (val ? AUDIT_ON : AUDIT_OFF);
+
+       if (audit_default == AUDIT_OFF)
                audit_initialized = AUDIT_DISABLED;
+       if (audit_set_enabled(audit_default))
+               panic("audit: error setting audit state (%d)\n", audit_default);
 
        pr_info("%s\n", audit_default ?
                "enabled (after initialization)" : "disabled (until reboot)");
@@ -2337,32 +2345,6 @@ void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type,
        }
 }
 
-#ifdef CONFIG_SECURITY
-/**
- * audit_log_secctx - Converts and logs SELinux context
- * @ab: audit_buffer
- * @secid: security number
- *
- * This is a helper function that calls security_secid_to_secctx to convert
- * secid to secctx and then adds the (converted) SELinux context to the audit
- * log by calling audit_log_format, thus also preventing leak of internal secid
- * to userspace. If secid cannot be converted audit_panic is called.
- */
-void audit_log_secctx(struct audit_buffer *ab, u32 secid)
-{
-       u32 len;
-       char *secctx;
-
-       if (security_secid_to_secctx(secid, &secctx, &len)) {
-               audit_panic("Cannot convert secid to context");
-       } else {
-               audit_log_format(ab, " obj=%s", secctx);
-               security_release_secctx(secctx, len);
-       }
-}
-EXPORT_SYMBOL(audit_log_secctx);
-#endif
-
 EXPORT_SYMBOL(audit_log_start);
 EXPORT_SYMBOL(audit_log_end);
 EXPORT_SYMBOL(audit_log_format);
index 9b110ae17ee3fe744592fdb1127d1dc868577af2..af5bc59487ed690bacb9b2ff1ed9c3a58d6994c7 100644 (file)
@@ -208,7 +208,7 @@ struct audit_context {
        struct audit_proctitle proctitle;
 };
 
-extern u32 audit_ever_enabled;
+extern bool audit_ever_enabled;
 
 extern void audit_copy_inode(struct audit_names *name,
                             const struct dentry *dentry,
index 0b0aa5854dac1ed41959f9383af95d4097ad4646..4a1758adb22249fcdc11ffba75263367ccde8936 100644 (file)
@@ -56,7 +56,8 @@ struct list_head audit_filter_list[AUDIT_NR_FILTERS] = {
        LIST_HEAD_INIT(audit_filter_list[3]),
        LIST_HEAD_INIT(audit_filter_list[4]),
        LIST_HEAD_INIT(audit_filter_list[5]),
-#if AUDIT_NR_FILTERS != 6
+       LIST_HEAD_INIT(audit_filter_list[6]),
+#if AUDIT_NR_FILTERS != 7
 #error Fix audit_filter_list initialiser
 #endif
 };
@@ -67,6 +68,7 @@ static struct list_head audit_rules_list[AUDIT_NR_FILTERS] = {
        LIST_HEAD_INIT(audit_rules_list[3]),
        LIST_HEAD_INIT(audit_rules_list[4]),
        LIST_HEAD_INIT(audit_rules_list[5]),
+       LIST_HEAD_INIT(audit_rules_list[6]),
 };
 
 DEFINE_MUTEX(audit_filter_mutex);
@@ -263,6 +265,7 @@ static inline struct audit_entry *audit_to_entry_common(struct audit_rule_data *
 #endif
        case AUDIT_FILTER_USER:
        case AUDIT_FILTER_TYPE:
+       case AUDIT_FILTER_FS:
                ;
        }
        if (unlikely(rule->action == AUDIT_POSSIBLE)) {
@@ -338,6 +341,21 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f)
                    entry->rule.listnr != AUDIT_FILTER_USER)
                        return -EINVAL;
                break;
+       case AUDIT_FSTYPE:
+               if (entry->rule.listnr != AUDIT_FILTER_FS)
+                       return -EINVAL;
+               break;
+       }
+
+       switch(entry->rule.listnr) {
+       case AUDIT_FILTER_FS:
+               switch(f->type) {
+               case AUDIT_FSTYPE:
+               case AUDIT_FILTERKEY:
+                       break;
+               default:
+                       return -EINVAL;
+               }
        }
 
        switch(f->type) {
@@ -391,6 +409,7 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f)
                        return -EINVAL;
        /* FALL THROUGH */
        case AUDIT_ARCH:
+       case AUDIT_FSTYPE:
                if (f->op != Audit_not_equal && f->op != Audit_equal)
                        return -EINVAL;
                break;
@@ -910,10 +929,13 @@ static inline int audit_add_rule(struct audit_entry *entry)
 #ifdef CONFIG_AUDITSYSCALL
        int dont_count = 0;
 
-       /* If either of these, don't count towards total */
-       if (entry->rule.listnr == AUDIT_FILTER_USER ||
-               entry->rule.listnr == AUDIT_FILTER_TYPE)
+       /* If any of these, don't count towards total */
+       switch(entry->rule.listnr) {
+       case AUDIT_FILTER_USER:
+       case AUDIT_FILTER_TYPE:
+       case AUDIT_FILTER_FS:
                dont_count = 1;
+       }
 #endif
 
        mutex_lock(&audit_filter_mutex);
@@ -989,10 +1011,13 @@ int audit_del_rule(struct audit_entry *entry)
 #ifdef CONFIG_AUDITSYSCALL
        int dont_count = 0;
 
-       /* If either of these, don't count towards total */
-       if (entry->rule.listnr == AUDIT_FILTER_USER ||
-               entry->rule.listnr == AUDIT_FILTER_TYPE)
+       /* If any of these, don't count towards total */
+       switch(entry->rule.listnr) {
+       case AUDIT_FILTER_USER:
+       case AUDIT_FILTER_TYPE:
+       case AUDIT_FILTER_FS:
                dont_count = 1;
+       }
 #endif
 
        mutex_lock(&audit_filter_mutex);
index 9c723e978245cfe55b33153e6fa36c8761165722..e80459f7e1327731f6960ee5824e22d71037b8c8 100644 (file)
@@ -1869,10 +1869,33 @@ void __audit_inode_child(struct inode *parent,
        struct inode *inode = d_backing_inode(dentry);
        const char *dname = dentry->d_name.name;
        struct audit_names *n, *found_parent = NULL, *found_child = NULL;
+       struct audit_entry *e;
+       struct list_head *list = &audit_filter_list[AUDIT_FILTER_FS];
+       int i;
 
        if (!context->in_syscall)
                return;
 
+       rcu_read_lock();
+       if (!list_empty(list)) {
+               list_for_each_entry_rcu(e, list, list) {
+                       for (i = 0; i < e->rule.field_count; i++) {
+                               struct audit_field *f = &e->rule.fields[i];
+
+                               if (f->type == AUDIT_FSTYPE) {
+                                       if (audit_comparator(parent->i_sb->s_magic,
+                                           f->op, f->val)) {
+                                               if (e->rule.action == AUDIT_NEVER) {
+                                                       rcu_read_unlock();
+                                                       return;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+       rcu_read_unlock();
+
        if (inode)
                handle_one(inode);