diff options
-rw-r--r-- | kernel/audit.c | 62 | ||||
-rw-r--r-- | kernel/audit.h | 11 | ||||
-rw-r--r-- | kernel/auditfilter.c | 60 |
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 | ||
369 | int 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 | |||
387 | struct 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 | |||
407 | nlmsg_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 | |||
406 | nlmsg_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 { | |||
82 | extern int audit_pid; | 83 | extern int audit_pid; |
83 | extern int audit_comparator(const u32 left, const u32 op, const u32 right); | 84 | extern int audit_comparator(const u32 left, const u32 op, const u32 right); |
84 | 85 | ||
86 | extern struct sk_buff * audit_make_reply(int pid, int seq, int type, | ||
87 | int done, int multi, | ||
88 | void *payload, int size); | ||
85 | extern void audit_send_reply(int pid, int seq, int type, | 89 | extern 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); | |||
89 | extern void audit_panic(const char *message); | 93 | extern void audit_panic(const char *message); |
90 | extern struct mutex audit_netlink_mutex; | 94 | extern struct mutex audit_netlink_mutex; |
91 | 95 | ||
96 | struct audit_netlink_list { | ||
97 | int pid; | ||
98 | struct sk_buff_head q; | ||
99 | }; | ||
100 | |||
101 | int audit_send_list(void *); | ||
102 | |||
92 | extern int selinux_audit_rule_update(void); | 103 | extern 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. */ |
513 | static int audit_list(void *_dest) | 513 | static 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. */ |
547 | static int audit_list_rules(void *_dest) | 541 | static 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 | } |