Audit: stop deadlock from signals under load
Eric Paris
maintainerPATCH 1/1 Audit: stop deadlock from signals under load
A deadlock is possible between kauditd and auditd under load if auditd receives a signal. When auditd receives a signal it sends a netlink message to the kernel asking for information about the sender of the signal. In that same context the audit system will attempt to send a netlink message back to the userspace auditd. If kauditd has already filled the socket buffer (see netlink_attachskb()) auditd will now put itself to sleep waiting for room to send the message. Since auditd is responsible for draining that socket we have a deadlock. The fix, since the response from the kernel does not need to be synchronous is to send the signal information back to auditd in a separate thread. And thus auditd can continue to drain the audit queue normally.
---
kernel/audit.c | 40 +++++++++++++++++++++++++++++++++++----- 1 files changed, 35 insertions(+), 5 deletions(-)
arch/x86/boot/install.sh +0 -0
kernel/audit.c +35 -5
@@ -155,6 +155,11 @@ struct audit_buffer {gfp_t gfp_mask; }; +struct audit_reply { +int pid; +struct sk_buff *skb; +}; +static void audit_set_pid (struct audit_buffer *ab,pid_t pid) {if (ab) {
@@ -470,6 +475,19 @@ nlmsg_failure: /* Used by NLMSG_PUT */return NULL ; } +static int audit_send_reply_thread (void *arg) +{ +struct audit_reply *reply = (struct audit_reply *)arg; + +mutex_lock (&audit_cmd_mutex); +mutex_unlock (&audit_cmd_mutex); + +/* Ignore failure. It'll only happen if the sender goes away, +because our timeout is set to infinite. */ +netlink_unicast (audit_sock, reply->skb, reply->pid,0 ); +kfree (reply); +return 0 ; +}/** * audit_send_reply - send an audit reply message via netlink * @pid: process id to send reply to
@@ -486,14 +504,26 @@ nlmsg_failure: /* Used by NLMSG_PUT */void audit_send_reply (int pid,int seq,int type,int done,int multi,void *payload,int size) { -struct sk_buff *skb; +struct sk_buff *skb; +struct task_struct *tsk; +struct audit_reply *reply =kmalloc (sizeof (struct audit_reply ), +GFP_KERNEL ); + +if (!reply) +return ; + skb =audit_make_reply (pid, seq, type, done, multi, payload, size);if (!skb)return ; -/* Ignore failure. It'll only happen if the sender goes away, -because our timeout is set to infinite. */ -netlink_unicast (audit_sock, skb, pid,0 ); -return ; + + reply->pid = pid; + reply->skb = skb; + + tsk =kthread_run (audit_send_reply_thread, reply,"audit_send_reply" ); +if (IS_ERR (tsk)) { +kfree (reply); +kfree_skb (skb); + } }/*