Merge branch 'stable-4.13' of git://git.infradead.org/users/pcmoore/audit
[muen/linux.git] / kernel / audit.c
index 4b7d49868ce1e39d11603f6160d04e7e5d4457e2..833267bbd80bc62b367699eb9cdc646c20fb264c 100644 (file)
@@ -575,12 +575,16 @@ static void kauditd_retry_skb(struct sk_buff *skb)
 
 /**
  * auditd_reset - Disconnect the auditd connection
+ * @ac: auditd connection state
  *
  * Description:
  * Break the auditd/kauditd connection and move all the queued records into the
- * hold queue in case auditd reconnects.
+ * hold queue in case auditd reconnects.  It is important to note that the @ac
+ * pointer should never be dereferenced inside this function as it may be NULL
+ * or invalid, you can only compare the memory address!  If @ac is NULL then
+ * the connection will always be reset.
  */
-static void auditd_reset(void)
+static void auditd_reset(const struct auditd_connection *ac)
 {
        unsigned long flags;
        struct sk_buff *skb;
@@ -590,17 +594,21 @@ static void auditd_reset(void)
        spin_lock_irqsave(&auditd_conn_lock, flags);
        ac_old = rcu_dereference_protected(auditd_conn,
                                           lockdep_is_held(&auditd_conn_lock));
+       if (ac && ac != ac_old) {
+               /* someone already registered a new auditd connection */
+               spin_unlock_irqrestore(&auditd_conn_lock, flags);
+               return;
+       }
        rcu_assign_pointer(auditd_conn, NULL);
        spin_unlock_irqrestore(&auditd_conn_lock, flags);
 
        if (ac_old)
                call_rcu(&ac_old->rcu, auditd_conn_free);
 
-       /* flush all of the main and retry queues to the hold queue */
+       /* flush the retry queue to the hold queue, but don't touch the main
+        * queue since we need to process that normally for multicast */
        while ((skb = skb_dequeue(&audit_retry_queue)))
                kauditd_hold_skb(skb);
-       while ((skb = skb_dequeue(&audit_queue)))
-               kauditd_hold_skb(skb);
 }
 
 /**
@@ -649,8 +657,8 @@ static int auditd_send_unicast_skb(struct sk_buff *skb)
        return rc;
 
 err:
-       if (rc == -ECONNREFUSED)
-               auditd_reset();
+       if (ac && rc == -ECONNREFUSED)
+               auditd_reset(ac);
        return rc;
 }
 
@@ -795,9 +803,9 @@ static int kauditd_thread(void *dummy)
                rc = kauditd_send_queue(sk, portid,
                                        &audit_hold_queue, UNICAST_RETRIES,
                                        NULL, kauditd_rehold_skb);
-               if (rc < 0) {
+               if (ac && rc < 0) {
                        sk = NULL;
-                       auditd_reset();
+                       auditd_reset(ac);
                        goto main_queue;
                }
 
@@ -805,9 +813,9 @@ static int kauditd_thread(void *dummy)
                rc = kauditd_send_queue(sk, portid,
                                        &audit_retry_queue, UNICAST_RETRIES,
                                        NULL, kauditd_hold_skb);
-               if (rc < 0) {
+               if (ac && rc < 0) {
                        sk = NULL;
-                       auditd_reset();
+                       auditd_reset(ac);
                        goto main_queue;
                }
 
@@ -815,12 +823,13 @@ main_queue:
                /* process the main queue - do the multicast send and attempt
                 * unicast, dump failed record sends to the retry queue; if
                 * sk == NULL due to previous failures we will just do the
-                * multicast send and move the record to the retry queue */
+                * multicast send and move the record to the hold queue */
                rc = kauditd_send_queue(sk, portid, &audit_queue, 1,
                                        kauditd_send_multicast_skb,
-                                       kauditd_retry_skb);
-               if (sk == NULL || rc < 0)
-                       auditd_reset();
+                                       (sk ?
+                                        kauditd_retry_skb : kauditd_hold_skb));
+               if (ac && rc < 0)
+                       auditd_reset(ac);
                sk = NULL;
 
                /* drop our netns reference, no auditd sends past this line */
@@ -1230,7 +1239,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                                                                auditd_pid, 1);
 
                                /* unregister the auditd connection */
-                               auditd_reset();
+                               auditd_reset(NULL);
                        }
                }
                if (s.mask & AUDIT_STATUS_RATE_LIMIT) {
@@ -1999,22 +2008,10 @@ void audit_log_cap(struct audit_buffer *ab, char *prefix, kernel_cap_t *cap)
 
 static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name)
 {
-       kernel_cap_t *perm = &name->fcap.permitted;
-       kernel_cap_t *inh = &name->fcap.inheritable;
-       int log = 0;
-
-       if (!cap_isclear(*perm)) {
-               audit_log_cap(ab, "cap_fp", perm);
-               log = 1;
-       }
-       if (!cap_isclear(*inh)) {
-               audit_log_cap(ab, "cap_fi", inh);
-               log = 1;
-       }
-
-       if (log)
-               audit_log_format(ab, " cap_fe=%d cap_fver=%x",
-                                name->fcap.fE, name->fcap_ver);
+       audit_log_cap(ab, "cap_fp", &name->fcap.permitted);
+       audit_log_cap(ab, "cap_fi", &name->fcap.inheritable);
+       audit_log_format(ab, " cap_fe=%d cap_fver=%x",
+                        name->fcap.fE, name->fcap_ver);
 }
 
 static inline int audit_copy_fcaps(struct audit_names *name,