aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/audit.c
diff options
context:
space:
mode:
authorAmy Griffis <amy.griffis@hp.com>2006-04-07 16:55:56 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2006-06-20 05:25:27 -0400
commitf368c07d7214a7c41dfceb76c8db473b850f0229 (patch)
treee3f1e2d1a6ffbe61bf99ece51b906654728db4c9 /kernel/audit.c
parent20ca73bc792be9625af184cbec36e1372611d1c3 (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.c41
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. */
104static struct sock *audit_sock; 105static struct sock *audit_sock;
105 106
107/* Inotify handle. */
108struct inotify_handle *audit_ih;
109
110/* Hash for inode-based rules */
111struct 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;
115static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait); 122static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait);
116static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait); 123static 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 126static DEFINE_MUTEX(audit_cmd_mutex);
120 * auditsc.c */
121DEFINE_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
684static 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. */
680static int __init audit_init(void) 691static 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);