Merge with /shiny/git/linux-2.6/.git
David Woodhouse [Wed, 13 Jul 2005 14:25:59 +0000 (15:25 +0100)]
MAINTAINERS
fs/namei.c
include/linux/audit.h
kernel/audit.c
kernel/auditsc.c
security/selinux/avc.c
security/selinux/hooks.c
security/selinux/ss/services.c

index 5d01472..a47b741 100644 (file)
@@ -363,6 +363,13 @@ L: linux-atm-general@lists.sourceforge.net
 W:     http://linux-atm.sourceforge.net
 S:     Maintained
 
+AUDIT SUBSYSTEM
+P:     David Woodhouse
+M:     dwmw2@infradead.org
+L:     linux-audit@redhat.com
+W:     http://people.redhat.com/sgrubb/audit/
+S:     Maintained
+
 ATMEL WIRELESS DRIVER
 P:     Simon Kelley
 M:     simon@thekelleys.org.uk
index 02a824c..e252b12 100644 (file)
@@ -1043,7 +1043,7 @@ int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata
 out:
        if (unlikely(current->audit_context
                     && nd && nd->dentry && nd->dentry->d_inode))
-               audit_inode(name, nd->dentry->d_inode);
+               audit_inode(name, nd->dentry->d_inode, flags);
        return retval;
 }
 
index 68aba0c..b2a2509 100644 (file)
@@ -51,7 +51,8 @@
 #define AUDIT_WATCH_LIST       1009    /* List all file/dir watches */
 #define AUDIT_SIGNAL_INFO      1010    /* Get info about sender of signal to auditd */
 
-#define AUDIT_FIRST_USER_MSG   1100    /* Userspace messages uninteresting to kernel */
+#define AUDIT_FIRST_USER_MSG   1100    /* Userspace messages mostly uninteresting to kernel */
+#define AUDIT_USER_AVC         1107    /* We filter this differently */
 #define AUDIT_LAST_USER_MSG    1199
  
 #define AUDIT_DAEMON_START      1200    /* Daemon startup record */
 #define AUDIT_KERNEL           2000    /* Asynchronous audit record. NOT A REQUEST. */
 
 /* Rule flags */
-#define AUDIT_PER_TASK 0x01    /* Apply rule at task creation (not syscall) */
-#define AUDIT_AT_ENTRY 0x02    /* Apply rule at syscall entry */
-#define AUDIT_AT_EXIT  0x04    /* Apply rule at syscall exit */
-#define AUDIT_PREPEND  0x10    /* Prepend to front of list */
+#define AUDIT_FILTER_USER      0x00    /* Apply rule to user-generated messages */
+#define AUDIT_FILTER_TASK      0x01    /* Apply rule at task creation (not syscall) */
+#define AUDIT_FILTER_ENTRY     0x02    /* Apply rule at syscall entry */
+#define AUDIT_FILTER_WATCH     0x03    /* Apply rule to file system watches */
+#define AUDIT_FILTER_EXIT      0x04    /* Apply rule at syscall exit */
+
+#define AUDIT_NR_FILTERS       5
+
+#define AUDIT_FILTER_PREPEND   0x10    /* Prepend to front of list */
 
 /* Rule actions */
 #define AUDIT_NEVER    0       /* Do not build context if rule matches */
@@ -199,6 +205,7 @@ struct audit_sig_info {
 struct audit_buffer;
 struct audit_context;
 struct inode;
+struct netlink_skb_parms;
 
 #define AUDITSC_INVALID 0
 #define AUDITSC_SUCCESS 1
@@ -215,7 +222,7 @@ extern void audit_syscall_entry(struct task_struct *task, int arch,
 extern void audit_syscall_exit(struct task_struct *task, int failed, long return_code);
 extern void audit_getname(const char *name);
 extern void audit_putname(const char *name);
-extern void audit_inode(const char *name, const struct inode *inode);
+extern void audit_inode(const char *name, const struct inode *inode, unsigned flags);
 
                                /* Private API (for audit.c only) */
 extern int  audit_receive_filter(int type, int pid, int uid, int seq,
@@ -230,6 +237,7 @@ extern int audit_socketcall(int nargs, unsigned long *args);
 extern int audit_sockaddr(int len, void *addr);
 extern int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt);
 extern void audit_signal_info(int sig, struct task_struct *t);
+extern int audit_filter_user(struct netlink_skb_parms *cb, int type);
 #else
 #define audit_alloc(t) ({ 0; })
 #define audit_free(t) do { ; } while (0)
@@ -237,7 +245,7 @@ extern void audit_signal_info(int sig, struct task_struct *t);
 #define audit_syscall_exit(t,f,r) do { ; } while (0)
 #define audit_getname(n) do { ; } while (0)
 #define audit_putname(n) do { ; } while (0)
-#define audit_inode(n,i) do { ; } while (0)
+#define audit_inode(n,i,f) do { ; } while (0)
 #define audit_receive_filter(t,p,u,s,d,l) ({ -EOPNOTSUPP; })
 #define auditsc_get_stamp(c,t,s) do { BUG(); } while (0)
 #define audit_get_loginuid(c) ({ -1; })
@@ -246,16 +254,17 @@ extern void audit_signal_info(int sig, struct task_struct *t);
 #define audit_sockaddr(len, addr) ({ 0; })
 #define audit_avc_path(dentry, mnt) ({ 0; })
 #define audit_signal_info(s,t) do { ; } while (0)
+#define audit_filter_user(cb,t) ({ 1; })
 #endif
 
 #ifdef CONFIG_AUDIT
 /* These are defined in audit.c */
                                /* Public API */
-extern void                audit_log(struct audit_context *ctx, int type,
-                                     const char *fmt, ...)
-                           __attribute__((format(printf,3,4)));
+extern void                audit_log(struct audit_context *ctx, int gfp_mask,
+                                     int type, const char *fmt, ...)
+                                     __attribute__((format(printf,4,5)));
 
-extern struct audit_buffer *audit_log_start(struct audit_context *ctx,int type);
+extern struct audit_buffer *audit_log_start(struct audit_context *ctx, int gfp_mask, int type);
 extern void                audit_log_format(struct audit_buffer *ab,
                                             const char *fmt, ...)
                            __attribute__((format(printf,2,3)));
@@ -274,9 +283,10 @@ extern void                    audit_send_reply(int pid, int seq, int type,
                                             int done, int multi,
                                             void *payload, int size);
 extern void                audit_log_lost(const char *message);
+extern struct semaphore audit_netlink_sem;
 #else
-#define audit_log(c,t,f,...) do { ; } while (0)
-#define audit_log_start(c,t) ({ NULL; })
+#define audit_log(c,g,t,f,...) do { ; } while (0)
+#define audit_log_start(c,g,t) ({ NULL; })
 #define audit_log_vformat(b,f,a) do { ; } while (0)
 #define audit_log_format(b,f,...) do { ; } while (0)
 #define audit_log_end(b) do { ; } while (0)
index ef35166..b683f2b 100644 (file)
@@ -79,6 +79,8 @@ static int    audit_rate_limit;
 
 /* Number of outstanding audit_buffers allowed. */
 static int     audit_backlog_limit = 64;
+static int     audit_backlog_wait_time = 60 * HZ;
+static int     audit_backlog_wait_overflow = 0;
 
 /* The identity of the user shutting down the audit system. */
 uid_t          audit_sig_uid = -1;
@@ -106,18 +108,12 @@ static LIST_HEAD(audit_freelist);
 static struct sk_buff_head audit_skb_queue;
 static struct task_struct *kauditd_task;
 static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait);
-
-/* There are three lists of rules -- one to search at task creation
- * time, one to search at syscall entry time, and another to search at
- * syscall exit time. */
-static LIST_HEAD(audit_tsklist);
-static LIST_HEAD(audit_entlist);
-static LIST_HEAD(audit_extlist);
+static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait);
 
 /* The netlink socket is only to be read by 1 CPU, which lets us assume
  * that list additions and deletions never happen simultaneously in
  * auditsc.c */
-static DECLARE_MUTEX(audit_netlink_sem);
+DECLARE_MUTEX(audit_netlink_sem);
 
 /* AUDIT_BUFSIZ is the size of the temporary buffer used for formatting
  * audit records.  Since printk uses a 1024 byte buffer, this buffer
@@ -137,6 +133,7 @@ struct audit_buffer {
        struct list_head     list;
        struct sk_buff       *skb;      /* formatted skb ready to send */
        struct audit_context *ctx;      /* NULL or associated context */
+       int                  gfp_mask;
 };
 
 static void audit_set_pid(struct audit_buffer *ab, pid_t pid)
@@ -233,7 +230,7 @@ static int audit_set_rate_limit(int limit, uid_t loginuid)
 {
        int old          = audit_rate_limit;
        audit_rate_limit = limit;
-       audit_log(NULL, AUDIT_CONFIG_CHANGE, 
+       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, 
                        "audit_rate_limit=%d old=%d by auid=%u",
                        audit_rate_limit, old, loginuid);
        return old;
@@ -243,7 +240,7 @@ static int audit_set_backlog_limit(int limit, uid_t loginuid)
 {
        int old          = audit_backlog_limit;
        audit_backlog_limit = limit;
-       audit_log(NULL, AUDIT_CONFIG_CHANGE,
+       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
                        "audit_backlog_limit=%d old=%d by auid=%u",
                        audit_backlog_limit, old, loginuid);
        return old;
@@ -255,7 +252,7 @@ static int audit_set_enabled(int state, uid_t loginuid)
        if (state != 0 && state != 1)
                return -EINVAL;
        audit_enabled = state;
-       audit_log(NULL, AUDIT_CONFIG_CHANGE,
+       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
                        "audit_enabled=%d old=%d by auid=%u",
                        audit_enabled, old, loginuid);
        return old;
@@ -269,7 +266,7 @@ static int audit_set_failure(int state, uid_t loginuid)
            && state != AUDIT_FAIL_PANIC)
                return -EINVAL;
        audit_failure = state;
-       audit_log(NULL, AUDIT_CONFIG_CHANGE,
+       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
                        "audit_failure=%d old=%d by auid=%u",
                        audit_failure, old, loginuid);
        return old;
@@ -281,6 +278,7 @@ int kauditd_thread(void *dummy)
 
        while (1) {
                skb = skb_dequeue(&audit_skb_queue);
+               wake_up(&audit_backlog_wait);
                if (skb) {
                        if (audit_pid) {
                                int err = netlink_unicast(audit_sock, skb, audit_pid, 0);
@@ -290,7 +288,7 @@ int kauditd_thread(void *dummy)
                                        audit_pid = 0;
                                }
                        } else {
-                               printk(KERN_ERR "%s\n", skb->data + NLMSG_SPACE(0));
+                               printk(KERN_NOTICE "%s\n", skb->data + NLMSG_SPACE(0));
                                kfree_skb(skb);
                        }
                } else {
@@ -423,7 +421,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                if (status_get->mask & AUDIT_STATUS_PID) {
                        int old   = audit_pid;
                        audit_pid = status_get->pid;
-                       audit_log(NULL, AUDIT_CONFIG_CHANGE,
+                       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
                                "audit_pid=%d old=%d by auid=%u",
                                  audit_pid, old, loginuid);
                }
@@ -435,15 +433,21 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                break;
        case AUDIT_USER:
        case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
-               ab = audit_log_start(NULL, msg_type);
-               if (!ab)
-                       break;  /* audit_panic has been called */
-               audit_log_format(ab,
-                                "user pid=%d uid=%u auid=%u"
-                                " msg='%.1024s'",
-                                pid, uid, loginuid, (char *)data);
-               audit_set_pid(ab, pid);
-               audit_log_end(ab);
+               if (!audit_enabled && msg_type != AUDIT_USER_AVC)
+                       return 0;
+
+               err = audit_filter_user(&NETLINK_CB(skb), msg_type);
+               if (err == 1) {
+                       err = 0;
+                       ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
+                       if (ab) {
+                               audit_log_format(ab,
+                                                "user pid=%d uid=%u auid=%u msg='%.1024s'",
+                                                pid, uid, loginuid, (char *)data);
+                               audit_set_pid(ab, pid);
+                               audit_log_end(ab);
+                       }
+               }
                break;
        case AUDIT_ADD:
        case AUDIT_DEL:
@@ -522,7 +526,7 @@ static int __init audit_init(void)
        skb_queue_head_init(&audit_skb_queue);
        audit_initialized = 1;
        audit_enabled = audit_default;
-       audit_log(NULL, AUDIT_KERNEL, "initialized");
+       audit_log(NULL, GFP_KERNEL, AUDIT_KERNEL, "initialized");
        return 0;
 }
 __initcall(audit_init);
@@ -586,6 +590,7 @@ static struct audit_buffer * audit_buffer_alloc(struct audit_context *ctx,
                goto err;
 
        ab->ctx = ctx;
+       ab->gfp_mask = gfp_mask;
        nlh = (struct nlmsghdr *)skb_put(ab->skb, NLMSG_SPACE(0));
        nlh->nlmsg_type = type;
        nlh->nlmsg_flags = 0;
@@ -644,17 +649,43 @@ static inline void audit_get_stamp(struct audit_context *ctx,
  * syscall, then the syscall is marked as auditable and an audit record
  * will be written at syscall exit.  If there is no associated task, tsk
  * should be NULL. */
-struct audit_buffer *audit_log_start(struct audit_context *ctx, int type)
+
+struct audit_buffer *audit_log_start(struct audit_context *ctx, int gfp_mask,
+                                    int type)
 {
        struct audit_buffer     *ab     = NULL;
        struct timespec         t;
        unsigned int            serial;
+       int reserve;
+       unsigned long timeout_start = jiffies;
 
        if (!audit_initialized)
                return NULL;
 
-       if (audit_backlog_limit
-           && skb_queue_len(&audit_skb_queue) > audit_backlog_limit) {
+       if (gfp_mask & __GFP_WAIT)
+               reserve = 0;
+       else
+               reserve = 5; /* Allow atomic callers to go up to five 
+                               entries over the normal backlog limit */
+
+       while (audit_backlog_limit
+              && skb_queue_len(&audit_skb_queue) > audit_backlog_limit + reserve) {
+               if (gfp_mask & __GFP_WAIT && audit_backlog_wait_time
+                   && time_before(jiffies, timeout_start + audit_backlog_wait_time)) {
+
+                       /* Wait for auditd to drain the queue a little */
+                       DECLARE_WAITQUEUE(wait, current);
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       add_wait_queue(&audit_backlog_wait, &wait);
+
+                       if (audit_backlog_limit &&
+                           skb_queue_len(&audit_skb_queue) > audit_backlog_limit)
+                               schedule_timeout(timeout_start + audit_backlog_wait_time - jiffies);
+
+                       __set_current_state(TASK_RUNNING);
+                       remove_wait_queue(&audit_backlog_wait, &wait);
+                       continue;
+               }
                if (audit_rate_check())
                        printk(KERN_WARNING
                               "audit: audit_backlog=%d > "
@@ -662,10 +693,12 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, int type)
                               skb_queue_len(&audit_skb_queue),
                               audit_backlog_limit);
                audit_log_lost("backlog limit exceeded");
+               audit_backlog_wait_time = audit_backlog_wait_overflow;
+               wake_up(&audit_backlog_wait);
                return NULL;
        }
 
-       ab = audit_buffer_alloc(ctx, GFP_ATOMIC, type);
+       ab = audit_buffer_alloc(ctx, gfp_mask, type);
        if (!ab) {
                audit_log_lost("out of memory in audit_log_start");
                return NULL;
@@ -689,7 +722,7 @@ static inline int audit_expand(struct audit_buffer *ab, int extra)
 {
        struct sk_buff *skb = ab->skb;
        int ret = pskb_expand_head(skb, skb_headroom(skb), extra,
-                                  GFP_ATOMIC);
+                                  ab->gfp_mask);
        if (ret < 0) {
                audit_log_lost("out of memory in audit_expand");
                return 0;
@@ -808,7 +841,7 @@ void audit_log_d_path(struct audit_buffer *ab, const char *prefix,
                audit_log_format(ab, " %s", prefix);
 
        /* We will allow 11 spaces for ' (deleted)' to be appended */
-       path = kmalloc(PATH_MAX+11, GFP_KERNEL);
+       path = kmalloc(PATH_MAX+11, ab->gfp_mask);
        if (!path) {
                audit_log_format(ab, "<no memory>");
                return;
@@ -840,7 +873,7 @@ void audit_log_end(struct audit_buffer *ab)
                        ab->skb = NULL;
                        wake_up_interruptible(&kauditd_wait);
                } else {
-                       printk("%s\n", ab->skb->data + NLMSG_SPACE(0));
+                       printk(KERN_NOTICE "%s\n", ab->skb->data + NLMSG_SPACE(0));
                }
        }
        audit_buffer_free(ab);
@@ -849,12 +882,13 @@ void audit_log_end(struct audit_buffer *ab)
 /* Log an audit record.  This is a convenience function that calls
  * audit_log_start, audit_log_vformat, and audit_log_end.  It may be
  * called in any context. */
-void audit_log(struct audit_context *ctx, int type, const char *fmt, ...)
+void audit_log(struct audit_context *ctx, int gfp_mask, int type, 
+              const char *fmt, ...)
 {
        struct audit_buffer *ab;
        va_list args;
 
-       ab = audit_log_start(ctx, type);
+       ab = audit_log_start(ctx, gfp_mask, type);
        if (ab) {
                va_start(args, fmt);
                audit_log_vformat(ab, fmt, args);
index e75f84e..0fdd901 100644 (file)
@@ -39,6 +39,8 @@
 #include <linux/audit.h>
 #include <linux/personality.h>
 #include <linux/time.h>
+#include <linux/kthread.h>
+#include <linux/netlink.h>
 #include <asm/unistd.h>
 
 /* 0 = no checking
@@ -95,6 +97,7 @@ struct audit_names {
        uid_t           uid;
        gid_t           gid;
        dev_t           rdev;
+       unsigned        flags;
 };
 
 struct audit_aux_data {
@@ -167,9 +170,16 @@ struct audit_context {
 /* There are three lists of rules -- one to search at task creation
  * time, one to search at syscall entry time, and another to search at
  * syscall exit time. */
-static LIST_HEAD(audit_tsklist);
-static LIST_HEAD(audit_entlist);
-static LIST_HEAD(audit_extlist);
+static struct list_head audit_filter_list[AUDIT_NR_FILTERS] = {
+       LIST_HEAD_INIT(audit_filter_list[0]),
+       LIST_HEAD_INIT(audit_filter_list[1]),
+       LIST_HEAD_INIT(audit_filter_list[2]),
+       LIST_HEAD_INIT(audit_filter_list[3]),
+       LIST_HEAD_INIT(audit_filter_list[4]),
+#if AUDIT_NR_FILTERS != 5
+#error Fix audit_filter_list initialiser
+#endif
+};
 
 struct audit_entry {
        struct list_head  list;
@@ -210,16 +220,15 @@ static int audit_compare_rule(struct audit_rule *a, struct audit_rule *b)
 /* Note that audit_add_rule and audit_del_rule are called via
  * audit_receive() in audit.c, and are protected by
  * audit_netlink_sem. */
-static inline int audit_add_rule(struct audit_entry *entry,
-                                struct list_head *list)
+static inline void audit_add_rule(struct audit_entry *entry,
+                                 struct list_head *list)
 {
-       if (entry->rule.flags & AUDIT_PREPEND) {
-               entry->rule.flags &= ~AUDIT_PREPEND;
+       if (entry->rule.flags & AUDIT_FILTER_PREPEND) {
+               entry->rule.flags &= ~AUDIT_FILTER_PREPEND;
                list_add_rcu(&entry->list, list);
        } else {
                list_add_tail_rcu(&entry->list, list);
        }
-       return 0;
 }
 
 static void audit_free_rule(struct rcu_head *head)
@@ -245,7 +254,7 @@ static inline int audit_del_rule(struct audit_rule *rule,
                        return 0;
                }
        }
-       return -EFAULT;         /* No matching rule */
+       return -ENOENT;         /* No matching rule */
 }
 
 /* Copy rule from user-space to kernel-space.  Called during
@@ -260,6 +269,8 @@ static int audit_copy_rule(struct audit_rule *d, struct audit_rule *s)
                return -1;
        if (s->field_count < 0 || s->field_count > AUDIT_MAX_FIELDS)
                return -1;
+       if ((s->flags & ~AUDIT_FILTER_PREPEND) >= AUDIT_NR_FILTERS)
+               return -1;
 
        d->flags        = s->flags;
        d->action       = s->action;
@@ -272,27 +283,60 @@ static int audit_copy_rule(struct audit_rule *d, struct audit_rule *s)
        return 0;
 }
 
+static int audit_list_rules(void *_dest)
+{
+       int pid, seq;
+       int *dest = _dest;
+       struct audit_entry *entry;
+       int i;
+
+       pid = dest[0];
+       seq = dest[1];
+       kfree(dest);
+
+       down(&audit_netlink_sem);
+
+       /* The *_rcu iterators not needed here because we are
+          always called with audit_netlink_sem held. */
+       for (i=0; i<AUDIT_NR_FILTERS; i++) {
+               list_for_each_entry(entry, &audit_filter_list[i], list)
+                       audit_send_reply(pid, seq, AUDIT_LIST, 0, 1,
+                                        &entry->rule, sizeof(entry->rule));
+       }
+       audit_send_reply(pid, seq, AUDIT_LIST, 1, 1, NULL, 0);
+       
+       up(&audit_netlink_sem);
+       return 0;
+}
+
 int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
                                                        uid_t loginuid)
 {
-       u32                flags;
        struct audit_entry *entry;
+       struct task_struct *tsk;
+       int *dest;
        int                err = 0;
+       unsigned listnr;
 
        switch (type) {
        case AUDIT_LIST:
-               /* The *_rcu iterators not needed here because we are
-                  always called with audit_netlink_sem held. */
-               list_for_each_entry(entry, &audit_tsklist, list)
-                       audit_send_reply(pid, seq, AUDIT_LIST, 0, 1,
-                                        &entry->rule, sizeof(entry->rule));
-               list_for_each_entry(entry, &audit_entlist, list)
-                       audit_send_reply(pid, seq, AUDIT_LIST, 0, 1,
-                                        &entry->rule, sizeof(entry->rule));
-               list_for_each_entry(entry, &audit_extlist, list)
-                       audit_send_reply(pid, seq, AUDIT_LIST, 0, 1,
-                                        &entry->rule, sizeof(entry->rule));
-               audit_send_reply(pid, seq, AUDIT_LIST, 1, 1, NULL, 0);
+               /* We can't just spew out the rules here because we might fill
+                * the available socket buffer space and deadlock waiting for
+                * auditctl to read from it... which isn't ever going to
+                * happen if we're actually running in the context of auditctl
+                * trying to _send_ the stuff */
+                
+               dest = kmalloc(2 * sizeof(int), GFP_KERNEL);
+               if (!dest)
+                       return -ENOMEM;
+               dest[0] = pid;
+               dest[1] = seq;
+
+               tsk = kthread_run(audit_list_rules, dest, "audit_list_rules");
+               if (IS_ERR(tsk)) {
+                       kfree(dest);
+                       err = PTR_ERR(tsk);
+               }
                break;
        case AUDIT_ADD:
                if (!(entry = kmalloc(sizeof(*entry), GFP_KERNEL)))
@@ -301,26 +345,20 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
                        kfree(entry);
                        return -EINVAL;
                }
-               flags = entry->rule.flags;
-               if (!err && (flags & AUDIT_PER_TASK))
-                       err = audit_add_rule(entry, &audit_tsklist);
-               if (!err && (flags & AUDIT_AT_ENTRY))
-                       err = audit_add_rule(entry, &audit_entlist);
-               if (!err && (flags & AUDIT_AT_EXIT))
-                       err = audit_add_rule(entry, &audit_extlist);
-               audit_log(NULL, AUDIT_CONFIG_CHANGE, 
+               listnr = entry->rule.flags & ~AUDIT_FILTER_PREPEND;
+               audit_add_rule(entry, &audit_filter_list[listnr]);
+               audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, 
                                "auid=%u added an audit rule\n", loginuid);
                break;
        case AUDIT_DEL:
-               flags =((struct audit_rule *)data)->flags;
-               if (!err && (flags & AUDIT_PER_TASK))
-                       err = audit_del_rule(data, &audit_tsklist);
-               if (!err && (flags & AUDIT_AT_ENTRY))
-                       err = audit_del_rule(data, &audit_entlist);
-               if (!err && (flags & AUDIT_AT_EXIT))
-                       err = audit_del_rule(data, &audit_extlist);
-               audit_log(NULL, AUDIT_CONFIG_CHANGE,
-                               "auid=%u removed an audit rule\n", loginuid);
+               listnr =((struct audit_rule *)data)->flags & ~AUDIT_FILTER_PREPEND;
+               if (listnr >= AUDIT_NR_FILTERS)
+                       return -EINVAL;
+
+               err = audit_del_rule(data, &audit_filter_list[listnr]);
+               if (!err)
+                       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+                                 "auid=%u removed an audit rule\n", loginuid);
                break;
        default:
                return -EINVAL;
@@ -454,7 +492,7 @@ static enum audit_state audit_filter_task(struct task_struct *tsk)
        enum audit_state   state;
 
        rcu_read_lock();
-       list_for_each_entry_rcu(e, &audit_tsklist, list) {
+       list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_TASK], list) {
                if (audit_filter_rules(tsk, &e->rule, NULL, &state)) {
                        rcu_read_unlock();
                        return state;
@@ -478,6 +516,9 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,
        int                word = AUDIT_WORD(ctx->major);
        int                bit  = AUDIT_BIT(ctx->major);
 
+       if (audit_pid && tsk->pid == audit_pid)
+               return AUDIT_DISABLED;
+
        rcu_read_lock();
        list_for_each_entry_rcu(e, list, list) {
                if ((e->rule.mask[word] & bit) == bit
@@ -490,6 +531,64 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,
        return AUDIT_BUILD_CONTEXT;
 }
 
+static int audit_filter_user_rules(struct netlink_skb_parms *cb,
+                             struct audit_rule *rule,
+                             enum audit_state *state)
+{
+       int i;
+
+       for (i = 0; i < rule->field_count; i++) {
+               u32 field  = rule->fields[i] & ~AUDIT_NEGATE;
+               u32 value  = rule->values[i];
+               int result = 0;
+
+               switch (field) {
+               case AUDIT_PID:
+                       result = (cb->creds.pid == value);
+                       break;
+               case AUDIT_UID:
+                       result = (cb->creds.uid == value);
+                       break;
+               case AUDIT_GID:
+                       result = (cb->creds.gid == value);
+                       break;
+               case AUDIT_LOGINUID:
+                       result = (cb->loginuid == value);
+                       break;
+               }
+
+               if (rule->fields[i] & AUDIT_NEGATE)
+                       result = !result;
+               if (!result)
+                       return 0;
+       }
+       switch (rule->action) {
+       case AUDIT_NEVER:    *state = AUDIT_DISABLED;       break;
+       case AUDIT_POSSIBLE: *state = AUDIT_BUILD_CONTEXT;  break;
+       case AUDIT_ALWAYS:   *state = AUDIT_RECORD_CONTEXT; break;
+       }
+       return 1;
+}
+
+int audit_filter_user(struct netlink_skb_parms *cb, int type)
+{
+       struct audit_entry *e;
+       enum audit_state   state;
+       int ret = 1;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_USER], list) {
+               if (audit_filter_user_rules(cb, &e->rule, &state)) {
+                       if (state == AUDIT_DISABLED)
+                               ret = 0;
+                       break;
+               }
+       }
+       rcu_read_unlock();
+
+       return ret; /* Audit by default */
+}
+
 /* This should be called with task_lock() held. */
 static inline struct audit_context *audit_get_context(struct task_struct *tsk,
                                                      int return_valid,
@@ -504,7 +603,7 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk,
 
        if (context->in_syscall && !context->auditable) {
                enum audit_state state;
-               state = audit_filter_syscall(tsk, context, &audit_extlist);
+               state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_EXIT]);
                if (state == AUDIT_RECORD_CONTEXT)
                        context->auditable = 1;
        }
@@ -685,7 +784,7 @@ static void audit_log_exit(struct audit_context *context)
        struct audit_buffer *ab;
        struct audit_aux_data *aux;
 
-       ab = audit_log_start(context, AUDIT_SYSCALL);
+       ab = audit_log_start(context, GFP_KERNEL, AUDIT_SYSCALL);
        if (!ab)
                return;         /* audit_panic has been called */
        audit_log_format(ab, "arch=%x syscall=%d",
@@ -717,7 +816,7 @@ static void audit_log_exit(struct audit_context *context)
 
        for (aux = context->aux; aux; aux = aux->next) {
 
-               ab = audit_log_start(context, aux->type);
+               ab = audit_log_start(context, GFP_KERNEL, aux->type);
                if (!ab)
                        continue; /* audit_panic has been called */
 
@@ -754,14 +853,14 @@ static void audit_log_exit(struct audit_context *context)
        }
 
        if (context->pwd && context->pwdmnt) {
-               ab = audit_log_start(context, AUDIT_CWD);
+               ab = audit_log_start(context, GFP_KERNEL, AUDIT_CWD);
                if (ab) {
                        audit_log_d_path(ab, "cwd=", context->pwd, context->pwdmnt);
                        audit_log_end(ab);
                }
        }
        for (i = 0; i < context->name_count; i++) {
-               ab = audit_log_start(context, AUDIT_PATH);
+               ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH);
                if (!ab)
                        continue; /* audit_panic has been called */
 
@@ -770,6 +869,8 @@ static void audit_log_exit(struct audit_context *context)
                        audit_log_format(ab, " name=");
                        audit_log_untrustedstring(ab, context->names[i].name);
                }
+               audit_log_format(ab, " flags=%x\n", context->names[i].flags);
+                        
                if (context->names[i].ino != (unsigned long)-1)
                        audit_log_format(ab, " inode=%lu dev=%02x:%02x mode=%#o"
                                             " ouid=%u ogid=%u rdev=%02x:%02x",
@@ -800,7 +901,7 @@ void audit_free(struct task_struct *tsk)
 
        /* Check for system calls that do not go through the exit
         * function (e.g., exit_group), then free context block. */
-       if (context->in_syscall && context->auditable && context->pid != audit_pid)
+       if (context->in_syscall && context->auditable)
                audit_log_exit(context);
 
        audit_free_context(context);
@@ -876,7 +977,7 @@ void audit_syscall_entry(struct task_struct *tsk, int arch, int major,
 
        state = context->state;
        if (state == AUDIT_SETUP_CONTEXT || state == AUDIT_BUILD_CONTEXT)
-               state = audit_filter_syscall(tsk, context, &audit_entlist);
+               state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_ENTRY]);
        if (likely(state == AUDIT_DISABLED))
                return;
 
@@ -905,7 +1006,7 @@ void audit_syscall_exit(struct task_struct *tsk, int valid, long return_code)
        if (likely(!context))
                return;
 
-       if (context->in_syscall && context->auditable && context->pid != audit_pid)
+       if (context->in_syscall && context->auditable)
                audit_log_exit(context);
 
        context->in_syscall = 0;
@@ -996,7 +1097,7 @@ void audit_putname(const char *name)
 
 /* Store the inode and device from a lookup.  Called from
  * fs/namei.c:path_lookup(). */
-void audit_inode(const char *name, const struct inode *inode)
+void audit_inode(const char *name, const struct inode *inode, unsigned flags)
 {
        int idx;
        struct audit_context *context = current->audit_context;
@@ -1022,12 +1123,13 @@ void audit_inode(const char *name, const struct inode *inode)
                ++context->ino_count;
 #endif
        }
-       context->names[idx].ino  = inode->i_ino;
-       context->names[idx].dev  = inode->i_sb->s_dev;
-       context->names[idx].mode = inode->i_mode;
-       context->names[idx].uid  = inode->i_uid;
-       context->names[idx].gid  = inode->i_gid;
-       context->names[idx].rdev = inode->i_rdev;
+       context->names[idx].flags = flags;
+       context->names[idx].ino   = inode->i_ino;
+       context->names[idx].dev   = inode->i_sb->s_dev;
+       context->names[idx].mode  = inode->i_mode;
+       context->names[idx].uid   = inode->i_uid;
+       context->names[idx].gid   = inode->i_gid;
+       context->names[idx].rdev  = inode->i_rdev;
 }
 
 void auditsc_get_stamp(struct audit_context *ctx,
@@ -1044,7 +1146,7 @@ int audit_set_loginuid(struct task_struct *task, uid_t loginuid)
        if (task->audit_context) {
                struct audit_buffer *ab;
 
-               ab = audit_log_start(NULL, AUDIT_LOGIN);
+               ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN);
                if (ab) {
                        audit_log_format(ab, "login pid=%d uid=%u "
                                "old auid=%u new auid=%u",
index 4515024..2d088bb 100644 (file)
@@ -242,7 +242,7 @@ void __init avc_init(void)
        avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node),
                                             0, SLAB_PANIC, NULL, NULL);
 
-       audit_log(current->audit_context, AUDIT_KERNEL, "AVC INITIALIZED\n");
+       audit_log(current->audit_context, GFP_KERNEL, AUDIT_KERNEL, "AVC INITIALIZED\n");
 }
 
 int avc_get_hash_stats(char *page)
@@ -550,7 +550,7 @@ void avc_audit(u32 ssid, u32 tsid,
                        return;
        }
 
-       ab = audit_log_start(current->audit_context, AUDIT_AVC);
+       ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_AVC);
        if (!ab)
                return;         /* audit_panic has been called */
        audit_log_format(ab, "avc:  %s ", denied ? "denied" : "granted");
index 6be2738..5e755a3 100644 (file)
@@ -3441,7 +3441,7 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
        err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
        if (err) {
                if (err == -EINVAL) {
-                       audit_log(current->audit_context, AUDIT_SELINUX_ERR,
+                       audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
                                  "SELinux:  unrecognized netlink message"
                                  " type=%hu for sclass=%hu\n",
                                  nlh->nlmsg_type, isec->sclass);
index 922bb45..bfa5a7d 100644 (file)
@@ -365,7 +365,7 @@ static int security_validtrans_handle_fail(struct context *ocontext,
                goto out;
        if (context_struct_to_string(tcontext, &t, &tlen) < 0)
                goto out;
-       audit_log(current->audit_context, AUDIT_SELINUX_ERR,
+       audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
                  "security_validate_transition:  denied for"
                  " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
                  o, n, t, policydb.p_class_val_to_name[tclass-1]);
@@ -742,7 +742,7 @@ static int compute_sid_handle_invalid_context(
                goto out;
        if (context_struct_to_string(newcontext, &n, &nlen) < 0)
                goto out;
-       audit_log(current->audit_context, AUDIT_SELINUX_ERR,
+       audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
                  "security_compute_sid:  invalid context %s"
                  " for scontext=%s"
                  " tcontext=%s"