drivers: power: report battery voltage in AOSP compatible format
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / kernel / auditsc.c
index c68229411a7c20afbd6903f7272d23afbc0e9ac0..138cce22ec9ad0507bde7504ad2aa32225960f8d 100644 (file)
@@ -68,7 +68,7 @@
 #include <linux/capability.h>
 #include <linux/fs_struct.h>
 #include <linux/compat.h>
-
+#include <linux/uaccess.h>
 #include "audit.h"
 
 /* flags stating the success for a syscall */
 #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) */
+/* no execve audit message should be longer than this (userspace limits),
+ * see the note near the top of audit_log_execve_info() about this value */
 #define MAX_EXECVE_AUDIT_LEN 7500
 
 /* number of audit rules */
@@ -90,44 +86,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 +133,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 +491,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 +614,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:
@@ -859,6 +734,22 @@ static enum audit_state audit_filter_task(struct task_struct *tsk, char **key)
        return AUDIT_BUILD_CONTEXT;
 }
 
+static int audit_in_mask(const struct audit_krule *rule, unsigned long val)
+{
+       int word, bit;
+
+       if (val > 0xffffffff)
+               return false;
+
+       word = AUDIT_WORD(val);
+       if (word >= AUDIT_BITMASK_SIZE)
+               return false;
+
+       bit = AUDIT_BIT(val);
+
+       return rule->mask[word] & bit;
+}
+
 /* At syscall entry and exit time, this filter is called if the
  * audit_state is not low enough that auditing cannot take place, but is
  * also not high enough that we already know we have to write an audit
@@ -876,11 +767,8 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,
 
        rcu_read_lock();
        if (!list_empty(list)) {
-               int word = AUDIT_WORD(ctx->major);
-               int bit  = AUDIT_BIT(ctx->major);
-
                list_for_each_entry_rcu(e, list, list) {
-                       if ((e->rule.mask[word] & bit) == bit &&
+                       if (audit_in_mask(&e->rule, ctx->major) &&
                            audit_filter_rules(tsk, &e->rule, ctx, NULL,
                                               &state, false)) {
                                rcu_read_unlock();
@@ -900,20 +788,16 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,
 static int audit_filter_inode_name(struct task_struct *tsk,
                                   struct audit_names *n,
                                   struct audit_context *ctx) {
-       int word, bit;
        int h = audit_hash_ino((u32)n->ino);
        struct list_head *list = &audit_inode_hash[h];
        struct audit_entry *e;
        enum audit_state state;
 
-       word = AUDIT_WORD(ctx->major);
-       bit  = AUDIT_BIT(ctx->major);
-
        if (list_empty(list))
                return 0;
 
        list_for_each_entry_rcu(e, list, list) {
-               if ((e->rule.mask[word] & bit) == bit &&
+               if (audit_in_mask(&e->rule, ctx->major) &&
                    audit_filter_rules(tsk, &e->rule, ctx, n, &state, false)) {
                        ctx->current_state = state;
                        return 1;
@@ -987,6 +871,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 +881,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 +896,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 +979,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 +995,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);
@@ -1205,218 +1011,180 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
        return rc;
 }
 
-/*
- * to_send and len_sent accounting are very loose estimates.  We aren't
- * really worried about a hard cap to MAX_EXECVE_AUDIT_LEN so much as being
- * within about 500 bytes (next page boundary)
- *
- * why snprintf?  an int is up to 12 digits long.  if we just assumed when
- * logging that a[%d]= was going to be 16 characters long we would be wasting
- * space in every audit message.  In one 7500 byte message we can log up to
- * about 1000 min size arguments.  That comes down to about 50% waste of space
- * if we didn't do the snprintf to find out how long arg_num_len was.
- */
-static int audit_log_single_execve_arg(struct audit_context *context,
-                                       struct audit_buffer **ab,
-                                       int arg_num,
-                                       size_t *len_sent,
-                                       const char __user *p,
-                                       char *buf)
-{
-       char arg_num_len_buf[12];
-       const char __user *tmp_p = p;
-       /* how many digits are in arg_num? 5 is the length of ' a=""' */
-       size_t arg_num_len = snprintf(arg_num_len_buf, 12, "%d", arg_num) + 5;
-       size_t len, len_left, to_send;
-       size_t max_execve_audit_len = MAX_EXECVE_AUDIT_LEN;
-       unsigned int i, has_cntl = 0, too_long = 0;
-       int ret;
-
-       /* strnlen_user includes the null we don't want to send */
-       len_left = len = strnlen_user(p, MAX_ARG_STRLEN) - 1;
-
-       /*
-        * We just created this mm, if we can't find the strings
-        * we just copied into it something is _very_ wrong. Similar
-        * for strings that are too long, we should not have created
-        * any.
-        */
-       if (unlikely((len == -1) || len > MAX_ARG_STRLEN - 1)) {
-               WARN_ON(1);
-               send_sig(SIGKILL, current, 0);
-               return -1;
-       }
-
-       /* walk the whole argument looking for non-ascii chars */
-       do {
-               if (len_left > MAX_EXECVE_AUDIT_LEN)
-                       to_send = MAX_EXECVE_AUDIT_LEN;
-               else
-                       to_send = len_left;
-               ret = copy_from_user(buf, tmp_p, to_send);
-               /*
-                * There is no reason for this copy to be short. We just
-                * copied them here, and the mm hasn't been exposed to user-
-                * space yet.
-                */
-               if (ret) {
-                       WARN_ON(1);
-                       send_sig(SIGKILL, current, 0);
-                       return -1;
-               }
-               buf[to_send] = '\0';
-               has_cntl = audit_string_contains_control(buf, to_send);
-               if (has_cntl) {
-                       /*
-                        * hex messages get logged as 2 bytes, so we can only
-                        * send half as much in each message
-                        */
-                       max_execve_audit_len = MAX_EXECVE_AUDIT_LEN / 2;
-                       break;
-               }
-               len_left -= to_send;
-               tmp_p += to_send;
-       } while (len_left > 0);
-
-       len_left = len;
-
-       if (len > max_execve_audit_len)
-               too_long = 1;
-
-       /* rewalk the argument actually logging the message */
-       for (i = 0; len_left > 0; i++) {
-               int room_left;
-
-               if (len_left > max_execve_audit_len)
-                       to_send = max_execve_audit_len;
-               else
-                       to_send = len_left;
-
-               /* do we have space left to send this argument in this ab? */
-               room_left = MAX_EXECVE_AUDIT_LEN - arg_num_len - *len_sent;
-               if (has_cntl)
-                       room_left -= (to_send * 2);
-               else
-                       room_left -= to_send;
-               if (room_left < 0) {
-                       *len_sent = 0;
-                       audit_log_end(*ab);
-                       *ab = audit_log_start(context, GFP_KERNEL, AUDIT_EXECVE);
-                       if (!*ab)
-                               return 0;
-               }
-
-               /*
-                * first record needs to say how long the original string was
-                * so we can be sure nothing was lost.
-                */
-               if ((i == 0) && (too_long))
-                       audit_log_format(*ab, " a%d_len=%zu", arg_num,
-                                        has_cntl ? 2*len : len);
-
-               /*
-                * normally arguments are small enough to fit and we already
-                * filled buf above when we checked for control characters
-                * so don't bother with another copy_from_user
-                */
-               if (len >= max_execve_audit_len)
-                       ret = copy_from_user(buf, p, to_send);
-               else
-                       ret = 0;
-               if (ret) {
-                       WARN_ON(1);
-                       send_sig(SIGKILL, current, 0);
-                       return -1;
-               }
-               buf[to_send] = '\0';
-
-               /* actually log it */
-               audit_log_format(*ab, " a%d", arg_num);
-               if (too_long)
-                       audit_log_format(*ab, "[%d]", i);
-               audit_log_format(*ab, "=");
-               if (has_cntl)
-                       audit_log_n_hex(*ab, buf, to_send);
-               else
-                       audit_log_string(*ab, buf);
-
-               p += to_send;
-               len_left -= to_send;
-               *len_sent += arg_num_len;
-               if (has_cntl)
-                       *len_sent += to_send * 2;
-               else
-                       *len_sent += to_send;
-       }
-       /* include the null we didn't log */
-       return len + 1;
-}
-
 static void audit_log_execve_info(struct audit_context *context,
-                                 struct audit_buffer **ab,
-                                 struct audit_aux_data_execve *axi)
-{
-       int i, len;
-       size_t len_sent = 0;
-       const char __user *p;
+                                struct audit_buffer **ab)
+{
+       long len_max;
+       long len_rem;
+       long len_full;
+       long len_buf;
+       long len_abuf;
+       long len_tmp;
+       bool require_data;
+       bool encode;
+       unsigned int iter;
+       unsigned int arg;
+       char *buf_head;
        char *buf;
+       const char __user *p = (const char __user *)current->mm->arg_start;
+
+       /* NOTE: this buffer needs to be large enough to hold all the non-arg
+        *       data we put in the audit record for this argument (see the
+        *       code below) ... at this point in time 96 is plenty */
+       char abuf[96];
+
+       /* NOTE: we set MAX_EXECVE_AUDIT_LEN to a rather arbitrary limit, the
+        *       current value of 7500 is not as important as the fact that it
+        *       is less than 8k, a setting of 7500 gives us plenty of wiggle
+        *       room if we go over a little bit in the logging below */
+       WARN_ON_ONCE(MAX_EXECVE_AUDIT_LEN > 7500);
+       len_max = MAX_EXECVE_AUDIT_LEN;
+
+       /* scratch buffer to hold the userspace args */
+       buf_head = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL);
+       if (!buf_head) {
+               audit_panic("out of memory for argv string");
+               return;
+       }
+       buf = buf_head;
 
-       if (axi->mm != current->mm)
-               return; /* execve failed, no additional info */
+       audit_log_format(*ab, "argc=%d", context->execve.argc);
 
-       p = (const char __user *)axi->mm->arg_start;
+       len_rem = len_max;
+       len_buf = 0;
+       len_full = 0;
+       require_data = true;
+       encode = false;
+       iter = 0;
+       arg = 0;
 
-       audit_log_format(*ab, "argc=%d", axi->argc);
+       do {
+               /* NOTE: we don't ever want to trust this value for anything
+                *       serious, but the audit record format insists we
+                *       provide an argument length for really long arguments,
+                *       e.g. > MAX_EXECVE_AUDIT_LEN, so we have no choice but
+                *       to use strncpy_from_user() to obtain this value for
+                *       recording in the log, although we don't use it
+                *       anywhere here to avoid a double-fetch problem */
+               if (len_full == 0)
+                       len_full = strnlen_user(p, MAX_ARG_STRLEN) - 1;
+
+               /* read more data from userspace */
+               if (require_data) {
+                       /* can we make more room in the buffer? */
+                       if (buf != buf_head) {
+                               memmove(buf_head, buf, len_buf);
+                               buf = buf_head;
+                       }
 
-       /*
-        * we need some kernel buffer to hold the userspace args.  Just
-        * allocate one big one rather than allocating one of the right size
-        * for every single argument inside audit_log_single_execve_arg()
-        * should be <8k allocation so should be pretty safe.
-        */
-       buf = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL);
-       if (!buf) {
-               audit_panic("out of memory for argv string\n");
-               return;
-       }
+                       /* fetch as much as we can of the argument */
+                       len_tmp = strncpy_from_user(&buf_head[len_buf], p,
+                                                   len_max - len_buf);
+                       if (len_tmp == -EFAULT) {
+                               /* unable to copy from userspace */
+                               send_sig(SIGKILL, current, 0);
+                               goto out;
+                       } else if (len_tmp == (len_max - len_buf)) {
+                               /* buffer is not large enough */
+                               require_data = true;
+                               /* NOTE: if we are going to span multiple
+                                *       buffers force the encoding so we stand
+                                *       a chance at a sane len_full value and
+                                *       consistent record encoding */
+                               encode = true;
+                               len_full = len_full * 2;
+                               p += len_tmp;
+                       } else {
+                               require_data = false;
+                               if (!encode)
+                                       encode = audit_string_contains_control(
+                                                               buf, len_tmp);
+                               /* try to use a trusted value for len_full */
+                               if (len_full < len_max)
+                                       len_full = (encode ?
+                                                   len_tmp * 2 : len_tmp);
+                               p += len_tmp + 1;
+                       }
+                       len_buf += len_tmp;
+                       buf_head[len_buf] = '\0';
 
-       for (i = 0; i < axi->argc; i++) {
-               len = audit_log_single_execve_arg(context, ab, i,
-                                                 &len_sent, p, buf);
-               if (len <= 0)
-                       break;
-               p += len;
-       }
-       kfree(buf);
-}
+                       /* length of the buffer in the audit record? */
+                       len_abuf = (encode ? len_buf * 2 : len_buf + 2);
 
-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]);
-       }
-}
+               /* write as much as we can to the audit log */
+               if (len_buf > 0) {
+                       /* NOTE: some magic numbers here - basically if we
+                        *       can't fit a reasonable amount of data into the
+                        *       existing audit buffer, flush it and start with
+                        *       a new buffer */
+                       if ((sizeof(abuf) + 8) > len_rem) {
+                               len_rem = len_max;
+                               audit_log_end(*ab);
+                               *ab = audit_log_start(context,
+                                                     GFP_KERNEL, AUDIT_EXECVE);
+                               if (!*ab)
+                                       goto out;
+                       }
 
-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;
+                       /* create the non-arg portion of the arg record */
+                       len_tmp = 0;
+                       if (require_data || (iter > 0) ||
+                           ((len_abuf + sizeof(abuf)) > len_rem)) {
+                               if (iter == 0) {
+                                       len_tmp += snprintf(&abuf[len_tmp],
+                                                       sizeof(abuf) - len_tmp,
+                                                       " a%d_len=%lu",
+                                                       arg, len_full);
+                               }
+                               len_tmp += snprintf(&abuf[len_tmp],
+                                                   sizeof(abuf) - len_tmp,
+                                                   " a%d[%d]=", arg, iter++);
+                       } else
+                               len_tmp += snprintf(&abuf[len_tmp],
+                                                   sizeof(abuf) - len_tmp,
+                                                   " a%d=", arg);
+                       WARN_ON(len_tmp >= sizeof(abuf));
+                       abuf[sizeof(abuf) - 1] = '\0';
+
+                       /* log the arg in the audit record */
+                       audit_log_format(*ab, "%s", abuf);
+                       len_rem -= len_tmp;
+                       len_tmp = len_buf;
+                       if (encode) {
+                               if (len_abuf > len_rem)
+                                       len_tmp = len_rem / 2; /* encoding */
+                               audit_log_n_hex(*ab, buf, len_tmp);
+                               len_rem -= len_tmp * 2;
+                               len_abuf -= len_tmp * 2;
+                       } else {
+                               if (len_abuf > len_rem)
+                                       len_tmp = len_rem - 2; /* quotes */
+                               audit_log_n_string(*ab, buf, len_tmp);
+                               len_rem -= len_tmp + 2;
+                               /* don't subtract the "2" because we still need
+                                * to add quotes to the remaining string */
+                               len_abuf -= len_tmp;
+                       }
+                       len_buf -= len_tmp;
+                       buf += len_tmp;
+               }
 
-       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;
-       }
+               /* ready to move to the next argument? */
+               if ((len_buf == 0) && !require_data) {
+                       arg++;
+                       iter = 0;
+                       len_full = 0;
+                       require_data = true;
+                       encode = false;
+               }
+       } while (arg < context->execve.argc);
+
+       /* NOTE: the caller handles the final audit_log_end() call */
 
-       if (log)
-               audit_log_format(ab, " cap_fe=%d cap_fver=%x", name->fcap.fE, name->fcap_ver);
+out:
+       kfree(buf_head);
 }
 
 static void show_special(struct audit_context *context, int *call_panic)
@@ -1516,68 +1284,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;
@@ -1621,8 +1327,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                switch (aux->type) {
 
                case AUDIT_EXECVE: {
-                       struct audit_aux_data_execve *axi = (void *)aux;
-                       audit_log_execve_info(context, &ab, axi);
+                       audit_log_execve_info(context, &ab);
                        break; }
 
                case AUDIT_BPRM_FCAPS: {
@@ -1694,8 +1399,11 @@ 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);
+       list_for_each_entry(n, &context->names_list, list) {
+               if (n->hidden)
+                       continue;
+               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 +1738,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,53 +1768,19 @@ 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
  * @dentry: dentry being audited
- * @parent: does this dentry represent the parent?
+ * @flags: attributes for this particular entry
  */
 void __audit_inode(struct filename *name, const struct dentry *dentry,
-                  unsigned int parent)
+                  unsigned int flags)
 {
        struct audit_context *context = current->audit_context;
        const struct inode *inode = dentry->d_inode;
        struct audit_names *n;
+       bool parent = flags & AUDIT_INODE_PARENT;
 
        if (!context->in_syscall)
                return;
@@ -2161,6 +1835,8 @@ out:
        if (parent) {
                n->name_len = n->name ? parent_len(n->name->name) : AUDIT_NAME_FULL;
                n->type = AUDIT_TYPE_PARENT;
+               if (flags & AUDIT_INODE_HIDDEN)
+                       n->hidden = true;
        } else {
                n->name_len = AUDIT_NAME_FULL;
                n->type = AUDIT_TYPE_NORMAL;
@@ -2303,7 +1979,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 +2147,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;
 }
 
 /**