aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/auditfilter.c
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/auditfilter.c
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/auditfilter.c')
-rw-r--r--kernel/auditfilter.c60
1 files changed, 25 insertions, 35 deletions
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 }