diff options
author | Amy Griffis <amy.griffis@hp.com> | 2006-04-07 16:55:56 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2006-06-20 05:25:27 -0400 |
commit | f368c07d7214a7c41dfceb76c8db473b850f0229 (patch) | |
tree | e3f1e2d1a6ffbe61bf99ece51b906654728db4c9 /kernel/audit.c | |
parent | 20ca73bc792be9625af184cbec36e1372611d1c3 (diff) |
[PATCH] audit: path-based rules
In this implementation, audit registers inotify watches on the parent
directories of paths specified in audit rules. When audit's inotify
event handler is called, it updates any affected rules based on the
filesystem event. If the parent directory is renamed, removed, or its
filesystem is unmounted, audit removes all rules referencing that
inotify watch.
To keep things simple, this implementation limits location-based
auditing to the directory entries in an existing directory. Given
a path-based rule for /foo/bar/passwd, the following table applies:
passwd modified -- audit event logged
passwd replaced -- audit event logged, rules list updated
bar renamed -- rule removed
foo renamed -- untracked, meaning that the rule now applies to
the new location
Audit users typically want to have many rules referencing filesystem
objects, which can significantly impact filtering performance. This
patch also adds an inode-number-based rule hash to mitigate this
situation.
The patch is relative to the audit git tree:
http://kernel.org/git/?p=linux/kernel/git/viro/audit-current.git;a=summary
and uses the inotify kernel API:
http://lkml.org/lkml/2006/6/1/145
Signed-off-by: Amy Griffis <amy.griffis@hp.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'kernel/audit.c')
-rw-r--r-- | kernel/audit.c | 41 |
1 files changed, 33 insertions, 8 deletions
diff --git a/kernel/audit.c b/kernel/audit.c index 0738a4b290e6..0fbf1c116363 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 | ||
@@ -103,6 +104,12 @@ static atomic_t audit_lost = ATOMIC_INIT(0); | |||
103 | /* The netlink socket. */ | 104 | /* The netlink socket. */ |
104 | static struct sock *audit_sock; | 105 | static struct sock *audit_sock; |
105 | 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 | |||
106 | /* 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 |
107 | * 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 |
108 | * being placed on the freelist). */ | 115 | * being placed on the freelist). */ |
@@ -115,10 +122,8 @@ static struct task_struct *kauditd_task; | |||
115 | static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait); | 122 | static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait); |
116 | static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait); | 123 | static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait); |
117 | 124 | ||
118 | /* The netlink socket is only to be read by 1 CPU, which lets us assume | 125 | /* Serialize requests from userspace. */ |
119 | * that list additions and deletions never happen simultaneously in | 126 | static DEFINE_MUTEX(audit_cmd_mutex); |
120 | * auditsc.c */ | ||
121 | DEFINE_MUTEX(audit_netlink_mutex); | ||
122 | 127 | ||
123 | /* 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 |
124 | * audit records. Since printk uses a 1024 byte buffer, this buffer | 129 | * audit records. Since printk uses a 1024 byte buffer, this buffer |
@@ -373,8 +378,8 @@ int audit_send_list(void *_dest) | |||
373 | struct sk_buff *skb; | 378 | struct sk_buff *skb; |
374 | 379 | ||
375 | /* wait for parent to finish and send an ACK */ | 380 | /* wait for parent to finish and send an ACK */ |
376 | mutex_lock(&audit_netlink_mutex); | 381 | mutex_lock(&audit_cmd_mutex); |
377 | mutex_unlock(&audit_netlink_mutex); | 382 | mutex_unlock(&audit_cmd_mutex); |
378 | 383 | ||
379 | while ((skb = __skb_dequeue(&dest->q)) != NULL) | 384 | while ((skb = __skb_dequeue(&dest->q)) != NULL) |
380 | netlink_unicast(audit_sock, skb, pid, 0); | 385 | netlink_unicast(audit_sock, skb, pid, 0); |
@@ -665,20 +670,30 @@ static void audit_receive(struct sock *sk, int length) | |||
665 | struct sk_buff *skb; | 670 | struct sk_buff *skb; |
666 | unsigned int qlen; | 671 | unsigned int qlen; |
667 | 672 | ||
668 | mutex_lock(&audit_netlink_mutex); | 673 | mutex_lock(&audit_cmd_mutex); |
669 | 674 | ||
670 | for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) { | 675 | for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) { |
671 | skb = skb_dequeue(&sk->sk_receive_queue); | 676 | skb = skb_dequeue(&sk->sk_receive_queue); |
672 | audit_receive_skb(skb); | 677 | audit_receive_skb(skb); |
673 | kfree_skb(skb); | 678 | kfree_skb(skb); |
674 | } | 679 | } |
675 | mutex_unlock(&audit_netlink_mutex); | 680 | mutex_unlock(&audit_cmd_mutex); |
676 | } | 681 | } |
677 | 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 | ||
678 | 689 | ||
679 | /* Initialize audit support at boot time. */ | 690 | /* Initialize audit support at boot time. */ |
680 | static int __init audit_init(void) | 691 | static int __init audit_init(void) |
681 | { | 692 | { |
693 | #ifdef CONFIG_AUDITSYSCALL | ||
694 | int i; | ||
695 | #endif | ||
696 | |||
682 | printk(KERN_INFO "audit: initializing netlink socket (%s)\n", | 697 | printk(KERN_INFO "audit: initializing netlink socket (%s)\n", |
683 | audit_default ? "enabled" : "disabled"); | 698 | audit_default ? "enabled" : "disabled"); |
684 | audit_sock = netlink_kernel_create(NETLINK_AUDIT, 0, audit_receive, | 699 | audit_sock = netlink_kernel_create(NETLINK_AUDIT, 0, audit_receive, |
@@ -697,6 +712,16 @@ static int __init audit_init(void) | |||
697 | selinux_audit_set_callback(&selinux_audit_rule_update); | 712 | selinux_audit_set_callback(&selinux_audit_rule_update); |
698 | 713 | ||
699 | 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 | |||
700 | return 0; | 725 | return 0; |
701 | } | 726 | } |
702 | __initcall(audit_init); | 727 | __initcall(audit_init); |