audit: fix a net reference leak in audit_send_reply()
authorPaul Moore <paul@paul-moore.com>
Mon, 20 Apr 2020 14:09:29 +0000 (10:09 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 7 Apr 2021 10:05:41 +0000 (12:05 +0200)
commit a48b284b403a4a073d8beb72d2bb33e54df67fb6 upstream.

If audit_send_reply() fails when trying to create a new thread to
send the reply it also fails to cleanup properly, leaking a reference
to a net structure.  This patch fixes the error path and makes a
handful of other cleanups that came up while fixing the code.

Reported-by: teroincn@gmail.com
Reviewed-by: Richard Guy Briggs <rgb@redhat.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Cc: <stable@vger.kernel.org> # 4.9.x
Signed-off-by: Wen Yang <wenyang@linux.alibaba.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
kernel/audit.c

index af1e00f52bd01f99a3276d2f12907fdf08a7365f..55ccd8421df7bb5948a003c0a3f649da3744f5ee 100644 (file)
@@ -580,6 +580,18 @@ out_kfree_skb:
        return NULL;
 }
 
+static void audit_free_reply(struct audit_reply *reply)
+{
+       if (!reply)
+               return;
+
+       if (reply->skb)
+               kfree_skb(reply->skb);
+       if (reply->net)
+               put_net(reply->net);
+       kfree(reply);
+}
+
 static int audit_send_reply_thread(void *arg)
 {
        struct audit_reply *reply = (struct audit_reply *)arg;
@@ -592,8 +604,8 @@ static int audit_send_reply_thread(void *arg)
        /* Ignore failure. It'll only happen if the sender goes away,
           because our timeout is set to infinite. */
        netlink_unicast(aunet->nlsk , reply->skb, reply->portid, 0);
-       put_net(net);
-       kfree(reply);
+       reply->skb = NULL;
+       audit_free_reply(reply);
        return 0;
 }
 /**
@@ -606,36 +618,34 @@ static int audit_send_reply_thread(void *arg)
  * @payload: payload data
  * @size: payload size
  *
- * Allocates an skb, builds the netlink message, and sends it to the port id.
- * No failure notifications.
+ * Allocates a skb, builds the netlink message, and sends it to the port id.
  */
 static void audit_send_reply(struct sk_buff *request_skb, int seq, int type, int done,
                             int multi, const void *payload, int size)
 {
        u32 portid = NETLINK_CB(request_skb).portid;
-       struct net *net = sock_net(NETLINK_CB(request_skb).sk);
-       struct sk_buff *skb;
        struct task_struct *tsk;
-       struct audit_reply *reply = kmalloc(sizeof(struct audit_reply),
-                                           GFP_KERNEL);
+       struct audit_reply *reply;
 
+       reply = kzalloc(sizeof(*reply), GFP_KERNEL);
        if (!reply)
                return;
 
-       skb = audit_make_reply(portid, seq, type, done, multi, payload, size);
-       if (!skb)
-               goto out;
+       reply->skb = audit_make_reply(portid, seq, type, done, multi, payload, size);
+       if (!reply->skb)
+               goto err;
 
-       reply->net = get_net(net);
+       reply->net = get_net(sock_net(NETLINK_CB(request_skb).sk));
        reply->portid = portid;
-       reply->skb = skb;
 
        tsk = kthread_run(audit_send_reply_thread, reply, "audit_send_reply");
-       if (!IS_ERR(tsk))
-               return;
-       kfree_skb(skb);
-out:
-       kfree(reply);
+       if (IS_ERR(tsk))
+               goto err;
+
+       return;
+
+err:
+       audit_free_reply(reply);
 }
 
 /*