aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2006-05-22 01:09:24 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2006-06-20 05:25:20 -0400
commit9044e6bca5a4a575d3c068dfccb5651a2d6a13bc (patch)
treee0fa2beb83c3ef4e52cc6c6b28ce3173656f4276 /kernel
parentbc0f3b8ebba611291fdaa2864dbffd2d29336c64 (diff)
[PATCH] fix deadlocks in AUDIT_LIST/AUDIT_LIST_RULES
We should not send a pile of replies while holding audit_netlink_mutex since we hold the same mutex when we receive commands. As the result, we can get blocked while sending and sit there holding the mutex while auditctl is unable to send the next command and get around to receiving what we'd sent. Solution: create skb and put them into a queue instead of sending; once we are done, send what we've got on the list. The former can be done synchronously while we are handling AUDIT_LIST or AUDIT_LIST_RULES; we are holding audit_netlink_mutex at that point. The latter is done asynchronously and without messing with audit_netlink_mutex. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/audit.c62
-rw-r--r--kernel/audit.h11
-rw-r--r--kernel/auditfilter.c60
3 files changed, 81 insertions, 52 deletions
diff --git a/kernel/audit.c b/kernel/audit.c
index df57b493e1cb..bf74bf02aa4b 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -366,6 +366,50 @@ static int kauditd_thread(void *dummy)
366 return 0; 366 return 0;
367} 367}
368 368
369int audit_send_list(void *_dest)
370{
371 struct audit_netlink_list *dest = _dest;
372 int pid = dest->pid;
373 struct sk_buff *skb;
374
375 /* wait for parent to finish and send an ACK */
376 mutex_lock(&audit_netlink_mutex);
377 mutex_unlock(&audit_netlink_mutex);
378
379 while ((skb = __skb_dequeue(&dest->q)) != NULL)
380 netlink_unicast(audit_sock, skb, pid, 0);
381
382 kfree(dest);
383
384 return 0;
385}
386
387struct sk_buff *audit_make_reply(int pid, int seq, int type, int done,
388 int multi, void *payload, int size)
389{
390 struct sk_buff *skb;
391 struct nlmsghdr *nlh;
392 int len = NLMSG_SPACE(size);
393 void *data;
394 int flags = multi ? NLM_F_MULTI : 0;
395 int t = done ? NLMSG_DONE : type;
396
397 skb = alloc_skb(len, GFP_KERNEL);
398 if (!skb)
399 return NULL;
400
401 nlh = NLMSG_PUT(skb, pid, seq, t, size);
402 nlh->nlmsg_flags = flags;
403 data = NLMSG_DATA(nlh);
404 memcpy(data, payload, size);
405 return skb;
406
407nlmsg_failure: /* Used by NLMSG_PUT */
408 if (skb)
409 kfree_skb(skb);
410 return NULL;
411}
412
369/** 413/**
370 * audit_send_reply - send an audit reply message via netlink 414 * audit_send_reply - send an audit reply message via netlink
371 * @pid: process id to send reply to 415 * @pid: process id to send reply to
@@ -383,29 +427,13 @@ void audit_send_reply(int pid, int seq, int type, int done, int multi,
383 void *payload, int size) 427 void *payload, int size)
384{ 428{
385 struct sk_buff *skb; 429 struct sk_buff *skb;
386 struct nlmsghdr *nlh; 430 skb = audit_make_reply(pid, seq, type, done, multi, payload, size);
387 int len = NLMSG_SPACE(size);
388 void *data;
389 int flags = multi ? NLM_F_MULTI : 0;
390 int t = done ? NLMSG_DONE : type;
391
392 skb = alloc_skb(len, GFP_KERNEL);
393 if (!skb) 431 if (!skb)
394 return; 432 return;
395
396 nlh = NLMSG_PUT(skb, pid, seq, t, size);
397 nlh->nlmsg_flags = flags;
398 data = NLMSG_DATA(nlh);
399 memcpy(data, payload, size);
400
401 /* Ignore failure. It'll only happen if the sender goes away, 433 /* Ignore failure. It'll only happen if the sender goes away,
402 because our timeout is set to infinite. */ 434 because our timeout is set to infinite. */
403 netlink_unicast(audit_sock, skb, pid, 0); 435 netlink_unicast(audit_sock, skb, pid, 0);
404 return; 436 return;
405
406nlmsg_failure: /* Used by NLMSG_PUT */
407 if (skb)
408 kfree_skb(skb);
409} 437}
410 438
411/* 439/*
diff --git a/kernel/audit.h b/kernel/audit.h
index 6f733920fd32..8948fc1e9e54 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -22,6 +22,7 @@
22#include <linux/mutex.h> 22#include <linux/mutex.h>
23#include <linux/fs.h> 23#include <linux/fs.h>
24#include <linux/audit.h> 24#include <linux/audit.h>
25#include <linux/skbuff.h>
25 26
26/* 0 = no checking 27/* 0 = no checking
27 1 = put_count checking 28 1 = put_count checking
@@ -82,6 +83,9 @@ struct audit_entry {
82extern int audit_pid; 83extern int audit_pid;
83extern int audit_comparator(const u32 left, const u32 op, const u32 right); 84extern int audit_comparator(const u32 left, const u32 op, const u32 right);
84 85
86extern struct sk_buff * audit_make_reply(int pid, int seq, int type,
87 int done, int multi,
88 void *payload, int size);
85extern void audit_send_reply(int pid, int seq, int type, 89extern void audit_send_reply(int pid, int seq, int type,
86 int done, int multi, 90 int done, int multi,
87 void *payload, int size); 91 void *payload, int size);
@@ -89,4 +93,11 @@ extern void audit_log_lost(const char *message);
89extern void audit_panic(const char *message); 93extern void audit_panic(const char *message);
90extern struct mutex audit_netlink_mutex; 94extern struct mutex audit_netlink_mutex;
91 95
96struct audit_netlink_list {
97 int pid;
98 struct sk_buff_head q;
99};
100
101int audit_send_list(void *);
102
92extern int selinux_audit_rule_update(void); 103extern int selinux_audit_rule_update(void);
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 7c134906d689..ccfea6d82cc3 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -510,19 +510,12 @@ static inline int audit_del_rule(struct audit_entry *entry,
510 510
511/* List rules using struct audit_rule. Exists for backward 511/* List rules using struct audit_rule. Exists for backward
512 * compatibility with userspace. */ 512 * compatibility with userspace. */
513static int audit_list(void *_dest) 513static void audit_list(int pid, int seq, struct sk_buff_head *q)
514{ 514{
515 int pid, seq; 515 struct sk_buff *skb;
516 int *dest = _dest;
517 struct audit_entry *entry; 516 struct audit_entry *entry;
518 int i; 517 int i;
519 518
520 pid = dest[0];
521 seq = dest[1];
522 kfree(dest);
523
524 mutex_lock(&audit_netlink_mutex);
525
526 /* The *_rcu iterators not needed here because we are 519 /* The *_rcu iterators not needed here because we are
527 always called with audit_netlink_mutex held. */ 520 always called with audit_netlink_mutex held. */
528 for (i=0; i<AUDIT_NR_FILTERS; i++) { 521 for (i=0; i<AUDIT_NR_FILTERS; i++) {
@@ -532,31 +525,25 @@ static int audit_list(void *_dest)
532 rule = audit_krule_to_rule(&entry->rule); 525 rule = audit_krule_to_rule(&entry->rule);
533 if (unlikely(!rule)) 526 if (unlikely(!rule))
534 break; 527 break;
535 audit_send_reply(pid, seq, AUDIT_LIST, 0, 1, 528 skb = audit_make_reply(pid, seq, AUDIT_LIST, 0, 1,
536 rule, sizeof(*rule)); 529 rule, sizeof(*rule));
530 if (skb)
531 skb_queue_tail(q, skb);
537 kfree(rule); 532 kfree(rule);
538 } 533 }
539 } 534 }
540 audit_send_reply(pid, seq, AUDIT_LIST, 1, 1, NULL, 0); 535 skb = audit_make_reply(pid, seq, AUDIT_LIST, 1, 1, NULL, 0);
541 536 if (skb)
542 mutex_unlock(&audit_netlink_mutex); 537 skb_queue_tail(q, skb);
543 return 0;
544} 538}
545 539
546/* List rules using struct audit_rule_data. */ 540/* List rules using struct audit_rule_data. */
547static int audit_list_rules(void *_dest) 541static void audit_list_rules(int pid, int seq, struct sk_buff_head *q)
548{ 542{
549 int pid, seq; 543 struct sk_buff *skb;
550 int *dest = _dest;
551 struct audit_entry *e; 544 struct audit_entry *e;
552 int i; 545 int i;
553 546
554 pid = dest[0];
555 seq = dest[1];
556 kfree(dest);
557
558 mutex_lock(&audit_netlink_mutex);
559
560 /* The *_rcu iterators not needed here because we are 547 /* The *_rcu iterators not needed here because we are
561 always called with audit_netlink_mutex held. */ 548 always called with audit_netlink_mutex held. */
562 for (i=0; i<AUDIT_NR_FILTERS; i++) { 549 for (i=0; i<AUDIT_NR_FILTERS; i++) {
@@ -566,15 +553,16 @@ static int audit_list_rules(void *_dest)
566 data = audit_krule_to_data(&e->rule); 553 data = audit_krule_to_data(&e->rule);
567 if (unlikely(!data)) 554 if (unlikely(!data))
568 break; 555 break;
569 audit_send_reply(pid, seq, AUDIT_LIST_RULES, 0, 1, 556 skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 0, 1,
570 data, sizeof(*data)); 557 data, sizeof(*data));
558 if (skb)
559 skb_queue_tail(q, skb);
571 kfree(data); 560 kfree(data);
572 } 561 }
573 } 562 }
574 audit_send_reply(pid, seq, AUDIT_LIST_RULES, 1, 1, NULL, 0); 563 skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 1, 1, NULL, 0);
575 564 if (skb)
576 mutex_unlock(&audit_netlink_mutex); 565 skb_queue_tail(q, skb);
577 return 0;
578} 566}
579 567
580/** 568/**
@@ -592,7 +580,7 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
592 size_t datasz, uid_t loginuid, u32 sid) 580 size_t datasz, uid_t loginuid, u32 sid)
593{ 581{
594 struct task_struct *tsk; 582 struct task_struct *tsk;
595 int *dest; 583 struct audit_netlink_list *dest;
596 int err = 0; 584 int err = 0;
597 struct audit_entry *entry; 585 struct audit_entry *entry;
598 586
@@ -605,18 +593,20 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
605 * happen if we're actually running in the context of auditctl 593 * happen if we're actually running in the context of auditctl
606 * trying to _send_ the stuff */ 594 * trying to _send_ the stuff */
607 595
608 dest = kmalloc(2 * sizeof(int), GFP_KERNEL); 596 dest = kmalloc(sizeof(struct audit_netlink_list), GFP_KERNEL);
609 if (!dest) 597 if (!dest)
610 return -ENOMEM; 598 return -ENOMEM;
611 dest[0] = pid; 599 dest->pid = pid;
612 dest[1] = seq; 600 skb_queue_head_init(&dest->q);
613 601
614 if (type == AUDIT_LIST) 602 if (type == AUDIT_LIST)
615 tsk = kthread_run(audit_list, dest, "audit_list"); 603 audit_list(pid, seq, &dest->q);
616 else 604 else
617 tsk = kthread_run(audit_list_rules, dest, 605 audit_list_rules(pid, seq, &dest->q);
618 "audit_list_rules"); 606
607 tsk = kthread_run(audit_send_list, dest, "audit_send_list");
619 if (IS_ERR(tsk)) { 608 if (IS_ERR(tsk)) {
609 skb_queue_purge(&dest->q);
620 kfree(dest); 610 kfree(dest);
621 err = PTR_ERR(tsk); 611 err = PTR_ERR(tsk);
622 } 612 }