Commit a48b284b authored by Paul Moore's avatar Paul Moore

audit: fix a net reference leak in audit_send_reply()

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: default avatarRichard Guy Briggs <rgb@redhat.com>
Signed-off-by: default avatarPaul Moore <paul@paul-moore.com>
parent 8f3d9f35
...@@ -924,19 +924,30 @@ struct sk_buff *audit_make_reply(int seq, int type, int done, ...@@ -924,19 +924,30 @@ struct sk_buff *audit_make_reply(int seq, int type, int done,
return NULL; 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) static int audit_send_reply_thread(void *arg)
{ {
struct audit_reply *reply = (struct audit_reply *)arg; struct audit_reply *reply = (struct audit_reply *)arg;
struct sock *sk = audit_get_sk(reply->net);
audit_ctl_lock(); audit_ctl_lock();
audit_ctl_unlock(); audit_ctl_unlock();
/* Ignore failure. It'll only happen if the sender goes away, /* Ignore failure. It'll only happen if the sender goes away,
because our timeout is set to infinite. */ because our timeout is set to infinite. */
netlink_unicast(sk, reply->skb, reply->portid, 0); netlink_unicast(audit_get_sk(reply->net), reply->skb, reply->portid, 0);
put_net(reply->net); reply->skb = NULL;
kfree(reply); audit_free_reply(reply);
return 0; return 0;
} }
...@@ -950,35 +961,32 @@ static int audit_send_reply_thread(void *arg) ...@@ -950,35 +961,32 @@ static int audit_send_reply_thread(void *arg)
* @payload: payload data * @payload: payload data
* @size: payload size * @size: payload size
* *
* Allocates an skb, builds the netlink message, and sends it to the port id. * Allocates a skb, builds the netlink message, and sends it to the port id.
* No failure notifications.
*/ */
static void audit_send_reply(struct sk_buff *request_skb, int seq, int type, int done, static void audit_send_reply(struct sk_buff *request_skb, int seq, int type, int done,
int multi, const void *payload, int size) int multi, const void *payload, int size)
{ {
struct net *net = sock_net(NETLINK_CB(request_skb).sk);
struct sk_buff *skb;
struct task_struct *tsk; struct task_struct *tsk;
struct audit_reply *reply = kmalloc(sizeof(struct audit_reply), struct audit_reply *reply;
GFP_KERNEL);
reply = kzalloc(sizeof(*reply), GFP_KERNEL);
if (!reply) if (!reply)
return; return;
skb = audit_make_reply(seq, type, done, multi, payload, size); reply->skb = audit_make_reply(seq, type, done, multi, payload, size);
if (!skb) if (!reply->skb)
goto out; goto err;
reply->net = get_net(sock_net(NETLINK_CB(request_skb).sk));
reply->net = get_net(net);
reply->portid = NETLINK_CB(request_skb).portid; reply->portid = NETLINK_CB(request_skb).portid;
reply->skb = skb;
tsk = kthread_run(audit_send_reply_thread, reply, "audit_send_reply"); tsk = kthread_run(audit_send_reply_thread, reply, "audit_send_reply");
if (!IS_ERR(tsk)) if (IS_ERR(tsk))
return; goto err;
kfree_skb(skb);
out: return;
kfree(reply);
err:
audit_free_reply(reply);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment