Commit f09ac9db2aafe36fde9ebd63c8c5d776f6e7bd41
Committed by
Al Viro
1 parent
f3d357b092
Exists in
master
and in
39 other branches
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. Signed-off-by: Eric Paris <eparis@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Showing 1 changed file with 35 additions and 5 deletions Side-by-side Diff
kernel/audit.c
... | ... | @@ -156,6 +156,11 @@ |
156 | 156 | gfp_t gfp_mask; |
157 | 157 | }; |
158 | 158 | |
159 | +struct audit_reply { | |
160 | + int pid; | |
161 | + struct sk_buff *skb; | |
162 | +}; | |
163 | + | |
159 | 164 | static void audit_set_pid(struct audit_buffer *ab, pid_t pid) |
160 | 165 | { |
161 | 166 | if (ab) { |
... | ... | @@ -528,6 +533,19 @@ |
528 | 533 | return NULL; |
529 | 534 | } |
530 | 535 | |
536 | +static int audit_send_reply_thread(void *arg) | |
537 | +{ | |
538 | + struct audit_reply *reply = (struct audit_reply *)arg; | |
539 | + | |
540 | + mutex_lock(&audit_cmd_mutex); | |
541 | + mutex_unlock(&audit_cmd_mutex); | |
542 | + | |
543 | + /* Ignore failure. It'll only happen if the sender goes away, | |
544 | + because our timeout is set to infinite. */ | |
545 | + netlink_unicast(audit_sock, reply->skb, reply->pid, 0); | |
546 | + kfree(reply); | |
547 | + return 0; | |
548 | +} | |
531 | 549 | /** |
532 | 550 | * audit_send_reply - send an audit reply message via netlink |
533 | 551 | * @pid: process id to send reply to |
534 | 552 | |
... | ... | @@ -544,14 +562,26 @@ |
544 | 562 | void audit_send_reply(int pid, int seq, int type, int done, int multi, |
545 | 563 | void *payload, int size) |
546 | 564 | { |
547 | - struct sk_buff *skb; | |
565 | + struct sk_buff *skb; | |
566 | + struct task_struct *tsk; | |
567 | + struct audit_reply *reply = kmalloc(sizeof(struct audit_reply), | |
568 | + GFP_KERNEL); | |
569 | + | |
570 | + if (!reply) | |
571 | + return; | |
572 | + | |
548 | 573 | skb = audit_make_reply(pid, seq, type, done, multi, payload, size); |
549 | 574 | if (!skb) |
550 | 575 | return; |
551 | - /* Ignore failure. It'll only happen if the sender goes away, | |
552 | - because our timeout is set to infinite. */ | |
553 | - netlink_unicast(audit_sock, skb, pid, 0); | |
554 | - return; | |
576 | + | |
577 | + reply->pid = pid; | |
578 | + reply->skb = skb; | |
579 | + | |
580 | + tsk = kthread_run(audit_send_reply_thread, reply, "audit_send_reply"); | |
581 | + if (IS_ERR(tsk)) { | |
582 | + kfree(reply); | |
583 | + kfree_skb(skb); | |
584 | + } | |
555 | 585 | } |
556 | 586 | |
557 | 587 | /* |