audit: store the auditd PID as a pid struct instead of pid_t
authorPaul Moore <paul@paul-moore.com>
Tue, 2 May 2017 14:16:05 +0000 (10:16 -0400)
committerPaul Moore <paul@paul-moore.com>
Tue, 2 May 2017 14:16:05 +0000 (10:16 -0400)
This is arguably the right thing to do, and will make it easier when
we start supporting multiple audit daemons in different namespaces.

Signed-off-by: Paul Moore <paul@paul-moore.com>
kernel/audit.c
kernel/audit.h

index b40f3c4727e11f251ad2aa70fe816571a35b528c..a2f7803a68d019e51ff423a2cc8cde8970c6c573 100644 (file)
@@ -58,6 +58,7 @@
 #include <linux/rcupdate.h>
 #include <linux/mutex.h>
 #include <linux/gfp.h>
+#include <linux/pid.h>
 
 #include <linux/audit.h>
 
@@ -117,7 +118,7 @@ struct audit_net {
  * or the included spinlock for writing.
  */
 static struct auditd_connection {
-       int pid;
+       struct pid *pid;
        u32 portid;
        struct net *net;
        spinlock_t lock;
@@ -220,17 +221,40 @@ struct audit_reply {
  * Description:
  * Return 1 if the task is a registered audit daemon, 0 otherwise.
  */
-int auditd_test_task(const struct task_struct *task)
+int auditd_test_task(struct task_struct *task)
 {
        int rc;
 
        rcu_read_lock();
-       rc = (auditd_conn.pid && task->tgid == auditd_conn.pid ? 1 : 0);
+       rc = (auditd_conn.pid && auditd_conn.pid == task_tgid(task) ? 1 : 0);
        rcu_read_unlock();
 
        return rc;
 }
 
+/**
+ * auditd_pid_vnr - Return the auditd PID relative to the namespace
+ * @auditd: the auditd connection
+ *
+ * Description:
+ * Returns the PID in relation to the namespace, 0 on failure.  This function
+ * takes the RCU read lock internally, but if the caller needs to protect the
+ * auditd_connection pointer it should take the RCU read lock as well.
+ */
+static pid_t auditd_pid_vnr(const struct auditd_connection *auditd)
+{
+       pid_t pid;
+
+       rcu_read_lock();
+       if (!auditd || !auditd->pid)
+               pid = 0;
+       else
+               pid = pid_vnr(auditd->pid);
+       rcu_read_unlock();
+
+       return pid;
+}
+
 /**
  * audit_get_sk - Return the audit socket for the given network namespace
  * @net: the destination network namespace
@@ -428,12 +452,17 @@ static int audit_set_failure(u32 state)
  * This function will obtain and drop network namespace references as
  * necessary.
  */
-static void auditd_set(int pid, u32 portid, struct net *net)
+static void auditd_set(struct pid *pid, u32 portid, struct net *net)
 {
        unsigned long flags;
 
        spin_lock_irqsave(&auditd_conn.lock, flags);
-       auditd_conn.pid = pid;
+       if (auditd_conn.pid)
+               put_pid(auditd_conn.pid);
+       if (pid)
+               auditd_conn.pid = get_pid(pid);
+       else
+               auditd_conn.pid = NULL;
        auditd_conn.portid = portid;
        if (auditd_conn.net)
                put_net(auditd_conn.net);
@@ -1059,11 +1088,13 @@ static int audit_set_feature(struct sk_buff *skb)
        return 0;
 }
 
-static int audit_replace(pid_t pid)
+static int audit_replace(struct pid *pid)
 {
+       pid_t pvnr;
        struct sk_buff *skb;
 
-       skb = audit_make_reply(0, AUDIT_REPLACE, 0, 0, &pid, sizeof(pid));
+       pvnr = pid_vnr(pid);
+       skb = audit_make_reply(0, AUDIT_REPLACE, 0, 0, &pvnr, sizeof(pvnr));
        if (!skb)
                return -ENOMEM;
        return auditd_send_unicast_skb(skb);
@@ -1093,9 +1124,9 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                memset(&s, 0, sizeof(s));
                s.enabled               = audit_enabled;
                s.failure               = audit_failure;
-               rcu_read_lock();
-               s.pid                   = auditd_conn.pid;
-               rcu_read_unlock();
+               /* NOTE: use pid_vnr() so the PID is relative to the current
+                *       namespace */
+               s.pid                   = auditd_pid_vnr(&auditd_conn);
                s.rate_limit            = audit_rate_limit;
                s.backlog_limit         = audit_backlog_limit;
                s.lost                  = atomic_read(&audit_lost);
@@ -1121,36 +1152,36 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                                return err;
                }
                if (s.mask & AUDIT_STATUS_PID) {
-                       /* NOTE: we are using task_tgid_vnr() below because
-                        *       the s.pid value is relative to the namespace
-                        *       of the caller; at present this doesn't matter
-                        *       much since you can really only run auditd
-                        *       from the initial pid namespace, but something
-                        *       to keep in mind if this changes */
-                       int new_pid = s.pid;
+                       /* NOTE: we are using the vnr PID functions below
+                        *       because the s.pid value is relative to the
+                        *       namespace of the caller; at present this
+                        *       doesn't matter much since you can really only
+                        *       run auditd from the initial pid namespace, but
+                        *       something to keep in mind if this changes */
+                       pid_t new_pid = s.pid;
                        pid_t auditd_pid;
-                       pid_t requesting_pid = task_tgid_vnr(current);
+                       struct pid *req_pid = task_tgid(current);
+
+                       /* sanity check - PID values must match */
+                       if (new_pid != pid_vnr(req_pid))
+                               return -EINVAL;
 
                        /* test the auditd connection */
-                       audit_replace(requesting_pid);
+                       audit_replace(req_pid);
 
-                       rcu_read_lock();
-                       auditd_pid = auditd_conn.pid;
+                       auditd_pid = auditd_pid_vnr(&auditd_conn);
                        /* only the current auditd can unregister itself */
-                       if ((!new_pid) && (requesting_pid != auditd_pid)) {
-                               rcu_read_unlock();
+                       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) {
-                               rcu_read_unlock();
                                audit_log_config_change("audit_pid", new_pid,
                                                        auditd_pid, 0);
                                return -EEXIST;
                        }
-                       rcu_read_unlock();
 
                        if (audit_enabled != AUDIT_OFF)
                                audit_log_config_change("audit_pid", new_pid,
@@ -1158,8 +1189,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 
                        if (new_pid) {
                                /* register a new auditd connection */
-                               auditd_set(new_pid,
-                                          NETLINK_CB(skb).portid,
+                               auditd_set(req_pid, NETLINK_CB(skb).portid,
                                           sock_net(NETLINK_CB(skb).sk));
                                /* try to process any backlog */
                                wake_up_interruptible(&kauditd_wait);
index 18f3c2deeccfff34f798a460d2202b03c6654405..4987ea2a47027e53eb43ae809b2fa14852946efb 100644 (file)
@@ -218,7 +218,7 @@ extern void audit_log_name(struct audit_context *context,
                           struct audit_names *n, const struct path *path,
                           int record_num, int *call_panic);
 
-extern int auditd_test_task(const struct task_struct *task);
+extern int auditd_test_task(struct task_struct *task);
 
 #define AUDIT_INODE_BUCKETS    32
 extern struct list_head audit_inode_hash[AUDIT_INODE_BUCKETS];