diff options
Diffstat (limited to 'kernel/audit.c')
-rw-r--r-- | kernel/audit.c | 102 |
1 files changed, 81 insertions, 21 deletions
diff --git a/kernel/audit.c b/kernel/audit.c index ad6d1abfa1d2..fee9052eb5cf 100644 --- a/kernel/audit.c +++ b/kernel/audit.c | |||
@@ -126,6 +126,8 @@ static int audit_freelist_count; | |||
126 | static LIST_HEAD(audit_freelist); | 126 | static LIST_HEAD(audit_freelist); |
127 | 127 | ||
128 | static struct sk_buff_head audit_skb_queue; | 128 | static struct sk_buff_head audit_skb_queue; |
129 | /* queue of skbs to send to auditd when/if it comes back */ | ||
130 | static struct sk_buff_head audit_skb_hold_queue; | ||
129 | static struct task_struct *kauditd_task; | 131 | static struct task_struct *kauditd_task; |
130 | static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait); | 132 | static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait); |
131 | static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait); | 133 | static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait); |
@@ -347,30 +349,83 @@ static int audit_set_failure(int state, uid_t loginuid, u32 sessionid, u32 sid) | |||
347 | loginuid, sessionid, sid); | 349 | loginuid, sessionid, sid); |
348 | } | 350 | } |
349 | 351 | ||
352 | /* | ||
353 | * Queue skbs to be sent to auditd when/if it comes back. These skbs should | ||
354 | * already have been sent via prink/syslog and so if these messages are dropped | ||
355 | * it is not a huge concern since we already passed the audit_log_lost() | ||
356 | * notification and stuff. This is just nice to get audit messages during | ||
357 | * boot before auditd is running or messages generated while auditd is stopped. | ||
358 | * This only holds messages is audit_default is set, aka booting with audit=1 | ||
359 | * or building your kernel that way. | ||
360 | */ | ||
361 | static void audit_hold_skb(struct sk_buff *skb) | ||
362 | { | ||
363 | if (audit_default && | ||
364 | skb_queue_len(&audit_skb_hold_queue) < audit_backlog_limit) | ||
365 | skb_queue_tail(&audit_skb_hold_queue, skb); | ||
366 | else | ||
367 | kfree_skb(skb); | ||
368 | } | ||
369 | |||
370 | static void kauditd_send_skb(struct sk_buff *skb) | ||
371 | { | ||
372 | int err; | ||
373 | /* take a reference in case we can't send it and we want to hold it */ | ||
374 | skb_get(skb); | ||
375 | err = netlink_unicast(audit_sock, skb, audit_nlk_pid, 0); | ||
376 | if (err < 0) { | ||
377 | BUG_ON(err != -ECONNREFUSED); /* Shoudn't happen */ | ||
378 | printk(KERN_ERR "audit: *NO* daemon at audit_pid=%d\n", audit_pid); | ||
379 | audit_log_lost("auditd dissapeared\n"); | ||
380 | audit_pid = 0; | ||
381 | /* we might get lucky and get this in the next auditd */ | ||
382 | audit_hold_skb(skb); | ||
383 | } else | ||
384 | /* drop the extra reference if sent ok */ | ||
385 | kfree_skb(skb); | ||
386 | } | ||
387 | |||
350 | static int kauditd_thread(void *dummy) | 388 | static int kauditd_thread(void *dummy) |
351 | { | 389 | { |
352 | struct sk_buff *skb; | 390 | struct sk_buff *skb; |
353 | 391 | ||
354 | set_freezable(); | 392 | set_freezable(); |
355 | while (!kthread_should_stop()) { | 393 | while (!kthread_should_stop()) { |
394 | /* | ||
395 | * if auditd just started drain the queue of messages already | ||
396 | * sent to syslog/printk. remember loss here is ok. we already | ||
397 | * called audit_log_lost() if it didn't go out normally. so the | ||
398 | * race between the skb_dequeue and the next check for audit_pid | ||
399 | * doesn't matter. | ||
400 | * | ||
401 | * if you ever find kauditd to be too slow we can get a perf win | ||
402 | * by doing our own locking and keeping better track if there | ||
403 | * are messages in this queue. I don't see the need now, but | ||
404 | * in 5 years when I want to play with this again I'll see this | ||
405 | * note and still have no friggin idea what i'm thinking today. | ||
406 | */ | ||
407 | if (audit_default && audit_pid) { | ||
408 | skb = skb_dequeue(&audit_skb_hold_queue); | ||
409 | if (unlikely(skb)) { | ||
410 | while (skb && audit_pid) { | ||
411 | kauditd_send_skb(skb); | ||
412 | skb = skb_dequeue(&audit_skb_hold_queue); | ||
413 | } | ||
414 | } | ||
415 | } | ||
416 | |||
356 | skb = skb_dequeue(&audit_skb_queue); | 417 | skb = skb_dequeue(&audit_skb_queue); |
357 | wake_up(&audit_backlog_wait); | 418 | wake_up(&audit_backlog_wait); |
358 | if (skb) { | 419 | if (skb) { |
359 | if (audit_pid) { | 420 | if (audit_pid) |
360 | int err = netlink_unicast(audit_sock, skb, audit_nlk_pid, 0); | 421 | kauditd_send_skb(skb); |
361 | if (err < 0) { | 422 | else { |
362 | BUG_ON(err != -ECONNREFUSED); /* Shoudn't happen */ | ||
363 | printk(KERN_ERR "audit: *NO* daemon at audit_pid=%d\n", audit_pid); | ||
364 | audit_log_lost("auditd dissapeared\n"); | ||
365 | audit_pid = 0; | ||
366 | } | ||
367 | } else { | ||
368 | if (printk_ratelimit()) | 423 | if (printk_ratelimit()) |
369 | printk(KERN_NOTICE "%s\n", skb->data + | 424 | printk(KERN_NOTICE "%s\n", skb->data + NLMSG_SPACE(0)); |
370 | NLMSG_SPACE(0)); | ||
371 | else | 425 | else |
372 | audit_log_lost("printk limit exceeded\n"); | 426 | audit_log_lost("printk limit exceeded\n"); |
373 | kfree_skb(skb); | 427 | |
428 | audit_hold_skb(skb); | ||
374 | } | 429 | } |
375 | } else { | 430 | } else { |
376 | DECLARE_WAITQUEUE(wait, current); | 431 | DECLARE_WAITQUEUE(wait, current); |
@@ -885,6 +940,7 @@ static int __init audit_init(void) | |||
885 | audit_sock->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT; | 940 | audit_sock->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT; |
886 | 941 | ||
887 | skb_queue_head_init(&audit_skb_queue); | 942 | skb_queue_head_init(&audit_skb_queue); |
943 | skb_queue_head_init(&audit_skb_hold_queue); | ||
888 | audit_initialized = 1; | 944 | audit_initialized = 1; |
889 | audit_enabled = audit_default; | 945 | audit_enabled = audit_default; |
890 | audit_ever_enabled |= !!audit_default; | 946 | audit_ever_enabled |= !!audit_default; |
@@ -1363,19 +1419,23 @@ void audit_log_end(struct audit_buffer *ab) | |||
1363 | audit_log_lost("rate limit exceeded"); | 1419 | audit_log_lost("rate limit exceeded"); |
1364 | } else { | 1420 | } else { |
1365 | struct nlmsghdr *nlh = nlmsg_hdr(ab->skb); | 1421 | struct nlmsghdr *nlh = nlmsg_hdr(ab->skb); |
1422 | nlh->nlmsg_len = ab->skb->len - NLMSG_SPACE(0); | ||
1423 | |||
1366 | if (audit_pid) { | 1424 | if (audit_pid) { |
1367 | nlh->nlmsg_len = ab->skb->len - NLMSG_SPACE(0); | ||
1368 | skb_queue_tail(&audit_skb_queue, ab->skb); | 1425 | skb_queue_tail(&audit_skb_queue, ab->skb); |
1369 | ab->skb = NULL; | ||
1370 | wake_up_interruptible(&kauditd_wait); | 1426 | wake_up_interruptible(&kauditd_wait); |
1371 | } else if (nlh->nlmsg_type != AUDIT_EOE) { | 1427 | } else { |
1372 | if (printk_ratelimit()) { | 1428 | if (nlh->nlmsg_type != AUDIT_EOE) { |
1373 | printk(KERN_NOTICE "type=%d %s\n", | 1429 | if (printk_ratelimit()) { |
1374 | nlh->nlmsg_type, | 1430 | printk(KERN_NOTICE "type=%d %s\n", |
1375 | ab->skb->data + NLMSG_SPACE(0)); | 1431 | nlh->nlmsg_type, |
1376 | } else | 1432 | ab->skb->data + NLMSG_SPACE(0)); |
1377 | audit_log_lost("printk limit exceeded\n"); | 1433 | } else |
1434 | audit_log_lost("printk limit exceeded\n"); | ||
1435 | } | ||
1436 | audit_hold_skb(ab->skb); | ||
1378 | } | 1437 | } |
1438 | ab->skb = NULL; | ||
1379 | } | 1439 | } |
1380 | audit_buffer_free(ab); | 1440 | audit_buffer_free(ab); |
1381 | } | 1441 | } |