]> nv-tegra.nvidia Code Review - linux-3.10.git/blobdiff - kernel/auditsc.c
ARM: tegra: Check regulator_enable return values
[linux-3.10.git] / kernel / auditsc.c
index 0160a68b4d7f0678de1b31b9180238fc93fdb334..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,43 +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 */
-       const char      *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;
@@ -174,107 +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_context *previous; /* For nested syscalls */
-       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,8 +871,8 @@ 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,
-                              n->name, n->name ?: "(null)");
+                       printk(KERN_ERR "names[%d] = %p = %s\n", i++,
+                              n->name, n->name->name ?: "(null)");
                }
                dump_stack();
                return;
@@ -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);
        }
@@ -1034,21 +910,15 @@ static inline void audit_free_aux(struct audit_context *context)
        }
 }
 
-static inline void audit_zero_context(struct audit_context *context,
-                                     enum audit_state state)
-{
-       memset(context, 0, sizeof(*context));
-       context->state      = state;
-       context->prio = state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0;
-}
-
 static inline struct audit_context *audit_alloc_context(enum audit_state state)
 {
        struct audit_context *context;
 
-       if (!(context = kmalloc(sizeof(*context), GFP_KERNEL)))
+       context = kzalloc(sizeof(*context), GFP_KERNEL);
+       if (!context)
                return NULL;
-       audit_zero_context(context, state);
+       context->state = state;
+       context->prio = state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0;
        INIT_LIST_HEAD(&context->killed_trees);
        INIT_LIST_HEAD(&context->names_list);
        return context;
@@ -1090,113 +960,15 @@ int audit_alloc(struct task_struct *tsk)
 
 static inline void audit_free_context(struct audit_context *context)
 {
-       struct audit_context *previous;
-       int                  count = 0;
-
-       do {
-               previous = context->previous;
-               if (previous || (count &&  count < 10)) {
-                       ++count;
-                       printk(KERN_ERR "audit(:%d): major=%d name_count=%d:"
-                              " freeing multiple contexts (%d)\n",
-                              context->serial, context->major,
-                              context->name_count, count);
-               }
-               audit_free_names(context);
-               unroll_tree_refs(context, NULL, 0);
-               free_tree_refs(context);
-               audit_free_aux(context);
-               kfree(context->filterkey);
-               kfree(context->sockaddr);
-               kfree(context);
-               context  = previous;
-       } while (context);
-       if (count >= 10)
-               printk(KERN_ERR "audit: freed %d contexts\n", count);
-}
-
-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;
+       audit_free_names(context);
+       unroll_tree_refs(context, NULL, 0);
+       free_tree_refs(context);
+       audit_free_aux(context);
+       kfree(context->filterkey);
+       kfree(context->sockaddr);
+       kfree(context);
 }
 
-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, 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)
@@ -1213,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);
@@ -1412,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;
@@ -1480,14 +1225,14 @@ static void show_special(struct audit_context *context, int *call_panic)
                        audit_log_end(ab);
                        ab = audit_log_start(context, GFP_KERNEL,
                                             AUDIT_IPC_SET_PERM);
+                       if (unlikely(!ab))
+                               return;
                        audit_log_format(ab,
                                "qbytes=%lx ouid=%u ogid=%u mode=%#ho",
                                context->ipc.qbytes,
                                context->ipc.perm_uid,
                                context->ipc.perm_gid,
                                context->ipc.perm_mode);
-                       if (!ab)
-                               return;
                }
                break; }
        case AUDIT_MQ_OPEN: {
@@ -1538,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);
-                       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,
-                                                   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;
@@ -1717,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);
@@ -1782,42 +1465,6 @@ void __audit_syscall_entry(int arch, int major,
        if (!context)
                return;
 
-       /*
-        * This happens only on certain architectures that make system
-        * calls in kernel_thread via the entry.S interface, instead of
-        * with direct calls.  (If you are porting to a new
-        * architecture, hitting this condition can indicate that you
-        * got the _exit/_leave calls backward in entry.S.)
-        *
-        * i386     no
-        * x86_64   no
-        * ppc64    yes (see arch/powerpc/platforms/iseries/misc.S)
-        *
-        * This also happens with vm86 emulation in a non-nested manner
-        * (entries without exits), so this case must be caught.
-        */
-       if (context->in_syscall) {
-               struct audit_context *newctx;
-
-#if AUDIT_DEBUG
-               printk(KERN_ERR
-                      "audit(:%d) pid=%d in syscall=%d;"
-                      " entering syscall=%d\n",
-                      context->serial, tsk->pid, context->major, major);
-#endif
-               newctx = audit_alloc_context(context->state);
-               if (newctx) {
-                       newctx->previous   = context;
-                       context            = newctx;
-                       tsk->audit_context = newctx;
-               } else  {
-                       /* If we can't alloc a new context, the best we
-                        * can do is to leak memory (any pending putname
-                        * will be lost).  The only other alternative is
-                        * to abandon auditing. */
-                       audit_zero_context(context, context->state);
-               }
-       }
        BUG_ON(context->in_syscall || context->name_count);
 
        if (!audit_enabled)
@@ -1880,28 +1527,21 @@ void __audit_syscall_exit(int success, long return_code)
        if (!list_empty(&context->killed_trees))
                audit_kill_trees(&context->killed_trees);
 
-       if (context->previous) {
-               struct audit_context *new_context = context->previous;
-               context->previous  = NULL;
-               audit_free_context(context);
-               tsk->audit_context = new_context;
-       } else {
-               audit_free_names(context);
-               unroll_tree_refs(context, NULL, 0);
-               audit_free_aux(context);
-               context->aux = NULL;
-               context->aux_pids = NULL;
-               context->target_pid = 0;
-               context->target_sid = 0;
-               context->sockaddr_len = 0;
-               context->type = 0;
-               context->fds[0] = -1;
-               if (context->state != AUDIT_RECORD_CONTEXT) {
-                       kfree(context->filterkey);
-                       context->filterkey = NULL;
-               }
-               tsk->audit_context = context;
+       audit_free_names(context);
+       unroll_tree_refs(context, NULL, 0);
+       audit_free_aux(context);
+       context->aux = NULL;
+       context->aux_pids = NULL;
+       context->target_pid = 0;
+       context->target_sid = 0;
+       context->sockaddr_len = 0;
+       context->type = 0;
+       context->fds[0] = -1;
+       if (context->state != AUDIT_RECORD_CONTEXT) {
+               kfree(context->filterkey);
+               context->filterkey = NULL;
        }
+       tsk->audit_context = context;
 }
 
 static inline void handle_one(const struct inode *inode)
@@ -2019,6 +1659,29 @@ static struct audit_names *audit_alloc_name(struct audit_context *context,
        return aname;
 }
 
+/**
+ * audit_reusename - fill out filename with info from existing entry
+ * @uptr: userland ptr to pathname
+ *
+ * Search the audit_names list for the current audit context. If there is an
+ * existing entry with a matching "uptr" then return the filename
+ * associated with that audit_name. If not, return NULL.
+ */
+struct filename *
+__audit_reusename(const __user char *uptr)
+{
+       struct audit_context *context = current->audit_context;
+       struct audit_names *n;
+
+       list_for_each_entry(n, &context->names_list, list) {
+               if (!n->name)
+                       continue;
+               if (n->name->uptr == uptr)
+                       return n->name;
+       }
+       return NULL;
+}
+
 /**
  * audit_getname - add a name to the list
  * @name: name to add
@@ -2026,7 +1689,7 @@ static struct audit_names *audit_alloc_name(struct audit_context *context,
  * Add a name to the list of audit names for this context.
  * Called from fs/namei.c:getname().
  */
-void __audit_getname(const char *name)
+void __audit_getname(struct filename *name)
 {
        struct audit_context *context = current->audit_context;
        struct audit_names *n;
@@ -2040,6 +1703,11 @@ void __audit_getname(const char *name)
                return;
        }
 
+#if AUDIT_DEBUG
+       /* The filename _must_ have a populated ->name */
+       BUG_ON(!name->name);
+#endif
+
        n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN);
        if (!n)
                return;
@@ -2047,6 +1715,7 @@ void __audit_getname(const char *name)
        n->name = name;
        n->name_len = AUDIT_NAME_FULL;
        n->name_put = true;
+       name->aname = n;
 
        if (!context->pwd.dentry)
                get_fs_pwd(current->fs, &context->pwd);
@@ -2059,25 +1728,25 @@ void __audit_getname(const char *name)
  * then we delay the putname until syscall exit.
  * Called from include/linux/fs.h:putname().
  */
-void audit_putname(const char *name)
+void audit_putname(struct filename *name)
 {
        struct audit_context *context = current->audit_context;
 
        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,
-                                      n->name, n->name ?: "(null)");
+                               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 {
@@ -2088,56 +1757,21 @@ void audit_putname(const char *name)
                               " put_count=%d\n",
                               __FILE__, __LINE__,
                               context->serial, context->major,
-                              context->in_syscall, name, context->name_count,
-                              context->put_count);
+                              context->in_syscall, name->name,
+                              context->name_count, context->put_count);
                        dump_stack();
                }
        }
 #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
  * @dentry: dentry being audited
  * @parent: does this dentry represent the parent?
  */
-void __audit_inode(const char *name, const struct dentry *dentry,
+void __audit_inode(struct filename *name, const struct dentry *dentry,
                   unsigned int parent)
 {
        struct audit_context *context = current->audit_context;
@@ -2150,9 +1784,29 @@ void __audit_inode(const char *name, const struct dentry *dentry,
        if (!name)
                goto out_alloc;
 
+#if AUDIT_DEBUG
+       /* The struct filename _must_ have a populated ->name */
+       BUG_ON(!name->name);
+#endif
+       /*
+        * If we have a pointer to an audit_names entry already, then we can
+        * just use it directly if the type is correct.
+        */
+       n = name->aname;
+       if (n) {
+               if (parent) {
+                       if (n->type == AUDIT_TYPE_PARENT ||
+                           n->type == AUDIT_TYPE_UNKNOWN)
+                               goto out;
+               } else {
+                       if (n->type != AUDIT_TYPE_PARENT)
+                               goto out;
+               }
+       }
+
        list_for_each_entry_reverse(n, &context->names_list, list) {
                /* does the name pointer match? */
-               if (n->name != name)
+               if (!n->name || n->name->name != name->name)
                        continue;
 
                /* match the correct record type */
@@ -2175,7 +1829,7 @@ out_alloc:
                return;
 out:
        if (parent) {
-               n->name_len = n->name ? parent_len(n->name) : AUDIT_NAME_FULL;
+               n->name_len = n->name ? parent_len(n->name->name) : AUDIT_NAME_FULL;
                n->type = AUDIT_TYPE_PARENT;
        } else {
                n->name_len = AUDIT_NAME_FULL;
@@ -2189,6 +1843,7 @@ out:
  * __audit_inode_child - collect inode info for created/removed objects
  * @parent: inode of dentry parent
  * @dentry: dentry being audited
+ * @type:   AUDIT_TYPE_* value that we're looking for
  *
  * For syscalls that create or remove filesystem objects, audit_inode
  * can only collect information for the filesystem object's parent.
@@ -2199,13 +1854,13 @@ out:
  * unsuccessful attempts.
  */
 void __audit_inode_child(const struct inode *parent,
-                        const struct dentry *dentry)
+                        const struct dentry *dentry,
+                        const unsigned char type)
 {
        struct audit_context *context = current->audit_context;
-       const char *found_parent = NULL, *found_child = NULL;
        const struct inode *inode = dentry->d_inode;
        const char *dname = dentry->d_name.name;
-       struct audit_names *n;
+       struct audit_names *n, *found_parent = NULL, *found_child = NULL;
 
        if (!context->in_syscall)
                return;
@@ -2213,63 +1868,65 @@ void __audit_inode_child(const struct inode *parent,
        if (inode)
                handle_one(inode);
 
-       /* parent is more likely, look for it first */
+       /* look for a parent entry first */
        list_for_each_entry(n, &context->names_list, list) {
-               if (!n->name)
+               if (!n->name || n->type != AUDIT_TYPE_PARENT)
                        continue;
 
                if (n->ino == parent->i_ino &&
-                   !audit_compare_dname_path(dname, n->name, n->name_len)) {
-                       found_parent = n->name;
-                       goto add_names;
+                   !audit_compare_dname_path(dname, n->name->name, n->name_len)) {
+                       found_parent = n;
+                       break;
                }
        }
 
-       /* no matching parent, look for matching child */
+       /* is there a matching child entry? */
        list_for_each_entry(n, &context->names_list, list) {
-               if (!n->name)
+               /* can only match entries that have a name */
+               if (!n->name || n->type != type)
+                       continue;
+
+               /* if we found a parent, make sure this one is a child of it */
+               if (found_parent && (n->name != found_parent->name))
                        continue;
 
-               /* strcmp() is the more likely scenario */
-               if (!strcmp(dname, n->name) ||
-                   !audit_compare_dname_path(dname, n->name,
+               if (!strcmp(dname, n->name->name) ||
+                   !audit_compare_dname_path(dname, n->name->name,
+                                               found_parent ?
+                                               found_parent->name_len :
                                                AUDIT_NAME_FULL)) {
-                       if (inode)
-                               audit_copy_inode(n, dentry, inode);
-                       else
-                               n->ino = (unsigned long)-1;
-                       n->type = AUDIT_TYPE_NORMAL;
-                       found_child = n->name;
-                       goto add_names;
+                       found_child = n;
+                       break;
                }
        }
 
-add_names:
        if (!found_parent) {
-               n = audit_alloc_name(context, AUDIT_TYPE_NORMAL);
+               /* create a new, "anonymous" parent record */
+               n = audit_alloc_name(context, AUDIT_TYPE_PARENT);
                if (!n)
                        return;
                audit_copy_inode(n, NULL, parent);
        }
 
        if (!found_child) {
-               n = audit_alloc_name(context, AUDIT_TYPE_NORMAL);
-               if (!n)
+               found_child = audit_alloc_name(context, type);
+               if (!found_child)
                        return;
 
                /* Re-use the name belonging to the slot for a matching parent
                 * directory. All names for this context are relinquished in
                 * audit_free_names() */
                if (found_parent) {
-                       n->name = found_parent;
-                       n->name_len = AUDIT_NAME_FULL;
+                       found_child->name = found_parent->name;
+                       found_child->name_len = AUDIT_NAME_FULL;
                        /* don't call __putname() */
-                       n->name_put = false;
+                       found_child->name_put = false;
                }
-
-               if (inode)
-                       audit_copy_inode(n, dentry, inode);
        }
+       if (inode)
+               audit_copy_inode(found_child, dentry, inode);
+       else
+               found_child->ino = (unsigned long)-1;
 }
 EXPORT_SYMBOL_GPL(__audit_inode_child);
 
@@ -2316,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))
@@ -2484,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;
 }
 
 /**
@@ -2682,7 +2342,7 @@ void __audit_mmap_fd(int fd, int flags)
        context->type = AUDIT_MMAP;
 }
 
-static void audit_log_abend(struct audit_buffer *ab, char *reason, long signr)
+static void audit_log_task(struct audit_buffer *ab)
 {
        kuid_t auid, uid;
        kgid_t gid;
@@ -2700,6 +2360,11 @@ static void audit_log_abend(struct audit_buffer *ab, char *reason, long signr)
        audit_log_task_context(ab);
        audit_log_format(ab, " pid=%d comm=", current->pid);
        audit_log_untrustedstring(ab, current->comm);
+}
+
+static void audit_log_abend(struct audit_buffer *ab, char *reason, long signr)
+{
+       audit_log_task(ab);
        audit_log_format(ab, " reason=");
        audit_log_string(ab, reason);
        audit_log_format(ab, " sig=%ld", signr);
@@ -2722,6 +2387,8 @@ void audit_core_dumps(long signr)
                return;
 
        ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND);
+       if (unlikely(!ab))
+               return;
        audit_log_abend(ab, "memory violation", signr);
        audit_log_end(ab);
 }
@@ -2730,8 +2397,11 @@ void __audit_seccomp(unsigned long syscall, long signr, int code)
 {
        struct audit_buffer *ab;
 
-       ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND);
-       audit_log_abend(ab, "seccomp", signr);
+       ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_SECCOMP);
+       if (unlikely(!ab))
+               return;
+       audit_log_task(ab);
+       audit_log_format(ab, " sig=%ld", signr);
        audit_log_format(ab, " syscall=%ld", syscall);
        audit_log_format(ab, " compat=%d", is_compat_task());
        audit_log_format(ab, " ip=0x%lx", KSTK_EIP(current));