[PATCH 2/2] audit: kaudit_send_skb(): make non-blocking call to netlink_unicast()

2013-09-02 Thread Luiz Capitulino
From: Luiz capitulino 

Try this:

 1. Download the readahead-collector program and build it
 2. Run it with:
   # readahead-collector -f
 3. From another terminal do:
   # pkill -SIGSTOP readahead-collector
 4. Keep using the system, run top -d1, vmstat -S 1, etc
 5. Eventually, you'll get something like this:

[  124.046016] BUG: soft lockup - CPU#0 stuck for 22s! [login:2196]
[  124.046016] Modules linked in:
[  124.046016] CPU: 0 PID: 2196 Comm: login Not tainted 
3.11.0-rc7-00030-g41615e8 #13
[  124.046016] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011
[  124.046016] task: 88003d92c970 ti: 88003cd5 task.ti: 
88003cd5
[  124.046016] RIP: 0010:[]  [] 
audit_log_start+0x99/0x349
[  124.046016] RSP: 0018:88003cd51db0  EFLAGS: 0202
[  124.046016] RAX: 0100 RBX: 8107115e RCX: ea60
[  124.046016] RDX: 95f3 RSI: 0101 RDI: ea60
[  124.046016] RBP: 88003cd51e30 R08: 0100 R09: 
[  124.046016] R10: 000399b3 R11: 88003fc0d4a0 R12: 0046
[  124.046016] R13: 88003cd51d28 R14: 0046 R15: 810501ac
[  124.046016] FS:  7f80d3efa800() GS:88003fc0() 
knlGS:
[  124.046016] CS:  0010 DS:  ES:  CR0: 80050033
[  124.046016] CR2: 7f3f04f8c000 CR3: 3cd41000 CR4: 06b0
[  124.046016] Stack:
[  124.046016]  95f3 88003d747800 fffbfc40 
05160010
[  124.046016]  88003cd51e30   
88003d92c970
[  124.046016]  8105b3a6 dead00100100 dead00200200 
88003d747860
[  124.046016] Call Trace:
[  124.046016]  [] ? wake_up_state+0x12/0x12
[  124.046016]  [] audit_log_name+0x34/0x1a2
[  124.046016]  [] ? _raw_spin_unlock_irqrestore+0x34/0x48
[  124.046016]  [] audit_log_exit+0xa44/0xa8f
[  124.046016]  [] ? rcu_read_unlock+0x1c/0x2d
[  124.046016]  [] ? audit_filter_inodes+0xf5/0x10e
[  124.046016]  [] ? audit_filter_syscall+0xb2/0xd9
[  124.046016]  [] __audit_syscall_exit+0x4d/0x108
[  124.046016]  [] sysret_audit+0x17/0x21
[  124.046016] Code: e7 8b 05 1c ed 59 00 8b 0d 12 ed 59 00 8b 35 1c 24 e1 00 
46 8d 04 30 48 63 f9 85 c0 0f 84 29 01 00 00 44 39 c6 0f 86 20 01 00 00 <83> 7c 
24 18 00 0f 84 a4 00 00 00 85 c9 0f 84 9c 00 00 00 48 8b

This is what happens:

 1. The readahead-collector daemon got stuck and stops reading
from the netlink socket
 2. The kernel keeps logging stuff to the audit subsystem at
a high rate
 3. Because kauditd's call to netlink_unicast() is blocking and
as the netlink socket got a backlog, the kaudit thread will
eventually get blocked when trying to send an SKB to user-space
 4. As the kaudit thread is blocked, SKBs start to accumulate.
This will cause a thread calling audit_log_start() to
be put to sleep when a threshold of queued SBKs is reached
 5. The kaudit thread never wakes up, but the kernel thread
put to sleep in step 4 does. Soon or later sleep_time will be
negative, causing it to busy-wait in the while() loop

This commit fixes that problem by making the call to netlink_unicast()
non-blocking in kaudit_send_skb(). This way the kaudit thread
never gets blocked, completely avoiding the scenario described above.

Signed-off-by: Luiz capitulino 
---
 kernel/audit.c | 8 ++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/kernel/audit.c b/kernel/audit.c
index 475c1d1..2b34bd6 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -385,8 +385,12 @@ static int kauditd_send_skb(struct sk_buff *skb)
int err;
/* take a reference in case we can't send it and we want to hold it */
skb_get(skb);
-   err = netlink_unicast(audit_sock, skb, audit_nlk_portid, 0);
-   if (err < 0) {
+   err = netlink_unicast(audit_sock, skb, audit_nlk_portid, 1);
+   if (err == -EAGAIN) {
+   pr_warn_ratelimited("auditd (pid=%d) is not responding\n", 
audit_pid);
+   audit_hold_skb(skb);
+   return err;
+   } else if (err < 0) {
BUG_ON(err != -ECONNREFUSED); /* Shouldn't happen */
printk(KERN_ERR "audit: *NO* daemon at audit_pid=%d\n", 
audit_pid);
audit_log_lost("auditd disappeared\n");
-- 
1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 2/2] audit: kaudit_send_skb(): make non-blocking call to netlink_unicast()

2013-09-02 Thread Luiz Capitulino
From: Luiz capitulino lcapitul...@redhat.com

Try this:

 1. Download the readahead-collector program and build it
 2. Run it with:
   # readahead-collector -f
 3. From another terminal do:
   # pkill -SIGSTOP readahead-collector
 4. Keep using the system, run top -d1, vmstat -S 1, etc
 5. Eventually, you'll get something like this:

[  124.046016] BUG: soft lockup - CPU#0 stuck for 22s! [login:2196]
[  124.046016] Modules linked in:
[  124.046016] CPU: 0 PID: 2196 Comm: login Not tainted 
3.11.0-rc7-00030-g41615e8 #13
[  124.046016] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011
[  124.046016] task: 88003d92c970 ti: 88003cd5 task.ti: 
88003cd5
[  124.046016] RIP: 0010:[8108a36c]  [8108a36c] 
audit_log_start+0x99/0x349
[  124.046016] RSP: 0018:88003cd51db0  EFLAGS: 0202
[  124.046016] RAX: 0100 RBX: 8107115e RCX: ea60
[  124.046016] RDX: 95f3 RSI: 0101 RDI: ea60
[  124.046016] RBP: 88003cd51e30 R08: 0100 R09: 
[  124.046016] R10: 000399b3 R11: 88003fc0d4a0 R12: 0046
[  124.046016] R13: 88003cd51d28 R14: 0046 R15: 810501ac
[  124.046016] FS:  7f80d3efa800() GS:88003fc0() 
knlGS:
[  124.046016] CS:  0010 DS:  ES:  CR0: 80050033
[  124.046016] CR2: 7f3f04f8c000 CR3: 3cd41000 CR4: 06b0
[  124.046016] Stack:
[  124.046016]  95f3 88003d747800 fffbfc40 
05160010
[  124.046016]  88003cd51e30   
88003d92c970
[  124.046016]  8105b3a6 dead00100100 dead00200200 
88003d747860
[  124.046016] Call Trace:
[  124.046016]  [8105b3a6] ? wake_up_state+0x12/0x12
[  124.046016]  [8108b6cb] audit_log_name+0x34/0x1a2
[  124.046016]  [8136f52b] ? _raw_spin_unlock_irqrestore+0x34/0x48
[  124.046016]  [8108ebe8] audit_log_exit+0xa44/0xa8f
[  124.046016]  [8108e07e] ? rcu_read_unlock+0x1c/0x2d
[  124.046016]  [8108efe8] ? audit_filter_inodes+0xf5/0x10e
[  124.046016]  [8108e17d] ? audit_filter_syscall+0xb2/0xd9
[  124.046016]  [8108f374] __audit_syscall_exit+0x4d/0x108
[  124.046016]  [813709c5] sysret_audit+0x17/0x21
[  124.046016] Code: e7 8b 05 1c ed 59 00 8b 0d 12 ed 59 00 8b 35 1c 24 e1 00 
46 8d 04 30 48 63 f9 85 c0 0f 84 29 01 00 00 44 39 c6 0f 86 20 01 00 00 83 7c 
24 18 00 0f 84 a4 00 00 00 85 c9 0f 84 9c 00 00 00 48 8b

This is what happens:

 1. The readahead-collector daemon got stuck and stops reading
from the netlink socket
 2. The kernel keeps logging stuff to the audit subsystem at
a high rate
 3. Because kauditd's call to netlink_unicast() is blocking and
as the netlink socket got a backlog, the kaudit thread will
eventually get blocked when trying to send an SKB to user-space
 4. As the kaudit thread is blocked, SKBs start to accumulate.
This will cause a thread calling audit_log_start() to
be put to sleep when a threshold of queued SBKs is reached
 5. The kaudit thread never wakes up, but the kernel thread
put to sleep in step 4 does. Soon or later sleep_time will be
negative, causing it to busy-wait in the while() loop

This commit fixes that problem by making the call to netlink_unicast()
non-blocking in kaudit_send_skb(). This way the kaudit thread
never gets blocked, completely avoiding the scenario described above.

Signed-off-by: Luiz capitulino lcapitul...@redhat.com
---
 kernel/audit.c | 8 ++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/kernel/audit.c b/kernel/audit.c
index 475c1d1..2b34bd6 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -385,8 +385,12 @@ static int kauditd_send_skb(struct sk_buff *skb)
int err;
/* take a reference in case we can't send it and we want to hold it */
skb_get(skb);
-   err = netlink_unicast(audit_sock, skb, audit_nlk_portid, 0);
-   if (err  0) {
+   err = netlink_unicast(audit_sock, skb, audit_nlk_portid, 1);
+   if (err == -EAGAIN) {
+   pr_warn_ratelimited(auditd (pid=%d) is not responding\n, 
audit_pid);
+   audit_hold_skb(skb);
+   return err;
+   } else if (err  0) {
BUG_ON(err != -ECONNREFUSED); /* Shouldn't happen */
printk(KERN_ERR audit: *NO* daemon at audit_pid=%d\n, 
audit_pid);
audit_log_lost(auditd disappeared\n);
-- 
1.8.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/