Merge tag 'audit-pr-20180403' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoor...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 6 Apr 2018 22:01:25 +0000 (15:01 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 6 Apr 2018 22:01:25 +0000 (15:01 -0700)
Pull audit updates from Paul Moore:
 "We didn't have anything to send for v4.16, but we're back with a
  little more than usual for v4.17.

  Eleven patches in total, most fall into the small fix category, but
  there are three non-trivial changes worth calling out:

   - the audit entry filter is being removed after deprecating it for
     quite a while (years of no one really using it because it turns out
     to be not very practical)

   - created our own version of "__mutex_owner()" because the locking
     folks were upset we were using theirs

   - improved our handling of kernel command line parameters to make
     them more forgiving

   - we fixed auditing of symlink operations

  Everything passes the audit-testsuite and as of a few minutes ago it
  merges well with your tree"

* tag 'audit-pr-20180403' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit:
  audit: add refused symlink to audit_names
  audit: remove path param from link denied function
  audit: link denied should not directly generate PATH record
  audit: make ANOM_LINK obey audit_enabled and audit_dummy_context
  audit: do not panic on invalid boot parameter
  audit: track the owner of the command mutex ourselves
  audit: return on memory error to avoid null pointer dereference
  audit: bail before bug check if audit disabled
  audit: deprecate the AUDIT_FILTER_ENTRY filter
  audit: session ID should not set arch quick field pointer
  audit: update bugtracker and source URIs

Documentation/admin-guide/kernel-parameters.txt
MAINTAINERS
fs/namei.c
include/linux/audit.h
kernel/audit.c
kernel/audit.h
kernel/audit_tree.c
kernel/auditfilter.c
kernel/auditsc.c

index 3c87a69cffcb17b9a06285be601d11922dcb6693..7efed1ccddc9a0791e061ee9f933dac571170c8f 100644 (file)
                        Use software keyboard repeat
 
        audit=          [KNL] Enable the audit sub-system
-                       Format: { "0" | "1" } (0 = disabled, 1 = enabled)
-                       0 - kernel audit is disabled and can not be enabled
-                           until the next reboot
+                       Format: { "0" | "1" | "off" | "on" }
+                       0 | off - kernel audit is disabled and can not be
+                           enabled until the next reboot
                        unset - kernel audit is initialized but disabled and
                            will be fully enabled by the userspace auditd.
-                       1 - kernel audit is initialized and partially enabled,
-                           storing at most audit_backlog_limit messages in
-                           RAM until it is fully enabled by the userspace
-                           auditd.
+                       1 | on - kernel audit is initialized and partially
+                           enabled, storing at most audit_backlog_limit
+                           messages in RAM until it is fully enabled by the
+                           userspace auditd.
                        Default: unset
 
        audit_backlog_limit= [KNL] Set the audit queue size limit.
index 881d328020df5552bac4b1f931e1ea93c37241d4..f1be26eb7e802e417d60b1babd217b407f197c46 100644 (file)
@@ -2504,7 +2504,6 @@ M:        Paul Moore <paul@paul-moore.com>
 M:     Eric Paris <eparis@redhat.com>
 L:     linux-audit@redhat.com (moderated for non-subscribers)
 W:     https://github.com/linux-audit
-W:     https://people.redhat.com/sgrubb/audit
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit.git
 S:     Supported
 F:     include/linux/audit.h
index 5661da1972cdadfb17c26f15703df167c0c1322e..a66ed5a1622af5ea466041080931e8f4257ffdcd 100644 (file)
@@ -929,7 +929,8 @@ static inline int may_follow_link(struct nameidata *nd)
        if (nd->flags & LOOKUP_RCU)
                return -ECHILD;
 
-       audit_log_link_denied("follow_link", &nd->stack[0].link);
+       audit_inode(nd->name, nd->stack[0].link.dentry, 0);
+       audit_log_link_denied("follow_link");
        return -EACCES;
 }
 
@@ -995,7 +996,7 @@ static int may_linkat(struct path *link)
        if (safe_hardlink_source(inode) || inode_owner_or_capable(inode))
                return 0;
 
-       audit_log_link_denied("linkat", link);
+       audit_log_link_denied("linkat");
        return -EPERM;
 }
 
index af410d9fbf2da9f904bac6e8309c2b097142fea9..75d5b031e80271a8cc52bbfd49334ee291c01a16 100644 (file)
@@ -146,8 +146,7 @@ extern void             audit_log_d_path(struct audit_buffer *ab,
                                             const struct path *path);
 extern void                audit_log_key(struct audit_buffer *ab,
                                          char *key);
-extern void                audit_log_link_denied(const char *operation,
-                                                 const struct path *link);
+extern void                audit_log_link_denied(const char *operation);
 extern void                audit_log_lost(const char *message);
 
 extern int audit_log_task_context(struct audit_buffer *ab);
@@ -194,8 +193,7 @@ static inline void audit_log_d_path(struct audit_buffer *ab,
 { }
 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_link_denied(const char *string)
 { }
 static inline int audit_log_task_context(struct audit_buffer *ab)
 {
index d97e8f0f73ca51a82a93511b3194b0089ee41b66..670665c6e2a651648ba55f53879a12501464b5d8 100644 (file)
@@ -38,7 +38,8 @@
  *       6) Support low-overhead kernel-based filtering to minimize the
  *          information that must be passed to user-space.
  *
- * Example user-space utilities: http://people.redhat.com/sgrubb/audit/
+ * Audit userspace, documentation, tests, and bug/issue trackers:
+ *     https://github.com/linux-audit
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -180,9 +181,21 @@ static char *audit_feature_names[2] = {
        "loginuid_immutable",
 };
 
-
-/* Serialize requests from userspace. */
-DEFINE_MUTEX(audit_cmd_mutex);
+/**
+ * struct audit_ctl_mutex - serialize requests from userspace
+ * @lock: the mutex used for locking
+ * @owner: the task which owns the lock
+ *
+ * Description:
+ * This is the lock struct used to ensure we only process userspace requests
+ * in an orderly fashion.  We can't simply use a mutex/lock here because we
+ * need to track lock ownership so we don't end up blocking the lock owner in
+ * audit_log_start() or similar.
+ */
+static struct audit_ctl_mutex {
+       struct mutex lock;
+       void *owner;
+} audit_cmd_mutex;
 
 /* AUDIT_BUFSIZ is the size of the temporary buffer used for formatting
  * audit records.  Since printk uses a 1024 byte buffer, this buffer
@@ -226,6 +239,36 @@ int auditd_test_task(struct task_struct *task)
        return rc;
 }
 
+/**
+ * audit_ctl_lock - Take the audit control lock
+ */
+void audit_ctl_lock(void)
+{
+       mutex_lock(&audit_cmd_mutex.lock);
+       audit_cmd_mutex.owner = current;
+}
+
+/**
+ * audit_ctl_unlock - Drop the audit control lock
+ */
+void audit_ctl_unlock(void)
+{
+       audit_cmd_mutex.owner = NULL;
+       mutex_unlock(&audit_cmd_mutex.lock);
+}
+
+/**
+ * audit_ctl_owner_current - Test to see if the current task owns the lock
+ *
+ * Description:
+ * Return true if the current task owns the audit control lock, false if it
+ * doesn't own the lock.
+ */
+static bool audit_ctl_owner_current(void)
+{
+       return (current == audit_cmd_mutex.owner);
+}
+
 /**
  * auditd_pid_vnr - Return the auditd PID relative to the namespace
  *
@@ -860,8 +903,8 @@ int audit_send_list(void *_dest)
        struct sock *sk = audit_get_sk(dest->net);
 
        /* wait for parent to finish and send an ACK */
-       mutex_lock(&audit_cmd_mutex);
-       mutex_unlock(&audit_cmd_mutex);
+       audit_ctl_lock();
+       audit_ctl_unlock();
 
        while ((skb = __skb_dequeue(&dest->q)) != NULL)
                netlink_unicast(sk, skb, dest->portid, 0);
@@ -902,8 +945,8 @@ static int audit_send_reply_thread(void *arg)
        struct audit_reply *reply = (struct audit_reply *)arg;
        struct sock *sk = audit_get_sk(reply->net);
 
-       mutex_lock(&audit_cmd_mutex);
-       mutex_unlock(&audit_cmd_mutex);
+       audit_ctl_lock();
+       audit_ctl_unlock();
 
        /* Ignore failure. It'll only happen if the sender goes away,
           because our timeout is set to infinite. */
@@ -1058,6 +1101,8 @@ static void audit_log_feature_change(int which, u32 old_feature, u32 new_feature
                return;
 
        ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_FEATURE_CHANGE);
+       if (!ab)
+               return;
        audit_log_task_info(ab, current);
        audit_log_format(ab, " feature=%s old=%u new=%u old_lock=%u new_lock=%u res=%d",
                         audit_feature_names[which], !!old_feature, !!new_feature,
@@ -1466,7 +1511,7 @@ static void audit_receive(struct sk_buff  *skb)
        nlh = nlmsg_hdr(skb);
        len = skb->len;
 
-       mutex_lock(&audit_cmd_mutex);
+       audit_ctl_lock();
        while (nlmsg_ok(nlh, len)) {
                err = audit_receive_msg(skb, nlh);
                /* if err or if this message says it wants a response */
@@ -1475,7 +1520,7 @@ static void audit_receive(struct sk_buff  *skb)
 
                nlh = nlmsg_next(nlh, &len);
        }
-       mutex_unlock(&audit_cmd_mutex);
+       audit_ctl_unlock();
 }
 
 /* Run custom bind function on netlink socket group connect or bind requests. */
@@ -1547,6 +1592,9 @@ static int __init audit_init(void)
        for (i = 0; i < AUDIT_INODE_BUCKETS; i++)
                INIT_LIST_HEAD(&audit_inode_hash[i]);
 
+       mutex_init(&audit_cmd_mutex.lock);
+       audit_cmd_mutex.owner = NULL;
+
        pr_info("initializing netlink subsys (%s)\n",
                audit_default ? "enabled" : "disabled");
        register_pernet_subsys(&audit_net_ops);
@@ -1567,19 +1615,26 @@ static int __init audit_init(void)
 }
 postcore_initcall(audit_init);
 
-/* Process kernel command-line parameter at boot time.  audit=0 or audit=1. */
+/*
+ * Process kernel command-line parameter at boot time.
+ * audit={0|off} or audit={1|on}.
+ */
 static int __init audit_enable(char *str)
 {
-       long val;
-
-       if (kstrtol(str, 0, &val))
-               panic("audit: invalid 'audit' parameter value (%s)\n", str);
-       audit_default = (val ? AUDIT_ON : AUDIT_OFF);
+       if (!strcasecmp(str, "off") || !strcmp(str, "0"))
+               audit_default = AUDIT_OFF;
+       else if (!strcasecmp(str, "on") || !strcmp(str, "1"))
+               audit_default = AUDIT_ON;
+       else {
+               pr_err("audit: invalid 'audit' parameter value (%s)\n", str);
+               audit_default = AUDIT_ON;
+       }
 
        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_err("audit: error setting audit state (%d)\n",
+                      audit_default);
 
        pr_info("%s\n", audit_default ?
                "enabled (after initialization)" : "disabled (until reboot)");
@@ -1710,8 +1765,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
         *    using a PID anchored in the caller's namespace
         * 2. generator holding the audit_cmd_mutex - we don't want to block
         *    while holding the mutex */
-       if (!(auditd_test_task(current) ||
-             (current == __mutex_owner(&audit_cmd_mutex)))) {
+       if (!(auditd_test_task(current) || audit_ctl_owner_current())) {
                long stime = audit_backlog_wait_time;
 
                while (audit_backlog_limit &&
@@ -2254,33 +2308,23 @@ EXPORT_SYMBOL(audit_log_task_info);
 /**
  * audit_log_link_denied - report a link restriction denial
  * @operation: specific link operation
- * @link: the path that triggered the restriction
  */
-void audit_log_link_denied(const char *operation, const struct path *link)
+void audit_log_link_denied(const char *operation)
 {
        struct audit_buffer *ab;
-       struct audit_names *name;
 
-       name = kzalloc(sizeof(*name), GFP_NOFS);
-       if (!name)
+       if (!audit_enabled || audit_dummy_context())
                return;
 
        /* Generate AUDIT_ANOM_LINK with subject, operation, outcome. */
        ab = audit_log_start(current->audit_context, GFP_KERNEL,
                             AUDIT_ANOM_LINK);
        if (!ab)
-               goto out;
+               return;
        audit_log_format(ab, "op=%s", operation);
        audit_log_task_info(ab, current);
        audit_log_format(ab, " res=0");
        audit_log_end(ab);
-
-       /* Generate AUDIT_PATH record with object. */
-       name->type = AUDIT_TYPE_NORMAL;
-       audit_copy_inode(name, link->dentry, d_backing_inode(link->dentry));
-       audit_log_name(current->audit_context, name, link, 0, NULL);
-out:
-       kfree(name);
 }
 
 /**
index af5bc59487ed690bacb9b2ff1ed9c3a58d6994c7..214e1494837060bd580050c62edfd5838c0104f0 100644 (file)
@@ -341,4 +341,5 @@ extern struct list_head *audit_killed_trees(void);
 #define audit_filter_inodes(t,c) AUDIT_DISABLED
 #endif
 
-extern struct mutex audit_cmd_mutex;
+extern void audit_ctl_lock(void);
+extern void audit_ctl_unlock(void);
index fd353120e0d946f3d3bb3ac98f3903aebbf42c76..67e6956c0b61d0c2c08aa3f21546bd16696b4e75 100644 (file)
@@ -709,7 +709,7 @@ static int prune_tree_thread(void *unused)
                        schedule();
                }
 
-               mutex_lock(&audit_cmd_mutex);
+               audit_ctl_lock();
                mutex_lock(&audit_filter_mutex);
 
                while (!list_empty(&prune_list)) {
@@ -727,7 +727,7 @@ static int prune_tree_thread(void *unused)
                }
 
                mutex_unlock(&audit_filter_mutex);
-               mutex_unlock(&audit_cmd_mutex);
+               audit_ctl_unlock();
        }
        return 0;
 }
@@ -924,7 +924,7 @@ static void audit_schedule_prune(void)
  */
 void audit_kill_trees(struct list_head *list)
 {
-       mutex_lock(&audit_cmd_mutex);
+       audit_ctl_lock();
        mutex_lock(&audit_filter_mutex);
 
        while (!list_empty(list)) {
@@ -942,7 +942,7 @@ void audit_kill_trees(struct list_head *list)
        }
 
        mutex_unlock(&audit_filter_mutex);
-       mutex_unlock(&audit_cmd_mutex);
+       audit_ctl_unlock();
 }
 
 /*
index 4a1758adb22249fcdc11ffba75263367ccde8936..d7a807e814514cea81694bb73667b7b34247ab84 100644 (file)
@@ -258,8 +258,8 @@ static inline struct audit_entry *audit_to_entry_common(struct audit_rule_data *
                goto exit_err;
 #ifdef CONFIG_AUDITSYSCALL
        case AUDIT_FILTER_ENTRY:
-               if (rule->action == AUDIT_ALWAYS)
-                       goto exit_err;
+               pr_err("AUDIT_FILTER_ENTRY is deprecated\n");
+               goto exit_err;
        case AUDIT_FILTER_EXIT:
        case AUDIT_FILTER_TASK:
 #endif
@@ -496,7 +496,6 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
                        if (!gid_valid(f->gid))
                                goto exit_free;
                        break;
-               case AUDIT_SESSIONID:
                case AUDIT_ARCH:
                        entry->rule.arch_f = f;
                        break;
index e80459f7e1327731f6960ee5824e22d71037b8c8..4e0a4ac803db72499f67822233f6db70d7b6f3b8 100644 (file)
@@ -1511,30 +1511,28 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2,
        struct audit_context *context = tsk->audit_context;
        enum audit_state     state;
 
-       if (!context)
+       if (!audit_enabled || !context)
                return;
 
        BUG_ON(context->in_syscall || context->name_count);
 
-       if (!audit_enabled)
+       state = context->state;
+       if (state == AUDIT_DISABLED)
                return;
 
+       context->dummy = !audit_n_rules;
+       if (!context->dummy && state == AUDIT_BUILD_CONTEXT) {
+               context->prio = 0;
+               if (auditd_test_task(tsk))
+                       return;
+       }
+
        context->arch       = syscall_get_arch();
        context->major      = major;
        context->argv[0]    = a1;
        context->argv[1]    = a2;
        context->argv[2]    = a3;
        context->argv[3]    = a4;
-
-       state = context->state;
-       context->dummy = !audit_n_rules;
-       if (!context->dummy && state == AUDIT_BUILD_CONTEXT) {
-               context->prio = 0;
-               state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_ENTRY]);
-       }
-       if (state == AUDIT_DISABLED)
-               return;
-
        context->serial     = 0;
        context->ctime = current_kernel_time64();
        context->in_syscall = 1;