Merge git://git.infradead.org/users/eparis/audit
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 11 May 2013 21:29:11 +0000 (14:29 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 11 May 2013 21:29:11 +0000 (14:29 -0700)
Pull audit changes from Eric Paris:
 "Al used to send pull requests every couple of years but he told me to
  just start pushing them to you directly.

  Our touching outside of core audit code is pretty straight forward.  A
  couple of interface changes which hit net/.  A simple argument bug
  calling audit functions in namei.c and the removal of some assembly
  branch prediction code on ppc"

* git://git.infradead.org/users/eparis/audit: (31 commits)
  audit: fix message spacing printing auid
  Revert "audit: move kaudit thread start from auditd registration to kaudit init"
  audit: vfs: fix audit_inode call in O_CREAT case of do_last
  audit: Make testing for a valid loginuid explicit.
  audit: fix event coverage of AUDIT_ANOM_LINK
  audit: use spin_lock in audit_receive_msg to process tty logging
  audit: do not needlessly take a lock in tty_audit_exit
  audit: do not needlessly take a spinlock in copy_signal
  audit: add an option to control logging of passwords with pam_tty_audit
  audit: use spin_lock_irqsave/restore in audit tty code
  helper for some session id stuff
  audit: use a consistent audit helper to log lsm information
  audit: push loginuid and sessionid processing down
  audit: stop pushing loginid, uid, sessionid as arguments
  audit: remove the old depricated kernel interface
  audit: make validity checking generic
  audit: allow checking the type of audit message in the user filter
  audit: fix build break when AUDIT_DEBUG == 2
  audit: remove duplicate export of audit_enabled
  Audit: do not print error when LSMs disabled
  ...

12 files changed:
arch/powerpc/kernel/entry_64.S
drivers/tty/tty_audit.c
fs/namei.c
include/linux/audit.h
include/linux/sched.h
include/linux/tty.h
include/uapi/linux/audit.h
kernel/audit.c
kernel/audit.h
kernel/auditfilter.c
kernel/auditsc.c
net/socket.c

index 3fe5259e2fea872be5da2e333427a935f8a012d0..915fbb4fc2fe4e7534dbf78eb39317013b03b014 100644 (file)
@@ -150,7 +150,7 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
        CURRENT_THREAD_INFO(r11, r1)
        ld      r10,TI_FLAGS(r11)
        andi.   r11,r10,_TIF_SYSCALL_T_OR_A
-       bne-    syscall_dotrace
+       bne     syscall_dotrace
 .Lsyscall_dotrace_cont:
        cmpldi  0,r0,NR_syscalls
        bge-    syscall_enosys
index 6953dc82850cb278fd99da209e560021d4d0c1e8..a4fdce74f883e4f5868f3efb975ec51347ef2c47 100644 (file)
@@ -60,24 +60,22 @@ static void tty_audit_buf_put(struct tty_audit_buf *buf)
                tty_audit_buf_free(buf);
 }
 
-static void tty_audit_log(const char *description, struct task_struct *tsk,
-                         kuid_t loginuid, unsigned sessionid, int major,
-                         int minor, unsigned char *data, size_t size)
+static void tty_audit_log(const char *description, int major, int minor,
+                         unsigned char *data, size_t size)
 {
        struct audit_buffer *ab;
+       struct task_struct *tsk = current;
+       uid_t uid = from_kuid(&init_user_ns, task_uid(tsk));
+       uid_t loginuid = from_kuid(&init_user_ns, audit_get_loginuid(tsk));
+       u32 sessionid = audit_get_sessionid(tsk);
 
        ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_TTY);
        if (ab) {
                char name[sizeof(tsk->comm)];
-               kuid_t uid = task_uid(tsk);
-
-               audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u "
-                                "major=%d minor=%d comm=", description,
-                                tsk->pid,
-                                from_kuid(&init_user_ns, uid),
-                                from_kuid(&init_user_ns, loginuid),
-                                sessionid,
-                                major, minor);
+
+               audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u major=%d"
+                                " minor=%d comm=", description, tsk->pid, uid,
+                                loginuid, sessionid, major, minor);
                get_task_comm(name, tsk);
                audit_log_untrustedstring(ab, name);
                audit_log_format(ab, " data=");
@@ -90,11 +88,9 @@ static void tty_audit_log(const char *description, struct task_struct *tsk,
  *     tty_audit_buf_push      -       Push buffered data out
  *
  *     Generate an audit message from the contents of @buf, which is owned by
- *     @tsk with @loginuid.  @buf->mutex must be locked.
+ *     the current task.  @buf->mutex must be locked.
  */
-static void tty_audit_buf_push(struct task_struct *tsk, kuid_t loginuid,
-                              unsigned int sessionid,
-                              struct tty_audit_buf *buf)
+static void tty_audit_buf_push(struct tty_audit_buf *buf)
 {
        if (buf->valid == 0)
                return;
@@ -102,24 +98,10 @@ static void tty_audit_buf_push(struct task_struct *tsk, kuid_t loginuid,
                buf->valid = 0;
                return;
        }
-       tty_audit_log("tty", tsk, loginuid, sessionid, buf->major, buf->minor,
-                     buf->data, buf->valid);
+       tty_audit_log("tty", buf->major, buf->minor, buf->data, buf->valid);
        buf->valid = 0;
 }
 
-/**
- *     tty_audit_buf_push_current      -       Push buffered data out
- *
- *     Generate an audit message from the contents of @buf, which is owned by
- *     the current task.  @buf->mutex must be locked.
- */
-static void tty_audit_buf_push_current(struct tty_audit_buf *buf)
-{
-       kuid_t auid = audit_get_loginuid(current);
-       unsigned int sessionid = audit_get_sessionid(current);
-       tty_audit_buf_push(current, auid, sessionid, buf);
-}
-
 /**
  *     tty_audit_exit  -       Handle a task exit
  *
@@ -130,15 +112,13 @@ void tty_audit_exit(void)
 {
        struct tty_audit_buf *buf;
 
-       spin_lock_irq(&current->sighand->siglock);
        buf = current->signal->tty_audit_buf;
        current->signal->tty_audit_buf = NULL;
-       spin_unlock_irq(&current->sighand->siglock);
        if (!buf)
                return;
 
        mutex_lock(&buf->mutex);
-       tty_audit_buf_push_current(buf);
+       tty_audit_buf_push(buf);
        mutex_unlock(&buf->mutex);
 
        tty_audit_buf_put(buf);
@@ -151,9 +131,8 @@ void tty_audit_exit(void)
  */
 void tty_audit_fork(struct signal_struct *sig)
 {
-       spin_lock_irq(&current->sighand->siglock);
        sig->audit_tty = current->signal->audit_tty;
-       spin_unlock_irq(&current->sighand->siglock);
+       sig->audit_tty_log_passwd = current->signal->audit_tty_log_passwd;
 }
 
 /**
@@ -163,20 +142,21 @@ void tty_audit_tiocsti(struct tty_struct *tty, char ch)
 {
        struct tty_audit_buf *buf;
        int major, minor, should_audit;
+       unsigned long flags;
 
-       spin_lock_irq(&current->sighand->siglock);
+       spin_lock_irqsave(&current->sighand->siglock, flags);
        should_audit = current->signal->audit_tty;
        buf = current->signal->tty_audit_buf;
        if (buf)
                atomic_inc(&buf->count);
-       spin_unlock_irq(&current->sighand->siglock);
+       spin_unlock_irqrestore(&current->sighand->siglock, flags);
 
        major = tty->driver->major;
        minor = tty->driver->minor_start + tty->index;
        if (buf) {
                mutex_lock(&buf->mutex);
                if (buf->major == major && buf->minor == minor)
-                       tty_audit_buf_push_current(buf);
+                       tty_audit_buf_push(buf);
                mutex_unlock(&buf->mutex);
                tty_audit_buf_put(buf);
        }
@@ -187,24 +167,20 @@ void tty_audit_tiocsti(struct tty_struct *tty, char ch)
 
                auid = audit_get_loginuid(current);
                sessionid = audit_get_sessionid(current);
-               tty_audit_log("ioctl=TIOCSTI", current, auid, sessionid, major,
-                             minor, &ch, 1);
+               tty_audit_log("ioctl=TIOCSTI", major, minor, &ch, 1);
        }
 }
 
 /**
- * tty_audit_push_task -       Flush task's pending audit data
- * @tsk:               task pointer
- * @loginuid:          sender login uid
- * @sessionid:         sender session id
+ * tty_audit_push_current -    Flush current's pending audit data
  *
- * Called with a ref on @tsk held. Try to lock sighand and get a
- * reference to the tty audit buffer if available.
+ * Try to lock sighand and get a reference to the tty audit buffer if available.
  * Flush the buffer or return an appropriate error code.
  */
-int tty_audit_push_task(struct task_struct *tsk, kuid_t loginuid, u32 sessionid)
+int tty_audit_push_current(void)
 {
        struct tty_audit_buf *buf = ERR_PTR(-EPERM);
+       struct task_struct *tsk = current;
        unsigned long flags;
 
        if (!lock_task_sighand(tsk, &flags))
@@ -225,7 +201,7 @@ int tty_audit_push_task(struct task_struct *tsk, kuid_t loginuid, u32 sessionid)
                return PTR_ERR(buf);
 
        mutex_lock(&buf->mutex);
-       tty_audit_buf_push(tsk, loginuid, sessionid, buf);
+       tty_audit_buf_push(buf);
        mutex_unlock(&buf->mutex);
 
        tty_audit_buf_put(buf);
@@ -243,10 +219,11 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty,
                unsigned icanon)
 {
        struct tty_audit_buf *buf, *buf2;
+       unsigned long flags;
 
        buf = NULL;
        buf2 = NULL;
-       spin_lock_irq(&current->sighand->siglock);
+       spin_lock_irqsave(&current->sighand->siglock, flags);
        if (likely(!current->signal->audit_tty))
                goto out;
        buf = current->signal->tty_audit_buf;
@@ -254,7 +231,7 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty,
                atomic_inc(&buf->count);
                goto out;
        }
-       spin_unlock_irq(&current->sighand->siglock);
+       spin_unlock_irqrestore(&current->sighand->siglock, flags);
 
        buf2 = tty_audit_buf_alloc(tty->driver->major,
                                   tty->driver->minor_start + tty->index,
@@ -264,7 +241,7 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty,
                return NULL;
        }
 
-       spin_lock_irq(&current->sighand->siglock);
+       spin_lock_irqsave(&current->sighand->siglock, flags);
        if (!current->signal->audit_tty)
                goto out;
        buf = current->signal->tty_audit_buf;
@@ -276,7 +253,7 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty,
        atomic_inc(&buf->count);
        /* Fall through */
  out:
-       spin_unlock_irq(&current->sighand->siglock);
+       spin_unlock_irqrestore(&current->sighand->siglock, flags);
        if (buf2)
                tty_audit_buf_free(buf2);
        return buf;
@@ -292,10 +269,18 @@ void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
 {
        struct tty_audit_buf *buf;
        int major, minor;
+       int audit_log_tty_passwd;
+       unsigned long flags;
 
        if (unlikely(size == 0))
                return;
 
+       spin_lock_irqsave(&current->sighand->siglock, flags);
+       audit_log_tty_passwd = current->signal->audit_tty_log_passwd;
+       spin_unlock_irqrestore(&current->sighand->siglock, flags);
+       if (!audit_log_tty_passwd && icanon && !L_ECHO(tty))
+               return;
+
        if (tty->driver->type == TTY_DRIVER_TYPE_PTY
            && tty->driver->subtype == PTY_TYPE_MASTER)
                return;
@@ -309,7 +294,7 @@ void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
        minor = tty->driver->minor_start + tty->index;
        if (buf->major != major || buf->minor != minor
            || buf->icanon != icanon) {
-               tty_audit_buf_push_current(buf);
+               tty_audit_buf_push(buf);
                buf->major = major;
                buf->minor = minor;
                buf->icanon = icanon;
@@ -325,7 +310,7 @@ void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
                data += run;
                size -= run;
                if (buf->valid == N_TTY_BUF_SIZE)
-                       tty_audit_buf_push_current(buf);
+                       tty_audit_buf_push(buf);
        } while (size != 0);
        mutex_unlock(&buf->mutex);
        tty_audit_buf_put(buf);
@@ -339,16 +324,17 @@ void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
 void tty_audit_push(struct tty_struct *tty)
 {
        struct tty_audit_buf *buf;
+       unsigned long flags;
 
-       spin_lock_irq(&current->sighand->siglock);
+       spin_lock_irqsave(&current->sighand->siglock, flags);
        if (likely(!current->signal->audit_tty)) {
-               spin_unlock_irq(&current->sighand->siglock);
+               spin_unlock_irqrestore(&current->sighand->siglock, flags);
                return;
        }
        buf = current->signal->tty_audit_buf;
        if (buf)
                atomic_inc(&buf->count);
-       spin_unlock_irq(&current->sighand->siglock);
+       spin_unlock_irqrestore(&current->sighand->siglock, flags);
 
        if (buf) {
                int major, minor;
@@ -357,7 +343,7 @@ void tty_audit_push(struct tty_struct *tty)
                minor = tty->driver->minor_start + tty->index;
                mutex_lock(&buf->mutex);
                if (buf->major == major && buf->minor == minor)
-                       tty_audit_buf_push_current(buf);
+                       tty_audit_buf_push(buf);
                mutex_unlock(&buf->mutex);
                tty_audit_buf_put(buf);
        }
index 57ae9c8c66bfc6d98ae96643874710cdc3de321a..85e40d1c0a8fd64b358447ee09b26f906102ee1d 100644 (file)
@@ -2740,7 +2740,7 @@ static int do_last(struct nameidata *nd, struct path *path,
                if (error)
                        return error;
 
-               audit_inode(name, dir, 0);
+               audit_inode(name, dir, LOOKUP_PARENT);
                error = -EISDIR;
                /* trailing slashes? */
                if (nd->last.name[nd->last.len])
index 5a6d718adf34825eb11bc4dd20cbcb8f1dced0ad..b20b03852f21dd722e405c4685f2c9851588ed98 100644 (file)
@@ -84,8 +84,13 @@ extern int audit_classify_arch(int arch);
 #define        AUDIT_TYPE_CHILD_DELETE 3       /* a child being deleted */
 #define        AUDIT_TYPE_CHILD_CREATE 4       /* a child being created */
 
+/* maximized args number that audit_socketcall can process */
+#define AUDITSC_ARGS           6
+
 struct filename;
 
+extern void audit_log_session_info(struct audit_buffer *ab);
+
 #ifdef CONFIG_AUDITSYSCALL
 /* These are defined in auditsc.c */
                                /* Public API */
@@ -120,7 +125,7 @@ static inline void audit_syscall_entry(int arch, int major, unsigned long a0,
                                       unsigned long a1, unsigned long a2,
                                       unsigned long a3)
 {
-       if (unlikely(!audit_dummy_context()))
+       if (unlikely(current->audit_context))
                __audit_syscall_entry(arch, major, a0, a1, a2, a3);
 }
 static inline void audit_syscall_exit(void *pt_regs)
@@ -185,12 +190,10 @@ static inline int audit_get_sessionid(struct task_struct *tsk)
        return tsk->sessionid;
 }
 
-extern void audit_log_task_context(struct audit_buffer *ab);
-extern void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk);
 extern void __audit_ipc_obj(struct kern_ipc_perm *ipcp);
 extern void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mode);
 extern int __audit_bprm(struct linux_binprm *bprm);
-extern void __audit_socketcall(int nargs, unsigned long *args);
+extern int __audit_socketcall(int nargs, unsigned long *args);
 extern int __audit_sockaddr(int len, void *addr);
 extern void __audit_fd_pair(int fd1, int fd2);
 extern void __audit_mq_open(int oflag, umode_t mode, struct mq_attr *attr);
@@ -224,10 +227,11 @@ static inline int audit_bprm(struct linux_binprm *bprm)
                return __audit_bprm(bprm);
        return 0;
 }
-static inline void audit_socketcall(int nargs, unsigned long *args)
+static inline int audit_socketcall(int nargs, unsigned long *args)
 {
        if (unlikely(!audit_dummy_context()))
-               __audit_socketcall(nargs, args);
+               return __audit_socketcall(nargs, args);
+       return 0;
 }
 static inline int audit_sockaddr(int len, void *addr)
 {
@@ -340,11 +344,6 @@ static inline int audit_get_sessionid(struct task_struct *tsk)
 {
        return -1;
 }
-static inline void audit_log_task_context(struct audit_buffer *ab)
-{ }
-static inline void audit_log_task_info(struct audit_buffer *ab,
-                                      struct task_struct *tsk)
-{ }
 static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp)
 { }
 static inline void audit_ipc_set_perm(unsigned long qbytes, uid_t uid,
@@ -354,8 +353,10 @@ static inline int audit_bprm(struct linux_binprm *bprm)
 {
        return 0;
 }
-static inline void audit_socketcall(int nargs, unsigned long *args)
-{ }
+static inline int audit_socketcall(int nargs, unsigned long *args)
+{
+       return 0;
+}
 static inline void audit_fd_pair(int fd1, int fd2)
 { }
 static inline int audit_sockaddr(int len, void *addr)
@@ -390,6 +391,11 @@ static inline void audit_ptrace(struct task_struct *t)
 #define audit_signals 0
 #endif /* CONFIG_AUDITSYSCALL */
 
+static inline bool audit_loginuid_set(struct task_struct *tsk)
+{
+       return uid_valid(audit_get_loginuid(tsk));
+}
+
 #ifdef CONFIG_AUDIT
 /* These are defined in audit.c */
                                /* Public API */
@@ -429,14 +435,17 @@ static inline void            audit_log_secctx(struct audit_buffer *ab, u32 secid)
 { }
 #endif
 
+extern int audit_log_task_context(struct audit_buffer *ab);
+extern void audit_log_task_info(struct audit_buffer *ab,
+                               struct task_struct *tsk);
+
 extern int                 audit_update_lsm_rules(void);
 
                                /* Private API (for audit.c only) */
-extern int audit_filter_user(void);
+extern int audit_filter_user(int type);
 extern int audit_filter_type(int type);
 extern int  audit_receive_filter(int type, int pid, int seq,
-                               void *data, size_t datasz, kuid_t loginuid,
-                               u32 sessionid, u32 sid);
+                               void *data, size_t datasz);
 extern int audit_enabled;
 #else /* CONFIG_AUDIT */
 static inline __printf(4, 5)
@@ -476,6 +485,13 @@ static inline void audit_log_link_denied(const char *string,
 { }
 static inline void audit_log_secctx(struct audit_buffer *ab, u32 secid)
 { }
+static inline int audit_log_task_context(struct audit_buffer *ab)
+{
+       return 0;
+}
+static inline void audit_log_task_info(struct audit_buffer *ab,
+                                      struct task_struct *tsk)
+{ }
 #define audit_enabled 0
 #endif /* CONFIG_AUDIT */
 static inline void audit_log_string(struct audit_buffer *ab, const char *buf)
index caa8f4d0186b742c3effc99c296ac99724f2f4d1..178a8d909f14a3dcdcbc0ce255572975c8b3b221 100644 (file)
@@ -593,6 +593,7 @@ struct signal_struct {
 #endif
 #ifdef CONFIG_AUDIT
        unsigned audit_tty;
+       unsigned audit_tty_log_passwd;
        struct tty_audit_buf *tty_audit_buf;
 #endif
 #ifdef CONFIG_CGROUPS
index 7e92bd86a808cfbdf31bf38f1165ab30fe93c2ff..8780bd2a272ab6672c8f6c32340b7d1ab2831acb 100644 (file)
@@ -575,8 +575,7 @@ extern void tty_audit_exit(void);
 extern void tty_audit_fork(struct signal_struct *sig);
 extern void tty_audit_tiocsti(struct tty_struct *tty, char ch);
 extern void tty_audit_push(struct tty_struct *tty);
-extern int tty_audit_push_task(struct task_struct *tsk,
-                              kuid_t loginuid, u32 sessionid);
+extern int tty_audit_push_current(void);
 #else
 static inline void tty_audit_add_data(struct tty_struct *tty,
                unsigned char *data, size_t size, unsigned icanon)
@@ -594,8 +593,7 @@ static inline void tty_audit_fork(struct signal_struct *sig)
 static inline void tty_audit_push(struct tty_struct *tty)
 {
 }
-static inline int tty_audit_push_task(struct task_struct *tsk,
-                                     kuid_t loginuid, u32 sessionid)
+static inline int tty_audit_push_current(void)
 {
        return 0;
 }
index 9f096f1c0907b7056bcbe396783fdb2237724a65..75cef3fd97add201693b6bf21f4e2f1754c96f43 100644 (file)
 #define AUDIT_OBJ_TYPE 21
 #define AUDIT_OBJ_LEV_LOW      22
 #define AUDIT_OBJ_LEV_HIGH     23
+#define AUDIT_LOGINUID_SET     24
 
                                /* These are ONLY useful when checking
                                 * at syscall exit time (AUDIT_AT_EXIT). */
@@ -369,7 +370,8 @@ struct audit_status {
 };
 
 struct audit_tty_status {
-       __u32           enabled; /* 1 = enabled, 0 = disabled */
+       __u32           enabled;        /* 1 = enabled, 0 = disabled */
+       __u32           log_passwd;     /* 1 = enabled, 0 = disabled */
 };
 
 /* audit_rule_data supports filter rules with both integer and string
index 0b084fa44b1f21f3cc73508676e79d58b08f1896..21c7fa615bd3107b0c28a4da499ea3ee7361d695 100644 (file)
@@ -49,6 +49,8 @@
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/kthread.h>
+#include <linux/kernel.h>
+#include <linux/syscalls.h>
 
 #include <linux/audit.h>
 
@@ -265,7 +267,6 @@ void audit_log_lost(const char *message)
 }
 
 static int audit_log_config_change(char *function_name, int new, int old,
-                                  kuid_t loginuid, u32 sessionid, u32 sid,
                                   int allow_changes)
 {
        struct audit_buffer *ab;
@@ -274,29 +275,17 @@ static int audit_log_config_change(char *function_name, int new, int old,
        ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
        if (unlikely(!ab))
                return rc;
-       audit_log_format(ab, "%s=%d old=%d auid=%u ses=%u", function_name, new,
-                        old, from_kuid(&init_user_ns, loginuid), sessionid);
-       if (sid) {
-               char *ctx = NULL;
-               u32 len;
-
-               rc = security_secid_to_secctx(sid, &ctx, &len);
-               if (rc) {
-                       audit_log_format(ab, " sid=%u", sid);
-                       allow_changes = 0; /* Something weird, deny request */
-               } else {
-                       audit_log_format(ab, " subj=%s", ctx);
-                       security_release_secctx(ctx, len);
-               }
-       }
+       audit_log_format(ab, "%s=%d old=%d", function_name, new, old);
+       audit_log_session_info(ab);
+       rc = audit_log_task_context(ab);
+       if (rc)
+               allow_changes = 0; /* Something weird, deny request */
        audit_log_format(ab, " res=%d", allow_changes);
        audit_log_end(ab);
        return rc;
 }
 
-static int audit_do_config_change(char *function_name, int *to_change,
-                                 int new, kuid_t loginuid, u32 sessionid,
-                                 u32 sid)
+static int audit_do_config_change(char *function_name, int *to_change, int new)
 {
        int allow_changes, rc = 0, old = *to_change;
 
@@ -307,8 +296,7 @@ static int audit_do_config_change(char *function_name, int *to_change,
                allow_changes = 1;
 
        if (audit_enabled != AUDIT_OFF) {
-               rc = audit_log_config_change(function_name, new, old, loginuid,
-                                            sessionid, sid, allow_changes);
+               rc = audit_log_config_change(function_name, new, old, allow_changes);
                if (rc)
                        allow_changes = 0;
        }
@@ -322,44 +310,37 @@ static int audit_do_config_change(char *function_name, int *to_change,
        return rc;
 }
 
-static int audit_set_rate_limit(int limit, kuid_t loginuid, u32 sessionid,
-                               u32 sid)
+static int audit_set_rate_limit(int limit)
 {
-       return audit_do_config_change("audit_rate_limit", &audit_rate_limit,
-                                     limit, loginuid, sessionid, sid);
+       return audit_do_config_change("audit_rate_limit", &audit_rate_limit, limit);
 }
 
-static int audit_set_backlog_limit(int limit, kuid_t loginuid, u32 sessionid,
-                                  u32 sid)
+static int audit_set_backlog_limit(int limit)
 {
-       return audit_do_config_change("audit_backlog_limit", &audit_backlog_limit,
-                                     limit, loginuid, sessionid, sid);
+       return audit_do_config_change("audit_backlog_limit", &audit_backlog_limit, limit);
 }
 
-static int audit_set_enabled(int state, kuid_t loginuid, u32 sessionid, u32 sid)
+static int audit_set_enabled(int state)
 {
        int rc;
        if (state < AUDIT_OFF || state > AUDIT_LOCKED)
                return -EINVAL;
 
-       rc =  audit_do_config_change("audit_enabled", &audit_enabled, state,
-                                    loginuid, sessionid, sid);
-
+       rc =  audit_do_config_change("audit_enabled", &audit_enabled, state);
        if (!rc)
                audit_ever_enabled |= !!state;
 
        return rc;
 }
 
-static int audit_set_failure(int state, kuid_t loginuid, u32 sessionid, u32 sid)
+static int audit_set_failure(int state)
 {
        if (state != AUDIT_FAIL_SILENT
            && state != AUDIT_FAIL_PRINTK
            && state != AUDIT_FAIL_PANIC)
                return -EINVAL;
 
-       return audit_do_config_change("audit_failure", &audit_failure, state,
-                                     loginuid, sessionid, sid);
+       return audit_do_config_change("audit_failure", &audit_failure, state);
 }
 
 /*
@@ -417,34 +398,53 @@ static void kauditd_send_skb(struct sk_buff *skb)
                consume_skb(skb);
 }
 
-static int kauditd_thread(void *dummy)
+/*
+ * flush_hold_queue - empty the hold queue if auditd appears
+ *
+ * If auditd just started, drain the queue of messages already
+ * sent to syslog/printk.  Remember loss here is ok.  We already
+ * called audit_log_lost() if it didn't go out normally.  so the
+ * race between the skb_dequeue and the next check for audit_pid
+ * doesn't matter.
+ *
+ * If you ever find kauditd to be too slow we can get a perf win
+ * by doing our own locking and keeping better track if there
+ * are messages in this queue.  I don't see the need now, but
+ * in 5 years when I want to play with this again I'll see this
+ * note and still have no friggin idea what i'm thinking today.
+ */
+static void flush_hold_queue(void)
 {
        struct sk_buff *skb;
 
+       if (!audit_default || !audit_pid)
+               return;
+
+       skb = skb_dequeue(&audit_skb_hold_queue);
+       if (likely(!skb))
+               return;
+
+       while (skb && audit_pid) {
+               kauditd_send_skb(skb);
+               skb = skb_dequeue(&audit_skb_hold_queue);
+       }
+
+       /*
+        * if auditd just disappeared but we
+        * dequeued an skb we need to drop ref
+        */
+       if (skb)
+               consume_skb(skb);
+}
+
+static int kauditd_thread(void *dummy)
+{
        set_freezable();
        while (!kthread_should_stop()) {
-               /*
-                * if auditd just started drain the queue of messages already
-                * sent to syslog/printk.  remember loss here is ok.  we already
-                * called audit_log_lost() if it didn't go out normally.  so the
-                * race between the skb_dequeue and the next check for audit_pid
-                * doesn't matter.
-                *
-                * if you ever find kauditd to be too slow we can get a perf win
-                * by doing our own locking and keeping better track if there
-                * are messages in this queue.  I don't see the need now, but
-                * in 5 years when I want to play with this again I'll see this
-                * note and still have no friggin idea what i'm thinking today.
-                */
-               if (audit_default && audit_pid) {
-                       skb = skb_dequeue(&audit_skb_hold_queue);
-                       if (unlikely(skb)) {
-                               while (skb && audit_pid) {
-                                       kauditd_send_skb(skb);
-                                       skb = skb_dequeue(&audit_skb_hold_queue);
-                               }
-                       }
-               }
+               struct sk_buff *skb;
+               DECLARE_WAITQUEUE(wait, current);
+
+               flush_hold_queue();
 
                skb = skb_dequeue(&audit_skb_queue);
                wake_up(&audit_backlog_wait);
@@ -453,19 +453,18 @@ static int kauditd_thread(void *dummy)
                                kauditd_send_skb(skb);
                        else
                                audit_printk_skb(skb);
-               } else {
-                       DECLARE_WAITQUEUE(wait, current);
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       add_wait_queue(&kauditd_wait, &wait);
-
-                       if (!skb_queue_len(&audit_skb_queue)) {
-                               try_to_freeze();
-                               schedule();
-                       }
+                       continue;
+               }
+               set_current_state(TASK_INTERRUPTIBLE);
+               add_wait_queue(&kauditd_wait, &wait);
 
-                       __set_current_state(TASK_RUNNING);
-                       remove_wait_queue(&kauditd_wait, &wait);
+               if (!skb_queue_len(&audit_skb_queue)) {
+                       try_to_freeze();
+                       schedule();
                }
+
+               __set_current_state(TASK_RUNNING);
+               remove_wait_queue(&kauditd_wait, &wait);
        }
        return 0;
 }
@@ -579,13 +578,14 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
                return -EPERM;
 
        switch (msg_type) {
-       case AUDIT_GET:
        case AUDIT_LIST:
-       case AUDIT_LIST_RULES:
-       case AUDIT_SET:
        case AUDIT_ADD:
-       case AUDIT_ADD_RULE:
        case AUDIT_DEL:
+               return -EOPNOTSUPP;
+       case AUDIT_GET:
+       case AUDIT_SET:
+       case AUDIT_LIST_RULES:
+       case AUDIT_ADD_RULE:
        case AUDIT_DEL_RULE:
        case AUDIT_SIGNAL_INFO:
        case AUDIT_TTY_GET:
@@ -608,12 +608,10 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
        return err;
 }
 
-static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type,
-                                    kuid_t auid, u32 ses, u32 sid)
+static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type)
 {
        int rc = 0;
-       char *ctx = NULL;
-       u32 len;
+       uid_t uid = from_kuid(&init_user_ns, current_uid());
 
        if (!audit_enabled) {
                *ab = NULL;
@@ -623,33 +621,21 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type,
        *ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
        if (unlikely(!*ab))
                return rc;
-       audit_log_format(*ab, "pid=%d uid=%u auid=%u ses=%u",
-                        task_tgid_vnr(current),
-                        from_kuid(&init_user_ns, current_uid()),
-                        from_kuid(&init_user_ns, auid), ses);
-       if (sid) {
-               rc = security_secid_to_secctx(sid, &ctx, &len);
-               if (rc)
-                       audit_log_format(*ab, " ssid=%u", sid);
-               else {
-                       audit_log_format(*ab, " subj=%s", ctx);
-                       security_release_secctx(ctx, len);
-               }
-       }
+       audit_log_format(*ab, "pid=%d uid=%u", task_tgid_vnr(current), uid);
+       audit_log_session_info(*ab);
+       audit_log_task_context(*ab);
 
        return rc;
 }
 
 static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
-       u32                     seq, sid;
+       u32                     seq;
        void                    *data;
        struct audit_status     *status_get, status_set;
        int                     err;
        struct audit_buffer     *ab;
        u16                     msg_type = nlh->nlmsg_type;
-       kuid_t                  loginuid; /* loginuid of sender */
-       u32                     sessionid;
        struct audit_sig_info   *sig_data;
        char                    *ctx = NULL;
        u32                     len;
@@ -668,9 +654,6 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                        return err;
                }
        }
-       loginuid = audit_get_loginuid(current);
-       sessionid = audit_get_sessionid(current);
-       security_task_getsecid(current, &sid);
        seq  = nlh->nlmsg_seq;
        data = nlmsg_data(nlh);
 
@@ -691,14 +674,12 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                        return -EINVAL;
                status_get   = (struct audit_status *)data;
                if (status_get->mask & AUDIT_STATUS_ENABLED) {
-                       err = audit_set_enabled(status_get->enabled,
-                                               loginuid, sessionid, sid);
+                       err = audit_set_enabled(status_get->enabled);
                        if (err < 0)
                                return err;
                }
                if (status_get->mask & AUDIT_STATUS_FAILURE) {
-                       err = audit_set_failure(status_get->failure,
-                                               loginuid, sessionid, sid);
+                       err = audit_set_failure(status_get->failure);
                        if (err < 0)
                                return err;
                }
@@ -706,22 +687,17 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                        int new_pid = status_get->pid;
 
                        if (audit_enabled != AUDIT_OFF)
-                               audit_log_config_change("audit_pid", new_pid,
-                                                       audit_pid, loginuid,
-                                                       sessionid, sid, 1);
-
+                               audit_log_config_change("audit_pid", new_pid, audit_pid, 1);
                        audit_pid = new_pid;
                        audit_nlk_portid = NETLINK_CB(skb).portid;
                }
                if (status_get->mask & AUDIT_STATUS_RATE_LIMIT) {
-                       err = audit_set_rate_limit(status_get->rate_limit,
-                                                  loginuid, sessionid, sid);
+                       err = audit_set_rate_limit(status_get->rate_limit);
                        if (err < 0)
                                return err;
                }
                if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT)
-                       err = audit_set_backlog_limit(status_get->backlog_limit,
-                                                     loginuid, sessionid, sid);
+                       err = audit_set_backlog_limit(status_get->backlog_limit);
                break;
        case AUDIT_USER:
        case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
@@ -729,25 +705,22 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                if (!audit_enabled && msg_type != AUDIT_USER_AVC)
                        return 0;
 
-               err = audit_filter_user();
+               err = audit_filter_user(msg_type);
                if (err == 1) {
                        err = 0;
                        if (msg_type == AUDIT_USER_TTY) {
-                               err = tty_audit_push_task(current, loginuid,
-                                                            sessionid);
+                               err = tty_audit_push_current();
                                if (err)
                                        break;
                        }
-                       audit_log_common_recv_msg(&ab, msg_type,
-                                                 loginuid, sessionid, sid);
-
+                       audit_log_common_recv_msg(&ab, msg_type);
                        if (msg_type != AUDIT_USER_TTY)
                                audit_log_format(ab, " msg='%.1024s'",
                                                 (char *)data);
                        else {
                                int size;
 
-                               audit_log_format(ab, " msg=");
+                               audit_log_format(ab, " data=");
                                size = nlmsg_len(nlh);
                                if (size > 0 &&
                                    ((unsigned char *)data)[size - 1] == '\0')
@@ -758,50 +731,24 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                        audit_log_end(ab);
                }
                break;
-       case AUDIT_ADD:
-       case AUDIT_DEL:
-               if (nlmsg_len(nlh) < sizeof(struct audit_rule))
-                       return -EINVAL;
-               if (audit_enabled == AUDIT_LOCKED) {
-                       audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE,
-                                                 loginuid, sessionid, sid);
-
-                       audit_log_format(ab, " audit_enabled=%d res=0",
-                                        audit_enabled);
-                       audit_log_end(ab);
-                       return -EPERM;
-               }
-               /* fallthrough */
-       case AUDIT_LIST:
-               err = audit_receive_filter(msg_type, NETLINK_CB(skb).portid,
-                                          seq, data, nlmsg_len(nlh),
-                                          loginuid, sessionid, sid);
-               break;
        case AUDIT_ADD_RULE:
        case AUDIT_DEL_RULE:
                if (nlmsg_len(nlh) < sizeof(struct audit_rule_data))
                        return -EINVAL;
                if (audit_enabled == AUDIT_LOCKED) {
-                       audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE,
-                                                 loginuid, sessionid, sid);
-
-                       audit_log_format(ab, " audit_enabled=%d res=0",
-                                        audit_enabled);
+                       audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE);
+                       audit_log_format(ab, " audit_enabled=%d res=0", audit_enabled);
                        audit_log_end(ab);
                        return -EPERM;
                }
                /* fallthrough */
        case AUDIT_LIST_RULES:
                err = audit_receive_filter(msg_type, NETLINK_CB(skb).portid,
-                                          seq, data, nlmsg_len(nlh),
-                                          loginuid, sessionid, sid);
+                                          seq, data, nlmsg_len(nlh));
                break;
        case AUDIT_TRIM:
                audit_trim_trees();
-
-               audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE,
-                                         loginuid, sessionid, sid);
-
+               audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE);
                audit_log_format(ab, " op=trim res=1");
                audit_log_end(ab);
                break;
@@ -831,8 +778,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                /* OK, here comes... */
                err = audit_tag_tree(old, new);
 
-               audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE,
-                                         loginuid, sessionid, sid);
+               audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE);
 
                audit_log_format(ab, " op=make_equiv old=");
                audit_log_untrustedstring(ab, old);
@@ -871,27 +817,30 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                struct audit_tty_status s;
                struct task_struct *tsk = current;
 
-               spin_lock_irq(&tsk->sighand->siglock);
+               spin_lock(&tsk->sighand->siglock);
                s.enabled = tsk->signal->audit_tty != 0;
-               spin_unlock_irq(&tsk->sighand->siglock);
+               s.log_passwd = tsk->signal->audit_tty_log_passwd;
+               spin_unlock(&tsk->sighand->siglock);
 
                audit_send_reply(NETLINK_CB(skb).portid, seq,
                                 AUDIT_TTY_GET, 0, 0, &s, sizeof(s));
                break;
        }
        case AUDIT_TTY_SET: {
-               struct audit_tty_status *s;
+               struct audit_tty_status s;
                struct task_struct *tsk = current;
 
-               if (nlh->nlmsg_len < sizeof(struct audit_tty_status))
-                       return -EINVAL;
-               s = data;
-               if (s->enabled != 0 && s->enabled != 1)
+               memset(&s, 0, sizeof(s));
+               /* guard against past and future API changes */
+               memcpy(&s, data, min(sizeof(s), (size_t)nlh->nlmsg_len));
+               if ((s.enabled != 0 && s.enabled != 1) ||
+                   (s.log_passwd != 0 && s.log_passwd != 1))
                        return -EINVAL;
 
-               spin_lock_irq(&tsk->sighand->siglock);
-               tsk->signal->audit_tty = s->enabled != 0;
-               spin_unlock_irq(&tsk->sighand->siglock);
+               spin_lock(&tsk->sighand->siglock);
+               tsk->signal->audit_tty = s.enabled;
+               tsk->signal->audit_tty_log_passwd = s.log_passwd;
+               spin_unlock(&tsk->sighand->siglock);
                break;
        }
        default:
@@ -1434,6 +1383,14 @@ void audit_log_d_path(struct audit_buffer *ab, const char *prefix,
        kfree(pathname);
 }
 
+void audit_log_session_info(struct audit_buffer *ab)
+{
+       u32 sessionid = audit_get_sessionid(current);
+       uid_t auid = from_kuid(&init_user_ns, audit_get_loginuid(current));
+
+       audit_log_format(ab, " auid=%u ses=%u\n", auid, sessionid);
+}
+
 void audit_log_key(struct audit_buffer *ab, char *key)
 {
        audit_log_format(ab, " key=");
@@ -1443,6 +1400,224 @@ void audit_log_key(struct audit_buffer *ab, char *key)
                audit_log_format(ab, "(null)");
 }
 
+void audit_log_cap(struct audit_buffer *ab, char *prefix, kernel_cap_t *cap)
+{
+       int i;
+
+       audit_log_format(ab, " %s=", prefix);
+       CAP_FOR_EACH_U32(i) {
+               audit_log_format(ab, "%08x",
+                                cap->cap[(_KERNEL_CAPABILITY_U32S-1) - i]);
+       }
+}
+
+void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name)
+{
+       kernel_cap_t *perm = &name->fcap.permitted;
+       kernel_cap_t *inh = &name->fcap.inheritable;
+       int log = 0;
+
+       if (!cap_isclear(*perm)) {
+               audit_log_cap(ab, "cap_fp", perm);
+               log = 1;
+       }
+       if (!cap_isclear(*inh)) {
+               audit_log_cap(ab, "cap_fi", inh);
+               log = 1;
+       }
+
+       if (log)
+               audit_log_format(ab, " cap_fe=%d cap_fver=%x",
+                                name->fcap.fE, name->fcap_ver);
+}
+
+static inline int audit_copy_fcaps(struct audit_names *name,
+                                  const struct dentry *dentry)
+{
+       struct cpu_vfs_cap_data caps;
+       int rc;
+
+       if (!dentry)
+               return 0;
+
+       rc = get_vfs_caps_from_disk(dentry, &caps);
+       if (rc)
+               return rc;
+
+       name->fcap.permitted = caps.permitted;
+       name->fcap.inheritable = caps.inheritable;
+       name->fcap.fE = !!(caps.magic_etc & VFS_CAP_FLAGS_EFFECTIVE);
+       name->fcap_ver = (caps.magic_etc & VFS_CAP_REVISION_MASK) >>
+                               VFS_CAP_REVISION_SHIFT;
+
+       return 0;
+}
+
+/* Copy inode data into an audit_names. */
+void audit_copy_inode(struct audit_names *name, const struct dentry *dentry,
+                     const struct inode *inode)
+{
+       name->ino   = inode->i_ino;
+       name->dev   = inode->i_sb->s_dev;
+       name->mode  = inode->i_mode;
+       name->uid   = inode->i_uid;
+       name->gid   = inode->i_gid;
+       name->rdev  = inode->i_rdev;
+       security_inode_getsecid(inode, &name->osid);
+       audit_copy_fcaps(name, dentry);
+}
+
+/**
+ * audit_log_name - produce AUDIT_PATH record from struct audit_names
+ * @context: audit_context for the task
+ * @n: audit_names structure with reportable details
+ * @path: optional path to report instead of audit_names->name
+ * @record_num: record number to report when handling a list of names
+ * @call_panic: optional pointer to int that will be updated if secid fails
+ */
+void audit_log_name(struct audit_context *context, struct audit_names *n,
+                   struct path *path, int record_num, int *call_panic)
+{
+       struct audit_buffer *ab;
+       ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH);
+       if (!ab)
+               return;
+
+       audit_log_format(ab, "item=%d", record_num);
+
+       if (path)
+               audit_log_d_path(ab, " name=", path);
+       else if (n->name) {
+               switch (n->name_len) {
+               case AUDIT_NAME_FULL:
+                       /* log the full path */
+                       audit_log_format(ab, " name=");
+                       audit_log_untrustedstring(ab, n->name->name);
+                       break;
+               case 0:
+                       /* name was specified as a relative path and the
+                        * directory component is the cwd */
+                       audit_log_d_path(ab, " name=", &context->pwd);
+                       break;
+               default:
+                       /* log the name's directory component */
+                       audit_log_format(ab, " name=");
+                       audit_log_n_untrustedstring(ab, n->name->name,
+                                                   n->name_len);
+               }
+       } else
+               audit_log_format(ab, " name=(null)");
+
+       if (n->ino != (unsigned long)-1) {
+               audit_log_format(ab, " inode=%lu"
+                                " dev=%02x:%02x mode=%#ho"
+                                " ouid=%u ogid=%u rdev=%02x:%02x",
+                                n->ino,
+                                MAJOR(n->dev),
+                                MINOR(n->dev),
+                                n->mode,
+                                from_kuid(&init_user_ns, n->uid),
+                                from_kgid(&init_user_ns, n->gid),
+                                MAJOR(n->rdev),
+                                MINOR(n->rdev));
+       }
+       if (n->osid != 0) {
+               char *ctx = NULL;
+               u32 len;
+               if (security_secid_to_secctx(
+                       n->osid, &ctx, &len)) {
+                       audit_log_format(ab, " osid=%u", n->osid);
+                       if (call_panic)
+                               *call_panic = 2;
+               } else {
+                       audit_log_format(ab, " obj=%s", ctx);
+                       security_release_secctx(ctx, len);
+               }
+       }
+
+       audit_log_fcaps(ab, n);
+       audit_log_end(ab);
+}
+
+int audit_log_task_context(struct audit_buffer *ab)
+{
+       char *ctx = NULL;
+       unsigned len;
+       int error;
+       u32 sid;
+
+       security_task_getsecid(current, &sid);
+       if (!sid)
+               return 0;
+
+       error = security_secid_to_secctx(sid, &ctx, &len);
+       if (error) {
+               if (error != -EINVAL)
+                       goto error_path;
+               return 0;
+       }
+
+       audit_log_format(ab, " subj=%s", ctx);
+       security_release_secctx(ctx, len);
+       return 0;
+
+error_path:
+       audit_panic("error in audit_log_task_context");
+       return error;
+}
+EXPORT_SYMBOL(audit_log_task_context);
+
+void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk)
+{
+       const struct cred *cred;
+       char name[sizeof(tsk->comm)];
+       struct mm_struct *mm = tsk->mm;
+       char *tty;
+
+       if (!ab)
+               return;
+
+       /* tsk == current */
+       cred = current_cred();
+
+       spin_lock_irq(&tsk->sighand->siglock);
+       if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name)
+               tty = tsk->signal->tty->name;
+       else
+               tty = "(none)";
+       spin_unlock_irq(&tsk->sighand->siglock);
+
+       audit_log_format(ab,
+                        " ppid=%ld pid=%d auid=%u uid=%u gid=%u"
+                        " euid=%u suid=%u fsuid=%u"
+                        " egid=%u sgid=%u fsgid=%u ses=%u tty=%s",
+                        sys_getppid(),
+                        tsk->pid,
+                        from_kuid(&init_user_ns, audit_get_loginuid(tsk)),
+                        from_kuid(&init_user_ns, cred->uid),
+                        from_kgid(&init_user_ns, cred->gid),
+                        from_kuid(&init_user_ns, cred->euid),
+                        from_kuid(&init_user_ns, cred->suid),
+                        from_kuid(&init_user_ns, cred->fsuid),
+                        from_kgid(&init_user_ns, cred->egid),
+                        from_kgid(&init_user_ns, cred->sgid),
+                        from_kgid(&init_user_ns, cred->fsgid),
+                        audit_get_sessionid(tsk), tty);
+
+       get_task_comm(name, tsk);
+       audit_log_format(ab, " comm=");
+       audit_log_untrustedstring(ab, name);
+
+       if (mm) {
+               down_read(&mm->mmap_sem);
+               if (mm->exe_file)
+                       audit_log_d_path(ab, " exe=", &mm->exe_file->f_path);
+               up_read(&mm->mmap_sem);
+       }
+       audit_log_task_context(ab);
+}
+EXPORT_SYMBOL(audit_log_task_info);
+
 /**
  * audit_log_link_denied - report a link restriction denial
  * @operation: specific link opreation
@@ -1451,19 +1626,28 @@ void audit_log_key(struct audit_buffer *ab, char *key)
 void audit_log_link_denied(const char *operation, struct path *link)
 {
        struct audit_buffer *ab;
+       struct audit_names *name;
+
+       name = kzalloc(sizeof(*name), GFP_NOFS);
+       if (!name)
+               return;
 
+       /* Generate AUDIT_ANOM_LINK with subject, operation, outcome. */
        ab = audit_log_start(current->audit_context, GFP_KERNEL,
                             AUDIT_ANOM_LINK);
        if (!ab)
-               return;
-       audit_log_format(ab, "op=%s action=denied", operation);
-       audit_log_format(ab, " pid=%d comm=", current->pid);
-       audit_log_untrustedstring(ab, current->comm);
-       audit_log_d_path(ab, " path=", link);
-       audit_log_format(ab, " dev=");
-       audit_log_untrustedstring(ab, link->dentry->d_inode->i_sb->s_id);
-       audit_log_format(ab, " ino=%lu", link->dentry->d_inode->i_ino);
+               goto out;
+       audit_log_format(ab, "op=%s", operation);
+       audit_log_task_info(ab, current);
+       audit_log_format(ab, " res=0");
        audit_log_end(ab);
+
+       /* Generate AUDIT_PATH record with object. */
+       name->type = AUDIT_TYPE_NORMAL;
+       audit_copy_inode(name, link->dentry, link->dentry->d_inode);
+       audit_log_name(current->audit_context, name, link, 0, NULL);
+out:
+       kfree(name);
 }
 
 /**
index 11468d99dad00b9f168071701c35965cf49ae585..1c95131ef760c2f45d140efdccfd2d08636b76d7 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/fs.h>
 #include <linux/audit.h>
 #include <linux/skbuff.h>
+#include <uapi/linux/mqueue.h>
 
 /* 0 = no checking
    1 = put_count checking
 */
 #define AUDIT_DEBUG 0
 
+/* AUDIT_NAMES is the number of slots we reserve in the audit_context
+ * for saving names from getname().  If we get more names we will allocate
+ * a name dynamically and also add those to the list anchored by names_list. */
+#define AUDIT_NAMES    5
+
 /* At task start time, the audit_state is set in the audit_context using
    a per-task filter.  At syscall entry, the audit_state is augmented by
    the syscall filter. */
@@ -59,8 +65,158 @@ struct audit_entry {
        struct audit_krule      rule;
 };
 
+struct audit_cap_data {
+       kernel_cap_t            permitted;
+       kernel_cap_t            inheritable;
+       union {
+               unsigned int    fE;             /* effective bit of file cap */
+               kernel_cap_t    effective;      /* effective set of process */
+       };
+};
+
+/* When fs/namei.c:getname() is called, we store the pointer in name and
+ * we don't let putname() free it (instead we free all of the saved
+ * pointers at syscall exit time).
+ *
+ * Further, in fs/namei.c:path_lookup() we store the inode and device.
+ */
+struct audit_names {
+       struct list_head        list;           /* audit_context->names_list */
+
+       struct filename         *name;
+       int                     name_len;       /* number of chars to log */
+       bool                    name_put;       /* call __putname()? */
+
+       unsigned long           ino;
+       dev_t                   dev;
+       umode_t                 mode;
+       kuid_t                  uid;
+       kgid_t                  gid;
+       dev_t                   rdev;
+       u32                     osid;
+       struct audit_cap_data   fcap;
+       unsigned int            fcap_ver;
+       unsigned char           type;           /* record type */
+       /*
+        * This was an allocated audit_names and not from the array of
+        * names allocated in the task audit context.  Thus this name
+        * should be freed on syscall exit.
+        */
+       bool                    should_free;
+};
+
+/* The per-task audit context. */
+struct audit_context {
+       int                 dummy;      /* must be the first element */
+       int                 in_syscall; /* 1 if task is in a syscall */
+       enum audit_state    state, current_state;
+       unsigned int        serial;     /* serial number for record */
+       int                 major;      /* syscall number */
+       struct timespec     ctime;      /* time of syscall entry */
+       unsigned long       argv[4];    /* syscall arguments */
+       long                return_code;/* syscall return code */
+       u64                 prio;
+       int                 return_valid; /* return code is valid */
+       /*
+        * The names_list is the list of all audit_names collected during this
+        * syscall.  The first AUDIT_NAMES entries in the names_list will
+        * actually be from the preallocated_names array for performance
+        * reasons.  Except during allocation they should never be referenced
+        * through the preallocated_names array and should only be found/used
+        * by running the names_list.
+        */
+       struct audit_names  preallocated_names[AUDIT_NAMES];
+       int                 name_count; /* total records in names_list */
+       struct list_head    names_list; /* struct audit_names->list anchor */
+       char                *filterkey; /* key for rule that triggered record */
+       struct path         pwd;
+       struct audit_aux_data *aux;
+       struct audit_aux_data *aux_pids;
+       struct sockaddr_storage *sockaddr;
+       size_t sockaddr_len;
+                               /* Save things to print about task_struct */
+       pid_t               pid, ppid;
+       kuid_t              uid, euid, suid, fsuid;
+       kgid_t              gid, egid, sgid, fsgid;
+       unsigned long       personality;
+       int                 arch;
+
+       pid_t               target_pid;
+       kuid_t              target_auid;
+       kuid_t              target_uid;
+       unsigned int        target_sessionid;
+       u32                 target_sid;
+       char                target_comm[TASK_COMM_LEN];
+
+       struct audit_tree_refs *trees, *first_trees;
+       struct list_head killed_trees;
+       int tree_count;
+
+       int type;
+       union {
+               struct {
+                       int nargs;
+                       long args[6];
+               } socketcall;
+               struct {
+                       kuid_t                  uid;
+                       kgid_t                  gid;
+                       umode_t                 mode;
+                       u32                     osid;
+                       int                     has_perm;
+                       uid_t                   perm_uid;
+                       gid_t                   perm_gid;
+                       umode_t                 perm_mode;
+                       unsigned long           qbytes;
+               } ipc;
+               struct {
+                       mqd_t                   mqdes;
+                       struct mq_attr          mqstat;
+               } mq_getsetattr;
+               struct {
+                       mqd_t                   mqdes;
+                       int                     sigev_signo;
+               } mq_notify;
+               struct {
+                       mqd_t                   mqdes;
+                       size_t                  msg_len;
+                       unsigned int            msg_prio;
+                       struct timespec         abs_timeout;
+               } mq_sendrecv;
+               struct {
+                       int                     oflag;
+                       umode_t                 mode;
+                       struct mq_attr          attr;
+               } mq_open;
+               struct {
+                       pid_t                   pid;
+                       struct audit_cap_data   cap;
+               } capset;
+               struct {
+                       int                     fd;
+                       int                     flags;
+               } mmap;
+       };
+       int fds[2];
+
+#if AUDIT_DEBUG
+       int                 put_count;
+       int                 ino_count;
+#endif
+};
+
 extern int audit_ever_enabled;
 
+extern void audit_copy_inode(struct audit_names *name,
+                            const struct dentry *dentry,
+                            const struct inode *inode);
+extern void audit_log_cap(struct audit_buffer *ab, char *prefix,
+                         kernel_cap_t *cap);
+extern void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name);
+extern void audit_log_name(struct audit_context *context,
+                          struct audit_names *n, struct path *path,
+                          int record_num, int *call_panic);
+
 extern int audit_pid;
 
 #define AUDIT_INODE_BUCKETS    32
index 267436826c3bc179678a57de72cf08220fa8faca..83a2970295d19ffdb1bd7417ed2b1b54a815cba1 100644 (file)
@@ -310,121 +310,83 @@ static u32 audit_to_op(u32 op)
        return n;
 }
 
-
-/* Translate struct audit_rule to kernel's rule respresentation.
- * Exists for backward compatibility with userspace. */
-static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
+/* check if an audit field is valid */
+static int audit_field_valid(struct audit_entry *entry, struct audit_field *f)
 {
-       struct audit_entry *entry;
-       int err = 0;
-       int i;
-
-       entry = audit_to_entry_common(rule);
-       if (IS_ERR(entry))
-               goto exit_nofree;
-
-       for (i = 0; i < rule->field_count; i++) {
-               struct audit_field *f = &entry->rule.fields[i];
-               u32 n;
-
-               n = rule->fields[i] & (AUDIT_NEGATE|AUDIT_OPERATORS);
-
-               /* Support for legacy operators where
-                * AUDIT_NEGATE bit signifies != and otherwise assumes == */
-               if (n & AUDIT_NEGATE)
-                       f->op = Audit_not_equal;
-               else if (!n)
-                       f->op = Audit_equal;
-               else
-                       f->op = audit_to_op(n);
-
-               entry->rule.vers_ops = (n & AUDIT_OPERATORS) ? 2 : 1;
-
-               f->type = rule->fields[i] & ~(AUDIT_NEGATE|AUDIT_OPERATORS);
-               f->val = rule->values[i];
-               f->uid = INVALID_UID;
-               f->gid = INVALID_GID;
-
-               err = -EINVAL;
-               if (f->op == Audit_bad)
-                       goto exit_free;
-
-               switch(f->type) {
-               default:
-                       goto exit_free;
-               case AUDIT_UID:
-               case AUDIT_EUID:
-               case AUDIT_SUID:
-               case AUDIT_FSUID:
-               case AUDIT_LOGINUID:
-                       /* bit ops not implemented for uid comparisons */
-                       if (f->op == Audit_bitmask || f->op == Audit_bittest)
-                               goto exit_free;
-
-                       f->uid = make_kuid(current_user_ns(), f->val);
-                       if (!uid_valid(f->uid))
-                               goto exit_free;
-                       break;
-               case AUDIT_GID:
-               case AUDIT_EGID:
-               case AUDIT_SGID:
-               case AUDIT_FSGID:
-                       /* bit ops not implemented for gid comparisons */
-                       if (f->op == Audit_bitmask || f->op == Audit_bittest)
-                               goto exit_free;
-
-                       f->gid = make_kgid(current_user_ns(), f->val);
-                       if (!gid_valid(f->gid))
-                               goto exit_free;
-                       break;
-               case AUDIT_PID:
-               case AUDIT_PERS:
-               case AUDIT_MSGTYPE:
-               case AUDIT_PPID:
-               case AUDIT_DEVMAJOR:
-               case AUDIT_DEVMINOR:
-               case AUDIT_EXIT:
-               case AUDIT_SUCCESS:
-                       /* bit ops are only useful on syscall args */
-                       if (f->op == Audit_bitmask || f->op == Audit_bittest)
-                               goto exit_free;
-                       break;
-               case AUDIT_ARG0:
-               case AUDIT_ARG1:
-               case AUDIT_ARG2:
-               case AUDIT_ARG3:
-                       break;
-               /* arch is only allowed to be = or != */
-               case AUDIT_ARCH:
-                       if (f->op != Audit_not_equal && f->op != Audit_equal)
-                               goto exit_free;
-                       entry->rule.arch_f = f;
-                       break;
-               case AUDIT_PERM:
-                       if (f->val & ~15)
-                               goto exit_free;
-                       break;
-               case AUDIT_FILETYPE:
-                       if (f->val & ~S_IFMT)
-                               goto exit_free;
-                       break;
-               case AUDIT_INODE:
-                       err = audit_to_inode(&entry->rule, f);
-                       if (err)
-                               goto exit_free;
-                       break;
-               }
-       }
-
-       if (entry->rule.inode_f && entry->rule.inode_f->op == Audit_not_equal)
-               entry->rule.inode_f = NULL;
-
-exit_nofree:
-       return entry;
+       switch(f->type) {
+       case AUDIT_MSGTYPE:
+               if (entry->rule.listnr != AUDIT_FILTER_TYPE &&
+                   entry->rule.listnr != AUDIT_FILTER_USER)
+                       return -EINVAL;
+               break;
+       };
 
-exit_free:
-       audit_free_rule(entry);
-       return ERR_PTR(err);
+       switch(f->type) {
+       default:
+               return -EINVAL;
+       case AUDIT_UID:
+       case AUDIT_EUID:
+       case AUDIT_SUID:
+       case AUDIT_FSUID:
+       case AUDIT_LOGINUID:
+       case AUDIT_OBJ_UID:
+       case AUDIT_GID:
+       case AUDIT_EGID:
+       case AUDIT_SGID:
+       case AUDIT_FSGID:
+       case AUDIT_OBJ_GID:
+       case AUDIT_PID:
+       case AUDIT_PERS:
+       case AUDIT_MSGTYPE:
+       case AUDIT_PPID:
+       case AUDIT_DEVMAJOR:
+       case AUDIT_DEVMINOR:
+       case AUDIT_EXIT:
+       case AUDIT_SUCCESS:
+               /* bit ops are only useful on syscall args */
+               if (f->op == Audit_bitmask || f->op == Audit_bittest)
+                       return -EINVAL;
+               break;
+       case AUDIT_ARG0:
+       case AUDIT_ARG1:
+       case AUDIT_ARG2:
+       case AUDIT_ARG3:
+       case AUDIT_SUBJ_USER:
+       case AUDIT_SUBJ_ROLE:
+       case AUDIT_SUBJ_TYPE:
+       case AUDIT_SUBJ_SEN:
+       case AUDIT_SUBJ_CLR:
+       case AUDIT_OBJ_USER:
+       case AUDIT_OBJ_ROLE:
+       case AUDIT_OBJ_TYPE:
+       case AUDIT_OBJ_LEV_LOW:
+       case AUDIT_OBJ_LEV_HIGH:
+       case AUDIT_WATCH:
+       case AUDIT_DIR:
+       case AUDIT_FILTERKEY:
+               break;
+       case AUDIT_LOGINUID_SET:
+               if ((f->val != 0) && (f->val != 1))
+                       return -EINVAL;
+       /* FALL THROUGH */
+       case AUDIT_ARCH:
+               if (f->op != Audit_not_equal && f->op != Audit_equal)
+                       return -EINVAL;
+               break;
+       case AUDIT_PERM:
+               if (f->val & ~15)
+                       return -EINVAL;
+               break;
+       case AUDIT_FILETYPE:
+               if (f->val & ~S_IFMT)
+                       return -EINVAL;
+               break;
+       case AUDIT_FIELD_COMPARE:
+               if (f->val > AUDIT_MAX_FIELD_COMPARE)
+                       return -EINVAL;
+               break;
+       };
+       return 0;
 }
 
 /* Translate struct audit_rule_data to kernel's rule respresentation. */
@@ -459,17 +421,25 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
                f->gid = INVALID_GID;
                f->lsm_str = NULL;
                f->lsm_rule = NULL;
-               switch(f->type) {
+
+               /* Support legacy tests for a valid loginuid */
+               if ((f->type == AUDIT_LOGINUID) && (f->val == 4294967295)) {
+                       f->type = AUDIT_LOGINUID_SET;
+                       f->val = 0;
+               }
+
+               err = audit_field_valid(entry, f);
+               if (err)
+                       goto exit_free;
+
+               err = -EINVAL;
+               switch (f->type) {
+               case AUDIT_LOGINUID:
                case AUDIT_UID:
                case AUDIT_EUID:
                case AUDIT_SUID:
                case AUDIT_FSUID:
-               case AUDIT_LOGINUID:
                case AUDIT_OBJ_UID:
-                       /* bit ops not implemented for uid comparisons */
-                       if (f->op == Audit_bitmask || f->op == Audit_bittest)
-                               goto exit_free;
-
                        f->uid = make_kuid(current_user_ns(), f->val);
                        if (!uid_valid(f->uid))
                                goto exit_free;
@@ -479,27 +449,10 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
                case AUDIT_SGID:
                case AUDIT_FSGID:
                case AUDIT_OBJ_GID:
-                       /* bit ops not implemented for gid comparisons */
-                       if (f->op == Audit_bitmask || f->op == Audit_bittest)
-                               goto exit_free;
-
                        f->gid = make_kgid(current_user_ns(), f->val);
                        if (!gid_valid(f->gid))
                                goto exit_free;
                        break;
-               case AUDIT_PID:
-               case AUDIT_PERS:
-               case AUDIT_MSGTYPE:
-               case AUDIT_PPID:
-               case AUDIT_DEVMAJOR:
-               case AUDIT_DEVMINOR:
-               case AUDIT_EXIT:
-               case AUDIT_SUCCESS:
-               case AUDIT_ARG0:
-               case AUDIT_ARG1:
-               case AUDIT_ARG2:
-               case AUDIT_ARG3:
-                       break;
                case AUDIT_ARCH:
                        entry->rule.arch_f = f;
                        break;
@@ -570,20 +523,6 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
                        entry->rule.buflen += f->val;
                        entry->rule.filterkey = str;
                        break;
-               case AUDIT_PERM:
-                       if (f->val & ~15)
-                               goto exit_free;
-                       break;
-               case AUDIT_FILETYPE:
-                       if (f->val & ~S_IFMT)
-                               goto exit_free;
-                       break;
-               case AUDIT_FIELD_COMPARE:
-                       if (f->val > AUDIT_MAX_FIELD_COMPARE)
-                               goto exit_free;
-                       break;
-               default:
-                       goto exit_free;
                }
        }
 
@@ -613,36 +552,6 @@ static inline size_t audit_pack_string(void **bufp, const char *str)
        return len;
 }
 
-/* Translate kernel rule respresentation to struct audit_rule.
- * Exists for backward compatibility with userspace. */
-static struct audit_rule *audit_krule_to_rule(struct audit_krule *krule)
-{
-       struct audit_rule *rule;
-       int i;
-
-       rule = kzalloc(sizeof(*rule), GFP_KERNEL);
-       if (unlikely(!rule))
-               return NULL;
-
-       rule->flags = krule->flags | krule->listnr;
-       rule->action = krule->action;
-       rule->field_count = krule->field_count;
-       for (i = 0; i < rule->field_count; i++) {
-               rule->values[i] = krule->fields[i].val;
-               rule->fields[i] = krule->fields[i].type;
-
-               if (krule->vers_ops == 1) {
-                       if (krule->fields[i].op == Audit_not_equal)
-                               rule->fields[i] |= AUDIT_NEGATE;
-               } else {
-                       rule->fields[i] |= audit_ops[krule->fields[i].op];
-               }
-       }
-       for (i = 0; i < AUDIT_BITMASK_SIZE; i++) rule->mask[i] = krule->mask[i];
-
-       return rule;
-}
-
 /* Translate kernel rule respresentation to struct audit_rule_data. */
 static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
 {
@@ -1055,35 +964,6 @@ out:
        return ret;
 }
 
-/* List rules using struct audit_rule.  Exists for backward
- * compatibility with userspace. */
-static void audit_list(int pid, int seq, struct sk_buff_head *q)
-{
-       struct sk_buff *skb;
-       struct audit_krule *r;
-       int i;
-
-       /* This is a blocking read, so use audit_filter_mutex instead of rcu
-        * iterator to sync with list writers. */
-       for (i=0; i<AUDIT_NR_FILTERS; i++) {
-               list_for_each_entry(r, &audit_rules_list[i], list) {
-                       struct audit_rule *rule;
-
-                       rule = audit_krule_to_rule(r);
-                       if (unlikely(!rule))
-                               break;
-                       skb = audit_make_reply(pid, seq, AUDIT_LIST, 0, 1,
-                                        rule, sizeof(*rule));
-                       if (skb)
-                               skb_queue_tail(q, skb);
-                       kfree(rule);
-               }
-       }
-       skb = audit_make_reply(pid, seq, AUDIT_LIST, 1, 1, NULL, 0);
-       if (skb)
-               skb_queue_tail(q, skb);
-}
-
 /* List rules using struct audit_rule_data. */
 static void audit_list_rules(int pid, int seq, struct sk_buff_head *q)
 {
@@ -1113,11 +993,11 @@ static void audit_list_rules(int pid, int seq, struct sk_buff_head *q)
 }
 
 /* Log rule additions and removals */
-static void audit_log_rule_change(kuid_t loginuid, u32 sessionid, u32 sid,
-                                 char *action, struct audit_krule *rule,
-                                 int res)
+static void audit_log_rule_change(char *action, struct audit_krule *rule, int res)
 {
        struct audit_buffer *ab;
+       uid_t loginuid = from_kuid(&init_user_ns, audit_get_loginuid(current));
+       u32 sessionid = audit_get_sessionid(current);
 
        if (!audit_enabled)
                return;
@@ -1125,18 +1005,8 @@ static void audit_log_rule_change(kuid_t loginuid, u32 sessionid, u32 sid,
        ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
        if (!ab)
                return;
-       audit_log_format(ab, "auid=%u ses=%u",
-                        from_kuid(&init_user_ns, loginuid), sessionid);
-       if (sid) {
-               char *ctx = NULL;
-               u32 len;
-               if (security_secid_to_secctx(sid, &ctx, &len))
-                       audit_log_format(ab, " ssid=%u", sid);
-               else {
-                       audit_log_format(ab, " subj=%s", ctx);
-                       security_release_secctx(ctx, len);
-               }
-       }
+       audit_log_format(ab, "auid=%u ses=%u" ,loginuid, sessionid);
+       audit_log_task_context(ab);
        audit_log_format(ab, " op=");
        audit_log_string(ab, action);
        audit_log_key(ab, rule->filterkey);
@@ -1155,8 +1025,7 @@ static void audit_log_rule_change(kuid_t loginuid, u32 sessionid, u32 sid,
  * @sessionid: sessionid for netlink audit message
  * @sid: SE Linux Security ID of sender
  */
-int audit_receive_filter(int type, int pid, int seq, void *data,
-                        size_t datasz, kuid_t loginuid, u32 sessionid, u32 sid)
+int audit_receive_filter(int type, int pid, int seq, void *data, size_t datasz)
 {
        struct task_struct *tsk;
        struct audit_netlink_list *dest;
@@ -1164,7 +1033,6 @@ int audit_receive_filter(int type, int pid, int seq, void *data,
        struct audit_entry *entry;
 
        switch (type) {
-       case AUDIT_LIST:
        case AUDIT_LIST_RULES:
                /* We can't just spew out the rules here because we might fill
                 * the available socket buffer space and deadlock waiting for
@@ -1179,10 +1047,7 @@ int audit_receive_filter(int type, int pid, int seq, void *data,
                skb_queue_head_init(&dest->q);
 
                mutex_lock(&audit_filter_mutex);
-               if (type == AUDIT_LIST)
-                       audit_list(pid, seq, &dest->q);
-               else
-                       audit_list_rules(pid, seq, &dest->q);
+               audit_list_rules(pid, seq, &dest->q);
                mutex_unlock(&audit_filter_mutex);
 
                tsk = kthread_run(audit_send_list, dest, "audit_send_list");
@@ -1192,35 +1057,23 @@ int audit_receive_filter(int type, int pid, int seq, void *data,
                        err = PTR_ERR(tsk);
                }
                break;
-       case AUDIT_ADD:
        case AUDIT_ADD_RULE:
-               if (type == AUDIT_ADD)
-                       entry = audit_rule_to_entry(data);
-               else
-                       entry = audit_data_to_entry(data, datasz);
+               entry = audit_data_to_entry(data, datasz);
                if (IS_ERR(entry))
                        return PTR_ERR(entry);
 
                err = audit_add_rule(entry);
-               audit_log_rule_change(loginuid, sessionid, sid, "add rule",
-                                     &entry->rule, !err);
-
+               audit_log_rule_change("add rule", &entry->rule, !err);
                if (err)
                        audit_free_rule(entry);
                break;
-       case AUDIT_DEL:
        case AUDIT_DEL_RULE:
-               if (type == AUDIT_DEL)
-                       entry = audit_rule_to_entry(data);
-               else
-                       entry = audit_data_to_entry(data, datasz);
+               entry = audit_data_to_entry(data, datasz);
                if (IS_ERR(entry))
                        return PTR_ERR(entry);
 
                err = audit_del_rule(entry);
-               audit_log_rule_change(loginuid, sessionid, sid, "remove rule",
-                                     &entry->rule, !err);
-
+               audit_log_rule_change("remove rule", &entry->rule, !err);
                audit_free_rule(entry);
                break;
        default:
@@ -1358,7 +1211,7 @@ int audit_compare_dname_path(const char *dname, const char *path, int parentlen)
        return strncmp(p, dname, dlen);
 }
 
-static int audit_filter_user_rules(struct audit_krule *rule,
+static int audit_filter_user_rules(struct audit_krule *rule, int type,
                                   enum audit_state *state)
 {
        int i;
@@ -1382,6 +1235,13 @@ static int audit_filter_user_rules(struct audit_krule *rule,
                        result = audit_uid_comparator(audit_get_loginuid(current),
                                                  f->op, f->uid);
                        break;
+               case AUDIT_LOGINUID_SET:
+                       result = audit_comparator(audit_loginuid_set(current),
+                                                 f->op, f->val);
+                       break;
+               case AUDIT_MSGTYPE:
+                       result = audit_comparator(type, f->op, f->val);
+                       break;
                case AUDIT_SUBJ_USER:
                case AUDIT_SUBJ_ROLE:
                case AUDIT_SUBJ_TYPE:
@@ -1408,7 +1268,7 @@ static int audit_filter_user_rules(struct audit_krule *rule,
        return 1;
 }
 
-int audit_filter_user(void)
+int audit_filter_user(int type)
 {
        enum audit_state state = AUDIT_DISABLED;
        struct audit_entry *e;
@@ -1416,7 +1276,7 @@ int audit_filter_user(void)
 
        rcu_read_lock();
        list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_USER], list) {
-               if (audit_filter_user_rules(&e->rule, &state)) {
+               if (audit_filter_user_rules(&e->rule, type, &state)) {
                        if (state == AUDIT_DISABLED)
                                ret = 0;
                        break;
index c68229411a7c20afbd6903f7272d23afbc0e9ac0..3c8a601324a280fe9224c872f24e2995243da830 100644 (file)
 #define AUDITSC_SUCCESS 1
 #define AUDITSC_FAILURE 2
 
-/* AUDIT_NAMES is the number of slots we reserve in the audit_context
- * for saving names from getname().  If we get more names we will allocate
- * a name dynamically and also add those to the list anchored by names_list. */
-#define AUDIT_NAMES    5
-
 /* no execve audit message should be longer than this (userspace limits) */
 #define MAX_EXECVE_AUDIT_LEN 7500
 
@@ -90,44 +85,6 @@ int audit_n_rules;
 /* determines whether we collect data for signals sent */
 int audit_signals;
 
-struct audit_cap_data {
-       kernel_cap_t            permitted;
-       kernel_cap_t            inheritable;
-       union {
-               unsigned int    fE;             /* effective bit of a file capability */
-               kernel_cap_t    effective;      /* effective set of a process */
-       };
-};
-
-/* When fs/namei.c:getname() is called, we store the pointer in name and
- * we don't let putname() free it (instead we free all of the saved
- * pointers at syscall exit time).
- *
- * Further, in fs/namei.c:path_lookup() we store the inode and device.
- */
-struct audit_names {
-       struct list_head        list;           /* audit_context->names_list */
-       struct filename *name;
-       unsigned long           ino;
-       dev_t                   dev;
-       umode_t                 mode;
-       kuid_t                  uid;
-       kgid_t                  gid;
-       dev_t                   rdev;
-       u32                     osid;
-       struct audit_cap_data    fcap;
-       unsigned int            fcap_ver;
-       int                     name_len;       /* number of name's characters to log */
-       unsigned char           type;           /* record type */
-       bool                    name_put;       /* call __putname() for this name */
-       /*
-        * This was an allocated audit_names and not from the array of
-        * names allocated in the task audit context.  Thus this name
-        * should be freed on syscall exit
-        */
-       bool                    should_free;
-};
-
 struct audit_aux_data {
        struct audit_aux_data   *next;
        int                     type;
@@ -175,106 +132,6 @@ struct audit_tree_refs {
        struct audit_chunk *c[31];
 };
 
-/* The per-task audit context. */
-struct audit_context {
-       int                 dummy;      /* must be the first element */
-       int                 in_syscall; /* 1 if task is in a syscall */
-       enum audit_state    state, current_state;
-       unsigned int        serial;     /* serial number for record */
-       int                 major;      /* syscall number */
-       struct timespec     ctime;      /* time of syscall entry */
-       unsigned long       argv[4];    /* syscall arguments */
-       long                return_code;/* syscall return code */
-       u64                 prio;
-       int                 return_valid; /* return code is valid */
-       /*
-        * The names_list is the list of all audit_names collected during this
-        * syscall.  The first AUDIT_NAMES entries in the names_list will
-        * actually be from the preallocated_names array for performance
-        * reasons.  Except during allocation they should never be referenced
-        * through the preallocated_names array and should only be found/used
-        * by running the names_list.
-        */
-       struct audit_names  preallocated_names[AUDIT_NAMES];
-       int                 name_count; /* total records in names_list */
-       struct list_head    names_list; /* anchor for struct audit_names->list */
-       char *              filterkey;  /* key for rule that triggered record */
-       struct path         pwd;
-       struct audit_aux_data *aux;
-       struct audit_aux_data *aux_pids;
-       struct sockaddr_storage *sockaddr;
-       size_t sockaddr_len;
-                               /* Save things to print about task_struct */
-       pid_t               pid, ppid;
-       kuid_t              uid, euid, suid, fsuid;
-       kgid_t              gid, egid, sgid, fsgid;
-       unsigned long       personality;
-       int                 arch;
-
-       pid_t               target_pid;
-       kuid_t              target_auid;
-       kuid_t              target_uid;
-       unsigned int        target_sessionid;
-       u32                 target_sid;
-       char                target_comm[TASK_COMM_LEN];
-
-       struct audit_tree_refs *trees, *first_trees;
-       struct list_head killed_trees;
-       int tree_count;
-
-       int type;
-       union {
-               struct {
-                       int nargs;
-                       long args[6];
-               } socketcall;
-               struct {
-                       kuid_t                  uid;
-                       kgid_t                  gid;
-                       umode_t                 mode;
-                       u32                     osid;
-                       int                     has_perm;
-                       uid_t                   perm_uid;
-                       gid_t                   perm_gid;
-                       umode_t                 perm_mode;
-                       unsigned long           qbytes;
-               } ipc;
-               struct {
-                       mqd_t                   mqdes;
-                       struct mq_attr          mqstat;
-               } mq_getsetattr;
-               struct {
-                       mqd_t                   mqdes;
-                       int                     sigev_signo;
-               } mq_notify;
-               struct {
-                       mqd_t                   mqdes;
-                       size_t                  msg_len;
-                       unsigned int            msg_prio;
-                       struct timespec         abs_timeout;
-               } mq_sendrecv;
-               struct {
-                       int                     oflag;
-                       umode_t                 mode;
-                       struct mq_attr          attr;
-               } mq_open;
-               struct {
-                       pid_t                   pid;
-                       struct audit_cap_data   cap;
-               } capset;
-               struct {
-                       int                     fd;
-                       int                     flags;
-               } mmap;
-       };
-       int fds[2];
-
-#if AUDIT_DEBUG
-       int                 put_count;
-       int                 ino_count;
-#endif
-};
-
 static inline int open_arg(int flags, int mask)
 {
        int n = ACC_MODE(flags);
@@ -633,9 +490,23 @@ static int audit_filter_rules(struct task_struct *tsk,
                        break;
                case AUDIT_GID:
                        result = audit_gid_comparator(cred->gid, f->op, f->gid);
+                       if (f->op == Audit_equal) {
+                               if (!result)
+                                       result = in_group_p(f->gid);
+                       } else if (f->op == Audit_not_equal) {
+                               if (result)
+                                       result = !in_group_p(f->gid);
+                       }
                        break;
                case AUDIT_EGID:
                        result = audit_gid_comparator(cred->egid, f->op, f->gid);
+                       if (f->op == Audit_equal) {
+                               if (!result)
+                                       result = in_egroup_p(f->gid);
+                       } else if (f->op == Audit_not_equal) {
+                               if (result)
+                                       result = !in_egroup_p(f->gid);
+                       }
                        break;
                case AUDIT_SGID:
                        result = audit_gid_comparator(cred->sgid, f->op, f->gid);
@@ -742,6 +613,9 @@ static int audit_filter_rules(struct task_struct *tsk,
                        if (ctx)
                                result = audit_uid_comparator(tsk->loginuid, f->op, f->uid);
                        break;
+               case AUDIT_LOGINUID_SET:
+                       result = audit_comparator(audit_loginuid_set(tsk), f->op, f->val);
+                       break;
                case AUDIT_SUBJ_USER:
                case AUDIT_SUBJ_ROLE:
                case AUDIT_SUBJ_TYPE:
@@ -987,6 +861,8 @@ static inline void audit_free_names(struct audit_context *context)
 
 #if AUDIT_DEBUG == 2
        if (context->put_count + context->ino_count != context->name_count) {
+               int i = 0;
+
                printk(KERN_ERR "%s:%d(:%d): major=%d in_syscall=%d"
                       " name_count=%d put_count=%d"
                       " ino_count=%d [NOT freeing]\n",
@@ -995,7 +871,7 @@ static inline void audit_free_names(struct audit_context *context)
                       context->name_count, context->put_count,
                       context->ino_count);
                list_for_each_entry(n, &context->names_list, list) {
-                       printk(KERN_ERR "names[%d] = %p = %s\n", i,
+                       printk(KERN_ERR "names[%d] = %p = %s\n", i++,
                               n->name, n->name->name ?: "(null)");
                }
                dump_stack();
@@ -1010,7 +886,7 @@ static inline void audit_free_names(struct audit_context *context)
        list_for_each_entry_safe(n, next, &context->names_list, list) {
                list_del(&n->list);
                if (n->name && n->name_put)
-                       __putname(n->name);
+                       final_putname(n->name);
                if (n->should_free)
                        kfree(n);
        }
@@ -1093,88 +969,6 @@ static inline void audit_free_context(struct audit_context *context)
        kfree(context);
 }
 
-void audit_log_task_context(struct audit_buffer *ab)
-{
-       char *ctx = NULL;
-       unsigned len;
-       int error;
-       u32 sid;
-
-       security_task_getsecid(current, &sid);
-       if (!sid)
-               return;
-
-       error = security_secid_to_secctx(sid, &ctx, &len);
-       if (error) {
-               if (error != -EINVAL)
-                       goto error_path;
-               return;
-       }
-
-       audit_log_format(ab, " subj=%s", ctx);
-       security_release_secctx(ctx, len);
-       return;
-
-error_path:
-       audit_panic("error in audit_log_task_context");
-       return;
-}
-
-EXPORT_SYMBOL(audit_log_task_context);
-
-void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk)
-{
-       const struct cred *cred;
-       char name[sizeof(tsk->comm)];
-       struct mm_struct *mm = tsk->mm;
-       char *tty;
-
-       if (!ab)
-               return;
-
-       /* tsk == current */
-       cred = current_cred();
-
-       spin_lock_irq(&tsk->sighand->siglock);
-       if (tsk->signal && tsk->signal->tty)
-               tty = tsk->signal->tty->name;
-       else
-               tty = "(none)";
-       spin_unlock_irq(&tsk->sighand->siglock);
-
-
-       audit_log_format(ab,
-                        " ppid=%ld pid=%d auid=%u uid=%u gid=%u"
-                        " euid=%u suid=%u fsuid=%u"
-                        " egid=%u sgid=%u fsgid=%u ses=%u tty=%s",
-                        sys_getppid(),
-                        tsk->pid,
-                        from_kuid(&init_user_ns, tsk->loginuid),
-                        from_kuid(&init_user_ns, cred->uid),
-                        from_kgid(&init_user_ns, cred->gid),
-                        from_kuid(&init_user_ns, cred->euid),
-                        from_kuid(&init_user_ns, cred->suid),
-                        from_kuid(&init_user_ns, cred->fsuid),
-                        from_kgid(&init_user_ns, cred->egid),
-                        from_kgid(&init_user_ns, cred->sgid),
-                        from_kgid(&init_user_ns, cred->fsgid),
-                        tsk->sessionid, tty);
-
-       get_task_comm(name, tsk);
-       audit_log_format(ab, " comm=");
-       audit_log_untrustedstring(ab, name);
-
-       if (mm) {
-               down_read(&mm->mmap_sem);
-               if (mm->exe_file)
-                       audit_log_d_path(ab, " exe=", &mm->exe_file->f_path);
-               up_read(&mm->mmap_sem);
-       }
-       audit_log_task_context(ab);
-}
-
-EXPORT_SYMBOL(audit_log_task_info);
-
 static int audit_log_pid_context(struct audit_context *context, pid_t pid,
                                 kuid_t auid, kuid_t uid, unsigned int sessionid,
                                 u32 sid, char *comm)
@@ -1191,12 +985,14 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
        audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid,
                         from_kuid(&init_user_ns, auid),
                         from_kuid(&init_user_ns, uid), sessionid);
-       if (security_secid_to_secctx(sid, &ctx, &len)) {
-               audit_log_format(ab, " obj=(none)");
-               rc = 1;
-       } else {
-               audit_log_format(ab, " obj=%s", ctx);
-               security_release_secctx(ctx, len);
+       if (sid) {
+               if (security_secid_to_secctx(sid, &ctx, &len)) {
+                       audit_log_format(ab, " obj=(none)");
+                       rc = 1;
+               } else {
+                       audit_log_format(ab, " obj=%s", ctx);
+                       security_release_secctx(ctx, len);
+               }
        }
        audit_log_format(ab, " ocomm=");
        audit_log_untrustedstring(ab, comm);
@@ -1390,35 +1186,6 @@ static void audit_log_execve_info(struct audit_context *context,
        kfree(buf);
 }
 
-static void audit_log_cap(struct audit_buffer *ab, char *prefix, kernel_cap_t *cap)
-{
-       int i;
-
-       audit_log_format(ab, " %s=", prefix);
-       CAP_FOR_EACH_U32(i) {
-               audit_log_format(ab, "%08x", cap->cap[(_KERNEL_CAPABILITY_U32S-1) - i]);
-       }
-}
-
-static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name)
-{
-       kernel_cap_t *perm = &name->fcap.permitted;
-       kernel_cap_t *inh = &name->fcap.inheritable;
-       int log = 0;
-
-       if (!cap_isclear(*perm)) {
-               audit_log_cap(ab, "cap_fp", perm);
-               log = 1;
-       }
-       if (!cap_isclear(*inh)) {
-               audit_log_cap(ab, "cap_fi", inh);
-               log = 1;
-       }
-
-       if (log)
-               audit_log_format(ab, " cap_fe=%d cap_fver=%x", name->fcap.fE, name->fcap_ver);
-}
-
 static void show_special(struct audit_context *context, int *call_panic)
 {
        struct audit_buffer *ab;
@@ -1516,68 +1283,6 @@ static void show_special(struct audit_context *context, int *call_panic)
        audit_log_end(ab);
 }
 
-static void audit_log_name(struct audit_context *context, struct audit_names *n,
-                          int record_num, int *call_panic)
-{
-       struct audit_buffer *ab;
-       ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH);
-       if (!ab)
-               return; /* audit_panic has been called */
-
-       audit_log_format(ab, "item=%d", record_num);
-
-       if (n->name) {
-               switch (n->name_len) {
-               case AUDIT_NAME_FULL:
-                       /* log the full path */
-                       audit_log_format(ab, " name=");
-                       audit_log_untrustedstring(ab, n->name->name);
-                       break;
-               case 0:
-                       /* name was specified as a relative path and the
-                        * directory component is the cwd */
-                       audit_log_d_path(ab, " name=", &context->pwd);
-                       break;
-               default:
-                       /* log the name's directory component */
-                       audit_log_format(ab, " name=");
-                       audit_log_n_untrustedstring(ab, n->name->name,
-                                                   n->name_len);
-               }
-       } else
-               audit_log_format(ab, " name=(null)");
-
-       if (n->ino != (unsigned long)-1) {
-               audit_log_format(ab, " inode=%lu"
-                                " dev=%02x:%02x mode=%#ho"
-                                " ouid=%u ogid=%u rdev=%02x:%02x",
-                                n->ino,
-                                MAJOR(n->dev),
-                                MINOR(n->dev),
-                                n->mode,
-                                from_kuid(&init_user_ns, n->uid),
-                                from_kgid(&init_user_ns, n->gid),
-                                MAJOR(n->rdev),
-                                MINOR(n->rdev));
-       }
-       if (n->osid != 0) {
-               char *ctx = NULL;
-               u32 len;
-               if (security_secid_to_secctx(
-                       n->osid, &ctx, &len)) {
-                       audit_log_format(ab, " osid=%u", n->osid);
-                       *call_panic = 2;
-               } else {
-                       audit_log_format(ab, " obj=%s", ctx);
-                       security_release_secctx(ctx, len);
-               }
-       }
-
-       audit_log_fcaps(ab, n);
-
-       audit_log_end(ab);
-}
-
 static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
 {
        int i, call_panic = 0;
@@ -1695,7 +1400,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
 
        i = 0;
        list_for_each_entry(n, &context->names_list, list)
-               audit_log_name(context, n, i++, &call_panic);
+               audit_log_name(context, n, NULL, i++, &call_panic);
 
        /* Send end of event record to help user space know we are finished */
        ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE);
@@ -2030,18 +1735,18 @@ void audit_putname(struct filename *name)
        BUG_ON(!context);
        if (!context->in_syscall) {
 #if AUDIT_DEBUG == 2
-               printk(KERN_ERR "%s:%d(:%d): __putname(%p)\n",
+               printk(KERN_ERR "%s:%d(:%d): final_putname(%p)\n",
                       __FILE__, __LINE__, context->serial, name);
                if (context->name_count) {
                        struct audit_names *n;
-                       int i;
+                       int i = 0;
 
                        list_for_each_entry(n, &context->names_list, list)
-                               printk(KERN_ERR "name[%d] = %p = %s\n", i,
+                               printk(KERN_ERR "name[%d] = %p = %s\n", i++,
                                       n->name, n->name->name ?: "(null)");
                        }
 #endif
-               __putname(name);
+               final_putname(name);
        }
 #if AUDIT_DEBUG
        else {
@@ -2060,41 +1765,6 @@ void audit_putname(struct filename *name)
 #endif
 }
 
-static inline int audit_copy_fcaps(struct audit_names *name, const struct dentry *dentry)
-{
-       struct cpu_vfs_cap_data caps;
-       int rc;
-
-       if (!dentry)
-               return 0;
-
-       rc = get_vfs_caps_from_disk(dentry, &caps);
-       if (rc)
-               return rc;
-
-       name->fcap.permitted = caps.permitted;
-       name->fcap.inheritable = caps.inheritable;
-       name->fcap.fE = !!(caps.magic_etc & VFS_CAP_FLAGS_EFFECTIVE);
-       name->fcap_ver = (caps.magic_etc & VFS_CAP_REVISION_MASK) >> VFS_CAP_REVISION_SHIFT;
-
-       return 0;
-}
-
-
-/* Copy inode data into an audit_names. */
-static void audit_copy_inode(struct audit_names *name, const struct dentry *dentry,
-                            const struct inode *inode)
-{
-       name->ino   = inode->i_ino;
-       name->dev   = inode->i_sb->s_dev;
-       name->mode  = inode->i_mode;
-       name->uid   = inode->i_uid;
-       name->gid   = inode->i_gid;
-       name->rdev  = inode->i_rdev;
-       security_inode_getsecid(inode, &name->osid);
-       audit_copy_fcaps(name, dentry);
-}
-
 /**
  * __audit_inode - store the inode and device from a lookup
  * @name: name being audited
@@ -2303,7 +1973,7 @@ int audit_set_loginuid(kuid_t loginuid)
        unsigned int sessionid;
 
 #ifdef CONFIG_AUDIT_LOGINUID_IMMUTABLE
-       if (uid_valid(task->loginuid))
+       if (audit_loginuid_set(task))
                return -EPERM;
 #else /* CONFIG_AUDIT_LOGINUID_IMMUTABLE */
        if (!capable(CAP_AUDIT_CONTROL))
@@ -2471,17 +2141,20 @@ int __audit_bprm(struct linux_binprm *bprm)
 
 /**
  * audit_socketcall - record audit data for sys_socketcall
- * @nargs: number of args
+ * @nargs: number of args, which should not be more than AUDITSC_ARGS.
  * @args: args array
  *
  */
-void __audit_socketcall(int nargs, unsigned long *args)
+int __audit_socketcall(int nargs, unsigned long *args)
 {
        struct audit_context *context = current->audit_context;
 
+       if (nargs <= 0 || nargs > AUDITSC_ARGS || !args)
+               return -EINVAL;
        context->type = AUDIT_SOCKETCALL;
        context->socketcall.nargs = nargs;
        memcpy(context->socketcall.args, args, nargs * sizeof(unsigned long));
+       return 0;
 }
 
 /**
index b416093997dafcf528204be9c99a9986dfe7965d..6b94633ca61d67e29faa58a7d42410e1ef678193 100644 (file)
@@ -2412,7 +2412,7 @@ static const unsigned char nargs[21] = {
 
 SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
 {
-       unsigned long a[6];
+       unsigned long a[AUDITSC_ARGS];
        unsigned long a0, a1;
        int err;
        unsigned int len;
@@ -2428,7 +2428,9 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
        if (copy_from_user(a, args, len))
                return -EFAULT;
 
-       audit_socketcall(nargs[call] / sizeof(unsigned long), a);
+       err = audit_socketcall(nargs[call] / sizeof(unsigned long), a);
+       if (err)
+               return err;
 
        a0 = a[0];
        a1 = a[1];