From: Paul Moore <p...@paul-moore.com>

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: teroi...@gmail.com
Reviewed-by: Richard Guy Briggs <r...@redhat.com>
Signed-off-by: Paul Moore <p...@paul-moore.com>
Cc: <sta...@vger.kernel.org> # 4.9.x
Signed-off-by: Wen Yang <weny...@linux.alibaba.com>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>
---
 kernel/audit.c |   46 ++++++++++++++++++++++++++++------------------
 1 file changed, 28 insertions(+), 18 deletions(-)

--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -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
        /* 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
  * @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);
 }
 
 /*


Reply via email to