diff options
Diffstat (limited to 'kernel/audit.c')
-rw-r--r-- | kernel/audit.c | 205 |
1 files changed, 158 insertions, 47 deletions
diff --git a/kernel/audit.c b/kernel/audit.c index df57b493e1cb..7dfac7031bd7 100644 --- a/kernel/audit.c +++ b/kernel/audit.c | |||
@@ -56,6 +56,7 @@ | |||
56 | #include <linux/skbuff.h> | 56 | #include <linux/skbuff.h> |
57 | #include <linux/netlink.h> | 57 | #include <linux/netlink.h> |
58 | #include <linux/selinux.h> | 58 | #include <linux/selinux.h> |
59 | #include <linux/inotify.h> | ||
59 | 60 | ||
60 | #include "audit.h" | 61 | #include "audit.h" |
61 | 62 | ||
@@ -89,6 +90,7 @@ static int audit_backlog_wait_overflow = 0; | |||
89 | /* The identity of the user shutting down the audit system. */ | 90 | /* The identity of the user shutting down the audit system. */ |
90 | uid_t audit_sig_uid = -1; | 91 | uid_t audit_sig_uid = -1; |
91 | pid_t audit_sig_pid = -1; | 92 | pid_t audit_sig_pid = -1; |
93 | u32 audit_sig_sid = 0; | ||
92 | 94 | ||
93 | /* Records can be lost in several ways: | 95 | /* Records can be lost in several ways: |
94 | 0) [suppressed in audit_alloc] | 96 | 0) [suppressed in audit_alloc] |
@@ -102,6 +104,12 @@ static atomic_t audit_lost = ATOMIC_INIT(0); | |||
102 | /* The netlink socket. */ | 104 | /* The netlink socket. */ |
103 | static struct sock *audit_sock; | 105 | static struct sock *audit_sock; |
104 | 106 | ||
107 | /* Inotify handle. */ | ||
108 | struct inotify_handle *audit_ih; | ||
109 | |||
110 | /* Hash for inode-based rules */ | ||
111 | struct list_head audit_inode_hash[AUDIT_INODE_BUCKETS]; | ||
112 | |||
105 | /* The audit_freelist is a list of pre-allocated audit buffers (if more | 113 | /* The audit_freelist is a list of pre-allocated audit buffers (if more |
106 | * than AUDIT_MAXFREE are in use, the audit buffer is freed instead of | 114 | * than AUDIT_MAXFREE are in use, the audit buffer is freed instead of |
107 | * being placed on the freelist). */ | 115 | * being placed on the freelist). */ |
@@ -114,10 +122,8 @@ static struct task_struct *kauditd_task; | |||
114 | static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait); | 122 | static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait); |
115 | static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait); | 123 | static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait); |
116 | 124 | ||
117 | /* The netlink socket is only to be read by 1 CPU, which lets us assume | 125 | /* Serialize requests from userspace. */ |
118 | * that list additions and deletions never happen simultaneously in | 126 | static DEFINE_MUTEX(audit_cmd_mutex); |
119 | * auditsc.c */ | ||
120 | DEFINE_MUTEX(audit_netlink_mutex); | ||
121 | 127 | ||
122 | /* AUDIT_BUFSIZ is the size of the temporary buffer used for formatting | 128 | /* AUDIT_BUFSIZ is the size of the temporary buffer used for formatting |
123 | * audit records. Since printk uses a 1024 byte buffer, this buffer | 129 | * audit records. Since printk uses a 1024 byte buffer, this buffer |
@@ -250,7 +256,7 @@ static int audit_set_rate_limit(int limit, uid_t loginuid, u32 sid) | |||
250 | "audit_rate_limit=%d old=%d by auid=%u", | 256 | "audit_rate_limit=%d old=%d by auid=%u", |
251 | limit, old, loginuid); | 257 | limit, old, loginuid); |
252 | audit_rate_limit = limit; | 258 | audit_rate_limit = limit; |
253 | return old; | 259 | return 0; |
254 | } | 260 | } |
255 | 261 | ||
256 | static int audit_set_backlog_limit(int limit, uid_t loginuid, u32 sid) | 262 | static int audit_set_backlog_limit(int limit, uid_t loginuid, u32 sid) |
@@ -273,7 +279,7 @@ static int audit_set_backlog_limit(int limit, uid_t loginuid, u32 sid) | |||
273 | "audit_backlog_limit=%d old=%d by auid=%u", | 279 | "audit_backlog_limit=%d old=%d by auid=%u", |
274 | limit, old, loginuid); | 280 | limit, old, loginuid); |
275 | audit_backlog_limit = limit; | 281 | audit_backlog_limit = limit; |
276 | return old; | 282 | return 0; |
277 | } | 283 | } |
278 | 284 | ||
279 | static int audit_set_enabled(int state, uid_t loginuid, u32 sid) | 285 | static int audit_set_enabled(int state, uid_t loginuid, u32 sid) |
@@ -299,7 +305,7 @@ static int audit_set_enabled(int state, uid_t loginuid, u32 sid) | |||
299 | "audit_enabled=%d old=%d by auid=%u", | 305 | "audit_enabled=%d old=%d by auid=%u", |
300 | state, old, loginuid); | 306 | state, old, loginuid); |
301 | audit_enabled = state; | 307 | audit_enabled = state; |
302 | return old; | 308 | return 0; |
303 | } | 309 | } |
304 | 310 | ||
305 | static int audit_set_failure(int state, uid_t loginuid, u32 sid) | 311 | static int audit_set_failure(int state, uid_t loginuid, u32 sid) |
@@ -327,7 +333,7 @@ static int audit_set_failure(int state, uid_t loginuid, u32 sid) | |||
327 | "audit_failure=%d old=%d by auid=%u", | 333 | "audit_failure=%d old=%d by auid=%u", |
328 | state, old, loginuid); | 334 | state, old, loginuid); |
329 | audit_failure = state; | 335 | audit_failure = state; |
330 | return old; | 336 | return 0; |
331 | } | 337 | } |
332 | 338 | ||
333 | static int kauditd_thread(void *dummy) | 339 | static int kauditd_thread(void *dummy) |
@@ -363,9 +369,52 @@ static int kauditd_thread(void *dummy) | |||
363 | remove_wait_queue(&kauditd_wait, &wait); | 369 | remove_wait_queue(&kauditd_wait, &wait); |
364 | } | 370 | } |
365 | } | 371 | } |
372 | } | ||
373 | |||
374 | int audit_send_list(void *_dest) | ||
375 | { | ||
376 | struct audit_netlink_list *dest = _dest; | ||
377 | int pid = dest->pid; | ||
378 | struct sk_buff *skb; | ||
379 | |||
380 | /* wait for parent to finish and send an ACK */ | ||
381 | mutex_lock(&audit_cmd_mutex); | ||
382 | mutex_unlock(&audit_cmd_mutex); | ||
383 | |||
384 | while ((skb = __skb_dequeue(&dest->q)) != NULL) | ||
385 | netlink_unicast(audit_sock, skb, pid, 0); | ||
386 | |||
387 | kfree(dest); | ||
388 | |||
366 | return 0; | 389 | return 0; |
367 | } | 390 | } |
368 | 391 | ||
392 | struct sk_buff *audit_make_reply(int pid, int seq, int type, int done, | ||
393 | int multi, void *payload, int size) | ||
394 | { | ||
395 | struct sk_buff *skb; | ||
396 | struct nlmsghdr *nlh; | ||
397 | int len = NLMSG_SPACE(size); | ||
398 | void *data; | ||
399 | int flags = multi ? NLM_F_MULTI : 0; | ||
400 | int t = done ? NLMSG_DONE : type; | ||
401 | |||
402 | skb = alloc_skb(len, GFP_KERNEL); | ||
403 | if (!skb) | ||
404 | return NULL; | ||
405 | |||
406 | nlh = NLMSG_PUT(skb, pid, seq, t, size); | ||
407 | nlh->nlmsg_flags = flags; | ||
408 | data = NLMSG_DATA(nlh); | ||
409 | memcpy(data, payload, size); | ||
410 | return skb; | ||
411 | |||
412 | nlmsg_failure: /* Used by NLMSG_PUT */ | ||
413 | if (skb) | ||
414 | kfree_skb(skb); | ||
415 | return NULL; | ||
416 | } | ||
417 | |||
369 | /** | 418 | /** |
370 | * audit_send_reply - send an audit reply message via netlink | 419 | * audit_send_reply - send an audit reply message via netlink |
371 | * @pid: process id to send reply to | 420 | * @pid: process id to send reply to |
@@ -383,29 +432,13 @@ void audit_send_reply(int pid, int seq, int type, int done, int multi, | |||
383 | void *payload, int size) | 432 | void *payload, int size) |
384 | { | 433 | { |
385 | struct sk_buff *skb; | 434 | struct sk_buff *skb; |
386 | struct nlmsghdr *nlh; | 435 | 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) | 436 | if (!skb) |
394 | return; | 437 | 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, | 438 | /* Ignore failure. It'll only happen if the sender goes away, |
402 | because our timeout is set to infinite. */ | 439 | because our timeout is set to infinite. */ |
403 | netlink_unicast(audit_sock, skb, pid, 0); | 440 | netlink_unicast(audit_sock, skb, pid, 0); |
404 | return; | 441 | return; |
405 | |||
406 | nlmsg_failure: /* Used by NLMSG_PUT */ | ||
407 | if (skb) | ||
408 | kfree_skb(skb); | ||
409 | } | 442 | } |
410 | 443 | ||
411 | /* | 444 | /* |
@@ -451,7 +484,9 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
451 | struct audit_buffer *ab; | 484 | struct audit_buffer *ab; |
452 | u16 msg_type = nlh->nlmsg_type; | 485 | u16 msg_type = nlh->nlmsg_type; |
453 | uid_t loginuid; /* loginuid of sender */ | 486 | uid_t loginuid; /* loginuid of sender */ |
454 | struct audit_sig_info sig_data; | 487 | struct audit_sig_info *sig_data; |
488 | char *ctx; | ||
489 | u32 len; | ||
455 | 490 | ||
456 | err = audit_netlink_ok(NETLINK_CB(skb).eff_cap, msg_type); | 491 | err = audit_netlink_ok(NETLINK_CB(skb).eff_cap, msg_type); |
457 | if (err) | 492 | if (err) |
@@ -503,12 +538,9 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
503 | if (status_get->mask & AUDIT_STATUS_PID) { | 538 | if (status_get->mask & AUDIT_STATUS_PID) { |
504 | int old = audit_pid; | 539 | int old = audit_pid; |
505 | if (sid) { | 540 | if (sid) { |
506 | char *ctx = NULL; | 541 | if ((err = selinux_ctxid_to_string( |
507 | u32 len; | ||
508 | int rc; | ||
509 | if ((rc = selinux_ctxid_to_string( | ||
510 | sid, &ctx, &len))) | 542 | sid, &ctx, &len))) |
511 | return rc; | 543 | return err; |
512 | else | 544 | else |
513 | audit_log(NULL, GFP_KERNEL, | 545 | audit_log(NULL, GFP_KERNEL, |
514 | AUDIT_CONFIG_CHANGE, | 546 | AUDIT_CONFIG_CHANGE, |
@@ -523,10 +555,10 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
523 | audit_pid = status_get->pid; | 555 | audit_pid = status_get->pid; |
524 | } | 556 | } |
525 | if (status_get->mask & AUDIT_STATUS_RATE_LIMIT) | 557 | if (status_get->mask & AUDIT_STATUS_RATE_LIMIT) |
526 | audit_set_rate_limit(status_get->rate_limit, | 558 | err = audit_set_rate_limit(status_get->rate_limit, |
527 | loginuid, sid); | 559 | loginuid, sid); |
528 | if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT) | 560 | if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT) |
529 | audit_set_backlog_limit(status_get->backlog_limit, | 561 | err = audit_set_backlog_limit(status_get->backlog_limit, |
530 | loginuid, sid); | 562 | loginuid, sid); |
531 | break; | 563 | break; |
532 | case AUDIT_USER: | 564 | case AUDIT_USER: |
@@ -544,8 +576,6 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
544 | "user pid=%d uid=%u auid=%u", | 576 | "user pid=%d uid=%u auid=%u", |
545 | pid, uid, loginuid); | 577 | pid, uid, loginuid); |
546 | if (sid) { | 578 | if (sid) { |
547 | char *ctx = NULL; | ||
548 | u32 len; | ||
549 | if (selinux_ctxid_to_string( | 579 | if (selinux_ctxid_to_string( |
550 | sid, &ctx, &len)) { | 580 | sid, &ctx, &len)) { |
551 | audit_log_format(ab, | 581 | audit_log_format(ab, |
@@ -584,10 +614,21 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
584 | loginuid, sid); | 614 | loginuid, sid); |
585 | break; | 615 | break; |
586 | case AUDIT_SIGNAL_INFO: | 616 | case AUDIT_SIGNAL_INFO: |
587 | sig_data.uid = audit_sig_uid; | 617 | err = selinux_ctxid_to_string(audit_sig_sid, &ctx, &len); |
588 | sig_data.pid = audit_sig_pid; | 618 | if (err) |
619 | return err; | ||
620 | sig_data = kmalloc(sizeof(*sig_data) + len, GFP_KERNEL); | ||
621 | if (!sig_data) { | ||
622 | kfree(ctx); | ||
623 | return -ENOMEM; | ||
624 | } | ||
625 | sig_data->uid = audit_sig_uid; | ||
626 | sig_data->pid = audit_sig_pid; | ||
627 | memcpy(sig_data->ctx, ctx, len); | ||
628 | kfree(ctx); | ||
589 | audit_send_reply(NETLINK_CB(skb).pid, seq, AUDIT_SIGNAL_INFO, | 629 | audit_send_reply(NETLINK_CB(skb).pid, seq, AUDIT_SIGNAL_INFO, |
590 | 0, 0, &sig_data, sizeof(sig_data)); | 630 | 0, 0, sig_data, sizeof(*sig_data) + len); |
631 | kfree(sig_data); | ||
591 | break; | 632 | break; |
592 | default: | 633 | default: |
593 | err = -EINVAL; | 634 | err = -EINVAL; |
@@ -629,20 +670,30 @@ static void audit_receive(struct sock *sk, int length) | |||
629 | struct sk_buff *skb; | 670 | struct sk_buff *skb; |
630 | unsigned int qlen; | 671 | unsigned int qlen; |
631 | 672 | ||
632 | mutex_lock(&audit_netlink_mutex); | 673 | mutex_lock(&audit_cmd_mutex); |
633 | 674 | ||
634 | for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) { | 675 | for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) { |
635 | skb = skb_dequeue(&sk->sk_receive_queue); | 676 | skb = skb_dequeue(&sk->sk_receive_queue); |
636 | audit_receive_skb(skb); | 677 | audit_receive_skb(skb); |
637 | kfree_skb(skb); | 678 | kfree_skb(skb); |
638 | } | 679 | } |
639 | mutex_unlock(&audit_netlink_mutex); | 680 | mutex_unlock(&audit_cmd_mutex); |
640 | } | 681 | } |
641 | 682 | ||
683 | #ifdef CONFIG_AUDITSYSCALL | ||
684 | static const struct inotify_operations audit_inotify_ops = { | ||
685 | .handle_event = audit_handle_ievent, | ||
686 | .destroy_watch = audit_free_parent, | ||
687 | }; | ||
688 | #endif | ||
642 | 689 | ||
643 | /* Initialize audit support at boot time. */ | 690 | /* Initialize audit support at boot time. */ |
644 | static int __init audit_init(void) | 691 | static int __init audit_init(void) |
645 | { | 692 | { |
693 | #ifdef CONFIG_AUDITSYSCALL | ||
694 | int i; | ||
695 | #endif | ||
696 | |||
646 | printk(KERN_INFO "audit: initializing netlink socket (%s)\n", | 697 | printk(KERN_INFO "audit: initializing netlink socket (%s)\n", |
647 | audit_default ? "enabled" : "disabled"); | 698 | audit_default ? "enabled" : "disabled"); |
648 | audit_sock = netlink_kernel_create(NETLINK_AUDIT, 0, audit_receive, | 699 | audit_sock = netlink_kernel_create(NETLINK_AUDIT, 0, audit_receive, |
@@ -661,6 +712,16 @@ static int __init audit_init(void) | |||
661 | selinux_audit_set_callback(&selinux_audit_rule_update); | 712 | selinux_audit_set_callback(&selinux_audit_rule_update); |
662 | 713 | ||
663 | audit_log(NULL, GFP_KERNEL, AUDIT_KERNEL, "initialized"); | 714 | audit_log(NULL, GFP_KERNEL, AUDIT_KERNEL, "initialized"); |
715 | |||
716 | #ifdef CONFIG_AUDITSYSCALL | ||
717 | audit_ih = inotify_init(&audit_inotify_ops); | ||
718 | if (IS_ERR(audit_ih)) | ||
719 | audit_panic("cannot initialize inotify handle"); | ||
720 | |||
721 | for (i = 0; i < AUDIT_INODE_BUCKETS; i++) | ||
722 | INIT_LIST_HEAD(&audit_inode_hash[i]); | ||
723 | #endif | ||
724 | |||
664 | return 0; | 725 | return 0; |
665 | } | 726 | } |
666 | __initcall(audit_init); | 727 | __initcall(audit_init); |
@@ -690,10 +751,12 @@ static void audit_buffer_free(struct audit_buffer *ab) | |||
690 | kfree_skb(ab->skb); | 751 | kfree_skb(ab->skb); |
691 | 752 | ||
692 | spin_lock_irqsave(&audit_freelist_lock, flags); | 753 | spin_lock_irqsave(&audit_freelist_lock, flags); |
693 | if (++audit_freelist_count > AUDIT_MAXFREE) | 754 | if (audit_freelist_count > AUDIT_MAXFREE) |
694 | kfree(ab); | 755 | kfree(ab); |
695 | else | 756 | else { |
757 | audit_freelist_count++; | ||
696 | list_add(&ab->list, &audit_freelist); | 758 | list_add(&ab->list, &audit_freelist); |
759 | } | ||
697 | spin_unlock_irqrestore(&audit_freelist_lock, flags); | 760 | spin_unlock_irqrestore(&audit_freelist_lock, flags); |
698 | } | 761 | } |
699 | 762 | ||
@@ -988,28 +1051,76 @@ void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf, | |||
988 | skb_put(skb, len << 1); /* new string is twice the old string */ | 1051 | skb_put(skb, len << 1); /* new string is twice the old string */ |
989 | } | 1052 | } |
990 | 1053 | ||
1054 | /* | ||
1055 | * Format a string of no more than slen characters into the audit buffer, | ||
1056 | * enclosed in quote marks. | ||
1057 | */ | ||
1058 | static void audit_log_n_string(struct audit_buffer *ab, size_t slen, | ||
1059 | const char *string) | ||
1060 | { | ||
1061 | int avail, new_len; | ||
1062 | unsigned char *ptr; | ||
1063 | struct sk_buff *skb; | ||
1064 | |||
1065 | BUG_ON(!ab->skb); | ||
1066 | skb = ab->skb; | ||
1067 | avail = skb_tailroom(skb); | ||
1068 | new_len = slen + 3; /* enclosing quotes + null terminator */ | ||
1069 | if (new_len > avail) { | ||
1070 | avail = audit_expand(ab, new_len); | ||
1071 | if (!avail) | ||
1072 | return; | ||
1073 | } | ||
1074 | ptr = skb->tail; | ||
1075 | *ptr++ = '"'; | ||
1076 | memcpy(ptr, string, slen); | ||
1077 | ptr += slen; | ||
1078 | *ptr++ = '"'; | ||
1079 | *ptr = 0; | ||
1080 | skb_put(skb, slen + 2); /* don't include null terminator */ | ||
1081 | } | ||
1082 | |||
991 | /** | 1083 | /** |
992 | * audit_log_unstrustedstring - log a string that may contain random characters | 1084 | * audit_log_n_unstrustedstring - log a string that may contain random characters |
993 | * @ab: audit_buffer | 1085 | * @ab: audit_buffer |
1086 | * @len: lenth of string (not including trailing null) | ||
994 | * @string: string to be logged | 1087 | * @string: string to be logged |
995 | * | 1088 | * |
996 | * This code will escape a string that is passed to it if the string | 1089 | * This code will escape a string that is passed to it if the string |
997 | * contains a control character, unprintable character, double quote mark, | 1090 | * contains a control character, unprintable character, double quote mark, |
998 | * or a space. Unescaped strings will start and end with a double quote mark. | 1091 | * or a space. Unescaped strings will start and end with a double quote mark. |
999 | * Strings that are escaped are printed in hex (2 digits per char). | 1092 | * Strings that are escaped are printed in hex (2 digits per char). |
1093 | * | ||
1094 | * The caller specifies the number of characters in the string to log, which may | ||
1095 | * or may not be the entire string. | ||
1000 | */ | 1096 | */ |
1001 | void audit_log_untrustedstring(struct audit_buffer *ab, const char *string) | 1097 | const char *audit_log_n_untrustedstring(struct audit_buffer *ab, size_t len, |
1098 | const char *string) | ||
1002 | { | 1099 | { |
1003 | const unsigned char *p = string; | 1100 | const unsigned char *p = string; |
1004 | 1101 | ||
1005 | while (*p) { | 1102 | while (*p) { |
1006 | if (*p == '"' || *p < 0x21 || *p > 0x7f) { | 1103 | if (*p == '"' || *p < 0x21 || *p > 0x7f) { |
1007 | audit_log_hex(ab, string, strlen(string)); | 1104 | audit_log_hex(ab, string, len); |
1008 | return; | 1105 | return string + len + 1; |
1009 | } | 1106 | } |
1010 | p++; | 1107 | p++; |
1011 | } | 1108 | } |
1012 | audit_log_format(ab, "\"%s\"", string); | 1109 | audit_log_n_string(ab, len, string); |
1110 | return p + 1; | ||
1111 | } | ||
1112 | |||
1113 | /** | ||
1114 | * audit_log_unstrustedstring - log a string that may contain random characters | ||
1115 | * @ab: audit_buffer | ||
1116 | * @string: string to be logged | ||
1117 | * | ||
1118 | * Same as audit_log_n_unstrustedstring(), except that strlen is used to | ||
1119 | * determine string length. | ||
1120 | */ | ||
1121 | const char *audit_log_untrustedstring(struct audit_buffer *ab, const char *string) | ||
1122 | { | ||
1123 | return audit_log_n_untrustedstring(ab, strlen(string), string); | ||
1013 | } | 1124 | } |
1014 | 1125 | ||
1015 | /* This is a helper-function to print the escaped d_path */ | 1126 | /* This is a helper-function to print the escaped d_path */ |