This patch will print cap_permitted and cap_inheritable data in the PATH
[safe/jmp/linux-2.6] / kernel / auditsc.c
index 2243c55..de7e9bc 100644 (file)
@@ -45,7 +45,6 @@
 #include <linux/init.h>
 #include <asm/types.h>
 #include <asm/atomic.h>
-#include <asm/types.h>
 #include <linux/fs.h>
 #include <linux/namei.h>
 #include <linux/mm.h>
 #include <linux/security.h>
 #include <linux/list.h>
 #include <linux/tty.h>
-#include <linux/selinux.h>
 #include <linux/binfmts.h>
 #include <linux/highmem.h>
 #include <linux/syscalls.h>
+#include <linux/inotify.h>
+#include <linux/capability.h>
 
 #include "audit.h"
 
-extern struct list_head audit_filter_list[];
-
-/* No syscall auditing will take place unless audit_enabled != 0. */
-extern int audit_enabled;
-
 /* AUDIT_NAMES is the number of slots we reserve in the audit_context
  * for saving names from getname(). */
 #define AUDIT_NAMES    20
 
-/* AUDIT_NAMES_RESERVED is the number of slots we reserve in the
- * audit_context from being used for nameless inodes from
- * path_lookup. */
-#define AUDIT_NAMES_RESERVED 7
-
 /* Indicates that audit should log the full pathname. */
 #define AUDIT_NAME_FULL -1
 
+/* no execve audit message should be longer than this (userspace limits) */
+#define MAX_EXECVE_AUDIT_LEN 7500
+
 /* number of audit rules */
 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).
@@ -105,6 +110,8 @@ struct audit_names {
        gid_t           gid;
        dev_t           rdev;
        u32             osid;
+       struct audit_cap_data fcap;
+       unsigned int    fcap_ver;
 };
 
 struct audit_aux_data {
@@ -114,6 +121,9 @@ struct audit_aux_data {
 
 #define AUDIT_AUX_IPCPERM      0
 
+/* Number of target pids per aux struct. */
+#define AUDIT_AUX_PIDS 16
+
 struct audit_aux_data_mq_open {
        struct audit_aux_data   d;
        int                     oflag;
@@ -155,7 +165,7 @@ struct audit_aux_data_execve {
        struct audit_aux_data   d;
        int argc;
        int envc;
-       char mem[0];
+       struct mm_struct *mm;
 };
 
 struct audit_aux_data_socketcall {
@@ -175,10 +185,20 @@ struct audit_aux_data_fd_pair {
        int     fd[2];
 };
 
-struct audit_aux_data_path {
+struct audit_aux_data_pids {
        struct audit_aux_data   d;
-       struct dentry           *dentry;
-       struct vfsmount         *mnt;
+       pid_t                   target_pid[AUDIT_AUX_PIDS];
+       uid_t                   target_auid[AUDIT_AUX_PIDS];
+       uid_t                   target_uid[AUDIT_AUX_PIDS];
+       unsigned int            target_sessionid[AUDIT_AUX_PIDS];
+       u32                     target_sid[AUDIT_AUX_PIDS];
+       char                    target_comm[AUDIT_AUX_PIDS][TASK_COMM_LEN];
+       int                     pid_count;
+};
+
+struct audit_tree_refs {
+       struct audit_tree_refs *next;
+       struct audit_chunk *c[31];
 };
 
 /* The per-task audit context. */
@@ -188,7 +208,6 @@ struct audit_context {
        enum audit_state    state;
        unsigned int        serial;     /* serial number for record */
        struct timespec     ctime;      /* time of syscall entry */
-       uid_t               loginuid;   /* login uid (identity) */
        int                 major;      /* syscall number */
        unsigned long       argv[4];    /* syscall arguments */
        int                 return_valid; /* return code is valid */
@@ -197,10 +216,10 @@ struct audit_context {
        int                 name_count;
        struct audit_names  names[AUDIT_NAMES];
        char *              filterkey;  /* key for rule that triggered record */
-       struct dentry *     pwd;
-       struct vfsmount *   pwdmnt;
+       struct path         pwd;
        struct audit_context *previous; /* For nested syscalls */
        struct audit_aux_data *aux;
+       struct audit_aux_data *aux_pids;
 
                                /* Save things to print about task_struct */
        pid_t               pid, ppid;
@@ -210,7 +229,14 @@ struct audit_context {
        int                 arch;
 
        pid_t               target_pid;
+       uid_t               target_auid;
+       uid_t               target_uid;
+       unsigned int        target_sessionid;
        u32                 target_sid;
+       char                target_comm[TASK_COMM_LEN];
+
+       struct audit_tree_refs *trees, *first_trees;
+       int tree_count;
 
 #if AUDIT_DEBUG
        int                 put_count;
@@ -229,7 +255,11 @@ static inline int open_arg(int flags, int mask)
 
 static int audit_match_perm(struct audit_context *ctx, int mask)
 {
-       unsigned n = ctx->major;
+       unsigned n;
+       if (unlikely(!ctx))
+               return 0;
+       n = ctx->major;
+
        switch (audit_classify_syscall(ctx->arch, n)) {
        case 0: /* native */
                if ((mask & AUDIT_PERM_WRITE) &&
@@ -266,6 +296,134 @@ static int audit_match_perm(struct audit_context *ctx, int mask)
        }
 }
 
+static int audit_match_filetype(struct audit_context *ctx, int which)
+{
+       unsigned index = which & ~S_IFMT;
+       mode_t mode = which & S_IFMT;
+
+       if (unlikely(!ctx))
+               return 0;
+
+       if (index >= ctx->name_count)
+               return 0;
+       if (ctx->names[index].ino == -1)
+               return 0;
+       if ((ctx->names[index].mode ^ mode) & S_IFMT)
+               return 0;
+       return 1;
+}
+
+/*
+ * We keep a linked list of fixed-sized (31 pointer) arrays of audit_chunk *;
+ * ->first_trees points to its beginning, ->trees - to the current end of data.
+ * ->tree_count is the number of free entries in array pointed to by ->trees.
+ * Original condition is (NULL, NULL, 0); as soon as it grows we never revert to NULL,
+ * "empty" becomes (p, p, 31) afterwards.  We don't shrink the list (and seriously,
+ * it's going to remain 1-element for almost any setup) until we free context itself.
+ * References in it _are_ dropped - at the same time we free/drop aux stuff.
+ */
+
+#ifdef CONFIG_AUDIT_TREE
+static int put_tree_ref(struct audit_context *ctx, struct audit_chunk *chunk)
+{
+       struct audit_tree_refs *p = ctx->trees;
+       int left = ctx->tree_count;
+       if (likely(left)) {
+               p->c[--left] = chunk;
+               ctx->tree_count = left;
+               return 1;
+       }
+       if (!p)
+               return 0;
+       p = p->next;
+       if (p) {
+               p->c[30] = chunk;
+               ctx->trees = p;
+               ctx->tree_count = 30;
+               return 1;
+       }
+       return 0;
+}
+
+static int grow_tree_refs(struct audit_context *ctx)
+{
+       struct audit_tree_refs *p = ctx->trees;
+       ctx->trees = kzalloc(sizeof(struct audit_tree_refs), GFP_KERNEL);
+       if (!ctx->trees) {
+               ctx->trees = p;
+               return 0;
+       }
+       if (p)
+               p->next = ctx->trees;
+       else
+               ctx->first_trees = ctx->trees;
+       ctx->tree_count = 31;
+       return 1;
+}
+#endif
+
+static void unroll_tree_refs(struct audit_context *ctx,
+                     struct audit_tree_refs *p, int count)
+{
+#ifdef CONFIG_AUDIT_TREE
+       struct audit_tree_refs *q;
+       int n;
+       if (!p) {
+               /* we started with empty chain */
+               p = ctx->first_trees;
+               count = 31;
+               /* if the very first allocation has failed, nothing to do */
+               if (!p)
+                       return;
+       }
+       n = count;
+       for (q = p; q != ctx->trees; q = q->next, n = 31) {
+               while (n--) {
+                       audit_put_chunk(q->c[n]);
+                       q->c[n] = NULL;
+               }
+       }
+       while (n-- > ctx->tree_count) {
+               audit_put_chunk(q->c[n]);
+               q->c[n] = NULL;
+       }
+       ctx->trees = p;
+       ctx->tree_count = count;
+#endif
+}
+
+static void free_tree_refs(struct audit_context *ctx)
+{
+       struct audit_tree_refs *p, *q;
+       for (p = ctx->first_trees; p; p = q) {
+               q = p->next;
+               kfree(p);
+       }
+}
+
+static int match_tree_refs(struct audit_context *ctx, struct audit_tree *tree)
+{
+#ifdef CONFIG_AUDIT_TREE
+       struct audit_tree_refs *p;
+       int n;
+       if (!tree)
+               return 0;
+       /* full ones */
+       for (p = ctx->first_trees; p != ctx->trees; p = p->next) {
+               for (n = 0; n < 31; n++)
+                       if (audit_tree_match(p->c[n], tree))
+                               return 1;
+       }
+       /* partial */
+       if (p) {
+               for (n = ctx->tree_count; n < 31; n++)
+                       if (audit_tree_match(p->c[n], tree))
+                               return 1;
+       }
+#endif
+       return 0;
+}
+
 /* Determine if any context name data matches a rule's watch data */
 /* Compare a task_struct with an audit_rule.  Return 1 on match, 0
  * otherwise. */
@@ -321,7 +479,7 @@ static int audit_filter_rules(struct task_struct *tsk,
                        result = audit_comparator(tsk->personality, f->op, f->val);
                        break;
                case AUDIT_ARCH:
-                       if (ctx)
+                       if (ctx)
                                result = audit_comparator(ctx->arch, f->op, f->val);
                        break;
 
@@ -380,10 +538,14 @@ static int audit_filter_rules(struct task_struct *tsk,
                                result = (name->dev == rule->watch->dev &&
                                          name->ino == rule->watch->ino);
                        break;
+               case AUDIT_DIR:
+                       if (ctx)
+                               result = match_tree_refs(ctx, rule->tree);
+                       break;
                case AUDIT_LOGINUID:
                        result = 0;
                        if (ctx)
-                               result = audit_comparator(ctx->loginuid, f->op, f->val);
+                               result = audit_comparator(tsk->loginuid, f->op, f->val);
                        break;
                case AUDIT_SUBJ_USER:
                case AUDIT_SUBJ_ROLE:
@@ -395,14 +557,14 @@ static int audit_filter_rules(struct task_struct *tsk,
                           match for now to avoid losing information that
                           may be wanted.   An error message will also be
                           logged upon error */
-                       if (f->se_rule) {
+                       if (f->lsm_rule) {
                                if (need_sid) {
-                                       selinux_get_task_sid(tsk, &sid);
+                                       security_task_getsecid(tsk, &sid);
                                        need_sid = 0;
                                }
-                               result = selinux_audit_rule_match(sid, f->type,
+                               result = security_audit_rule_match(sid, f->type,
                                                                  f->op,
-                                                                 f->se_rule,
+                                                                 f->lsm_rule,
                                                                  ctx);
                        }
                        break;
@@ -413,18 +575,18 @@ static int audit_filter_rules(struct task_struct *tsk,
                case AUDIT_OBJ_LEV_HIGH:
                        /* The above note for AUDIT_SUBJ_USER...AUDIT_SUBJ_CLR
                           also applies here */
-                       if (f->se_rule) {
+                       if (f->lsm_rule) {
                                /* Find files that match */
                                if (name) {
-                                       result = selinux_audit_rule_match(
+                                       result = security_audit_rule_match(
                                                   name->osid, f->type, f->op,
-                                                  f->se_rule, ctx);
+                                                  f->lsm_rule, ctx);
                                } else if (ctx) {
                                        for (j = 0; j < ctx->name_count; j++) {
-                                               if (selinux_audit_rule_match(
+                                               if (security_audit_rule_match(
                                                      ctx->names[j].osid,
                                                      f->type, f->op,
-                                                     f->se_rule, ctx)) {
+                                                     f->lsm_rule, ctx)) {
                                                        ++result;
                                                        break;
                                                }
@@ -437,7 +599,7 @@ static int audit_filter_rules(struct task_struct *tsk,
                                             aux = aux->next) {
                                                if (aux->type == AUDIT_IPC) {
                                                        struct audit_aux_data_ipcctl *axi = (void *)aux;
-                                                       if (selinux_audit_rule_match(axi->osid, f->type, f->op, f->se_rule, ctx)) {
+                                                       if (security_audit_rule_match(axi->osid, f->type, f->op, f->lsm_rule, ctx)) {
                                                                ++result;
                                                                break;
                                                        }
@@ -460,12 +622,15 @@ static int audit_filter_rules(struct task_struct *tsk,
                case AUDIT_PERM:
                        result = audit_match_perm(ctx, f->val);
                        break;
+               case AUDIT_FILETYPE:
+                       result = audit_match_filetype(ctx, f->val);
+                       break;
                }
 
                if (!result)
                        return 0;
        }
-       if (rule->filterkey)
+       if (rule->filterkey && ctx)
                ctx->filterkey = kstrdup(rule->filterkey, GFP_ATOMIC);
        switch (rule->action) {
        case AUDIT_NEVER:    *state = AUDIT_DISABLED;       break;
@@ -579,7 +744,24 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk,
        if (likely(!context))
                return NULL;
        context->return_valid = return_valid;
-       context->return_code  = return_code;
+
+       /*
+        * we need to fix up the return code in the audit logs if the actual
+        * return codes are later going to be fixed up by the arch specific
+        * signal handlers
+        *
+        * This is actually a test for:
+        * (rc == ERESTARTSYS ) || (rc == ERESTARTNOINTR) ||
+        * (rc == ERESTARTNOHAND) || (rc == ERESTART_RESTARTBLOCK)
+        *
+        * but is faster than a bunch of ||
+        */
+       if (unlikely(return_code <= -ERESTARTSYS) &&
+           (return_code >= -ERESTART_RESTARTBLOCK) &&
+           (return_code != -ENOIOCTLCMD))
+               context->return_code = -EINTR;
+       else
+               context->return_code  = return_code;
 
        if (context->in_syscall && !context->dummy && !context->auditable) {
                enum audit_state state;
@@ -635,12 +817,9 @@ static inline void audit_free_names(struct audit_context *context)
                        __putname(context->names[i].name);
        }
        context->name_count = 0;
-       if (context->pwd)
-               dput(context->pwd);
-       if (context->pwdmnt)
-               mntput(context->pwdmnt);
-       context->pwd = NULL;
-       context->pwdmnt = NULL;
+       path_put(&context->pwd);
+       context->pwd.dentry = NULL;
+       context->pwd.mnt = NULL;
 }
 
 static inline void audit_free_aux(struct audit_context *context)
@@ -648,25 +827,20 @@ static inline void audit_free_aux(struct audit_context *context)
        struct audit_aux_data *aux;
 
        while ((aux = context->aux)) {
-               if (aux->type == AUDIT_AVC_PATH) {
-                       struct audit_aux_data_path *axi = (void *)aux;
-                       dput(axi->dentry);
-                       mntput(axi->mnt);
-               }
-
                context->aux = aux->next;
                kfree(aux);
        }
+       while ((aux = context->aux_pids)) {
+               context->aux_pids = aux->next;
+               kfree(aux);
+       }
 }
 
 static inline void audit_zero_context(struct audit_context *context,
                                      enum audit_state state)
 {
-       uid_t loginuid = context->loginuid;
-
        memset(context, 0, sizeof(*context));
        context->state      = state;
-       context->loginuid   = loginuid;
 }
 
 static inline struct audit_context *audit_alloc_context(enum audit_state state)
@@ -693,7 +867,7 @@ int audit_alloc(struct task_struct *tsk)
        struct audit_context *context;
        enum audit_state     state;
 
-       if (likely(!audit_enabled))
+       if (likely(!audit_ever_enabled))
                return 0; /* Return if not auditing. */
 
        state = audit_filter_task(tsk);
@@ -705,11 +879,6 @@ int audit_alloc(struct task_struct *tsk)
                return -ENOMEM;
        }
 
-                               /* Preserve login uid */
-       context->loginuid = -1;
-       if (current->audit_context)
-               context->loginuid = current->audit_context->loginuid;
-
        tsk->audit_context  = context;
        set_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
        return 0;
@@ -730,6 +899,8 @@ static inline void audit_free_context(struct audit_context *context)
                               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);
@@ -746,11 +917,11 @@ void audit_log_task_context(struct audit_buffer *ab)
        int error;
        u32 sid;
 
-       selinux_get_task_sid(current, &sid);
+       security_task_getsecid(current, &sid);
        if (!sid)
                return;
 
-       error = selinux_sid_to_string(sid, &ctx, &len);
+       error = security_secid_to_secctx(sid, &ctx, &len);
        if (error) {
                if (error != -EINVAL)
                        goto error_path;
@@ -758,7 +929,7 @@ void audit_log_task_context(struct audit_buffer *ab)
        }
 
        audit_log_format(ab, " subj=%s", ctx);
-       kfree(ctx);
+       security_release_secctx(ctx, len);
        return;
 
 error_path:
@@ -787,8 +958,7 @@ static void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk
                        if ((vma->vm_flags & VM_EXECUTABLE) &&
                            vma->vm_file) {
                                audit_log_d_path(ab, "exe=",
-                                                vma->vm_file->f_path.dentry,
-                                                vma->vm_file->f_path.mnt);
+                                                &vma->vm_file->f_path);
                                break;
                        }
                        vma = vma->vm_next;
@@ -798,6 +968,250 @@ static void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk
        audit_log_task_context(ab);
 }
 
+static int audit_log_pid_context(struct audit_context *context, pid_t pid,
+                                uid_t auid, uid_t uid, unsigned int sessionid,
+                                u32 sid, char *comm)
+{
+       struct audit_buffer *ab;
+       char *ctx = NULL;
+       u32 len;
+       int rc = 0;
+
+       ab = audit_log_start(context, GFP_KERNEL, AUDIT_OBJ_PID);
+       if (!ab)
+               return rc;
+
+       audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid, auid,
+                        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);
+       }
+       audit_log_format(ab, " ocomm=");
+       audit_log_untrustedstring(ab, comm);
+       audit_log_end(ab);
+
+       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 boundry)
+ *
+ * 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? 3 is the length of a=\n */
+       size_t arg_num_len = snprintf(arg_num_len_buf, 12, "%d", arg_num) + 3;
+       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_format(*ab, "\"%s\"", buf);
+               audit_log_format(*ab, "\n");
+
+               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;
+       size_t len, len_sent = 0;
+       const char __user *p;
+       char *buf;
+
+       if (axi->mm != current->mm)
+               return; /* execve failed, no additional info */
+
+       p = (const char __user *)axi->mm->arg_start;
+
+       audit_log_format(*ab, "argc=%d ", axi->argc);
+
+       /*
+        * 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;
+       }
+
+       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);
+}
+
+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 audit_log_exit(struct audit_context *context, struct task_struct *tsk)
 {
        int i, call_panic = 0;
@@ -827,22 +1241,22 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
        if (context->personality != PER_LINUX)
                audit_log_format(ab, " per=%lx", context->personality);
        if (context->return_valid)
-               audit_log_format(ab, " success=%s exit=%ld", 
+               audit_log_format(ab, " success=%s exit=%ld",
                                 (context->return_valid==AUDITSC_SUCCESS)?"yes":"no",
                                 context->return_code);
 
-       mutex_lock(&tty_mutex);
-       read_lock(&tasklist_lock);
+       spin_lock_irq(&tsk->sighand->siglock);
        if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name)
                tty = tsk->signal->tty->name;
        else
                tty = "(none)";
-       read_unlock(&tasklist_lock);
+       spin_unlock_irq(&tsk->sighand->siglock);
+
        audit_log_format(ab,
                  " a0=%lx a1=%lx a2=%lx a3=%lx items=%d"
                  " ppid=%d pid=%d auid=%u uid=%u gid=%u"
                  " euid=%u suid=%u fsuid=%u"
-                 " egid=%u sgid=%u fsgid=%u tty=%s",
+                 " egid=%u sgid=%u fsgid=%u tty=%s ses=%u",
                  context->argv[0],
                  context->argv[1],
                  context->argv[2],
@@ -850,13 +1264,13 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                  context->name_count,
                  context->ppid,
                  context->pid,
-                 context->loginuid,
+                 tsk->loginuid,
                  context->uid,
                  context->gid,
                  context->euid, context->suid, context->fsuid,
-                 context->egid, context->sgid, context->fsgid, tty);
+                 context->egid, context->sgid, context->fsgid, tty,
+                 tsk->sessionid);
 
-       mutex_unlock(&tty_mutex);
 
        audit_log_task_info(ab, tsk);
        if (context->filterkey) {
@@ -913,42 +1327,36 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                case AUDIT_IPC: {
                        struct audit_aux_data_ipcctl *axi = (void *)aux;
                        audit_log_format(ab, 
-                                "ouid=%u ogid=%u mode=%x",
+                                "ouid=%u ogid=%u mode=%#o",
                                 axi->uid, axi->gid, axi->mode);
                        if (axi->osid != 0) {
                                char *ctx = NULL;
                                u32 len;
-                               if (selinux_sid_to_string(
+                               if (security_secid_to_secctx(
                                                axi->osid, &ctx, &len)) {
                                        audit_log_format(ab, " osid=%u",
                                                        axi->osid);
                                        call_panic = 1;
-                               } else
+                               } else {
                                        audit_log_format(ab, " obj=%s", ctx);
-                               kfree(ctx);
+                                       security_release_secctx(ctx, len);
+                               }
                        }
                        break; }
 
                case AUDIT_IPC_SET_PERM: {
                        struct audit_aux_data_ipcctl *axi = (void *)aux;
                        audit_log_format(ab,
-                               "qbytes=%lx ouid=%u ogid=%u mode=%x",
+                               "qbytes=%lx ouid=%u ogid=%u mode=%#o",
                                axi->qbytes, axi->uid, axi->gid, axi->mode);
                        break; }
 
                case AUDIT_EXECVE: {
                        struct audit_aux_data_execve *axi = (void *)aux;
-                       int i;
-                       const char *p;
-                       for (i = 0, p = axi->mem; i < axi->argc; i++) {
-                               audit_log_format(ab, "a%d=", i);
-                               p = audit_log_untrustedstring(ab, p);
-                               audit_log_format(ab, "\n");
-                       }
+                       audit_log_execve_info(context, &ab, axi);
                        break; }
 
                case AUDIT_SOCKETCALL: {
-                       int i;
                        struct audit_aux_data_socketcall *axs = (void *)aux;
                        audit_log_format(ab, "nargs=%d", axs->nargs);
                        for (i=0; i<axs->nargs; i++)
@@ -959,12 +1367,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                        struct audit_aux_data_sockaddr *axs = (void *)aux;
 
                        audit_log_format(ab, "saddr=");
-                       audit_log_hex(ab, axs->a, axs->len);
-                       break; }
-
-               case AUDIT_AVC_PATH: {
-                       struct audit_aux_data_path *axi = (void *)aux;
-                       audit_log_d_path(ab, "path=", axi->dentry, axi->mnt);
+                       audit_log_n_hex(ab, axs->a, axs->len);
                        break; }
 
                case AUDIT_FD_PAIR: {
@@ -976,27 +1379,30 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                audit_log_end(ab);
        }
 
-       if (context->target_pid) {
-               ab =audit_log_start(context, GFP_KERNEL, AUDIT_OBJ_PID);
-               if (ab) {
-                       char *s = NULL, *t;
-                       u32 len;
-                       if (selinux_sid_to_string(context->target_sid,
-                                                   &s, &len))
-                               t = "(none)";
-                       else
-                               t = s;
-                       audit_log_format(ab, "opid=%d obj=%s",
-                                       context->target_pid, t);
-                       audit_log_end(ab);
-                       kfree(s);
-               }
+       for (aux = context->aux_pids; aux; aux = aux->next) {
+               struct audit_aux_data_pids *axs = (void *)aux;
+
+               for (i = 0; i < axs->pid_count; i++)
+                       if (audit_log_pid_context(context, axs->target_pid[i],
+                                                 axs->target_auid[i],
+                                                 axs->target_uid[i],
+                                                 axs->target_sessionid[i],
+                                                 axs->target_sid[i],
+                                                 axs->target_comm[i]))
+                               call_panic = 1;
        }
 
-       if (context->pwd && context->pwdmnt) {
+       if (context->target_pid &&
+           audit_log_pid_context(context, context->target_pid,
+                                 context->target_auid, context->target_uid,
+                                 context->target_sessionid,
+                                 context->target_sid, context->target_comm))
+                       call_panic = 1;
+
+       if (context->pwd.dentry && context->pwd.mnt) {
                ab = audit_log_start(context, GFP_KERNEL, AUDIT_CWD);
                if (ab) {
-                       audit_log_d_path(ab, "cwd=", context->pwd, context->pwdmnt);
+                       audit_log_d_path(ab, "cwd=", &context->pwd);
                        audit_log_end(ab);
                }
        }
@@ -1019,14 +1425,13 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                        case 0:
                                /* name was specified as a relative path and the
                                 * directory component is the cwd */
-                               audit_log_d_path(ab, " name=", context->pwd,
-                                                context->pwdmnt);
+                               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_len,
-                                                           n->name);
+                               audit_log_n_untrustedstring(ab, n->name,
+                                                           n->name_len);
                        }
                } else
                        audit_log_format(ab, " name=(null)");
@@ -1047,17 +1452,25 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                if (n->osid != 0) {
                        char *ctx = NULL;
                        u32 len;
-                       if (selinux_sid_to_string(
+                       if (security_secid_to_secctx(
                                n->osid, &ctx, &len)) {
                                audit_log_format(ab, " osid=%u", n->osid);
                                call_panic = 2;
-                       } else
+                       } else {
                                audit_log_format(ab, " obj=%s", ctx);
-                       kfree(ctx);
+                               security_release_secctx(ctx, len);
+                       }
                }
 
+               audit_log_fcaps(ab, n);
+
                audit_log_end(ab);
        }
+
+       /* Send end of event record to help user space know we are finished */
+       ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE);
+       if (ab)
+               audit_log_end(ab);
        if (call_panic)
                audit_panic("error converting sid to string");
 }
@@ -1077,8 +1490,8 @@ void audit_free(struct task_struct *tsk)
                return;
 
        /* Check for system calls that do not go through the exit
-        * function (e.g., exit_group), then free context block. 
-        * We use GFP_ATOMIC here because we might be doing this 
+        * function (e.g., exit_group), then free context block.
+        * We use GFP_ATOMIC here because we might be doing this
         * in the context of the idle thread */
        /* that can happen only if we are called from do_exit() */
        if (context->in_syscall && context->auditable)
@@ -1113,7 +1526,8 @@ void audit_syscall_entry(int arch, int major,
        struct audit_context *context = tsk->audit_context;
        enum audit_state     state;
 
-       BUG_ON(!context);
+       if (unlikely(!context))
+               return;
 
        /*
         * This happens only on certain architectures that make system
@@ -1212,14 +1626,107 @@ void audit_syscall_exit(int valid, long return_code)
                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;
                kfree(context->filterkey);
                context->filterkey = NULL;
                tsk->audit_context = context;
        }
 }
 
+static inline void handle_one(const struct inode *inode)
+{
+#ifdef CONFIG_AUDIT_TREE
+       struct audit_context *context;
+       struct audit_tree_refs *p;
+       struct audit_chunk *chunk;
+       int count;
+       if (likely(list_empty(&inode->inotify_watches)))
+               return;
+       context = current->audit_context;
+       p = context->trees;
+       count = context->tree_count;
+       rcu_read_lock();
+       chunk = audit_tree_lookup(inode);
+       rcu_read_unlock();
+       if (!chunk)
+               return;
+       if (likely(put_tree_ref(context, chunk)))
+               return;
+       if (unlikely(!grow_tree_refs(context))) {
+               printk(KERN_WARNING "out of memory, audit has lost a tree reference\n");
+               audit_set_auditable(context);
+               audit_put_chunk(chunk);
+               unroll_tree_refs(context, p, count);
+               return;
+       }
+       put_tree_ref(context, chunk);
+#endif
+}
+
+static void handle_path(const struct dentry *dentry)
+{
+#ifdef CONFIG_AUDIT_TREE
+       struct audit_context *context;
+       struct audit_tree_refs *p;
+       const struct dentry *d, *parent;
+       struct audit_chunk *drop;
+       unsigned long seq;
+       int count;
+
+       context = current->audit_context;
+       p = context->trees;
+       count = context->tree_count;
+retry:
+       drop = NULL;
+       d = dentry;
+       rcu_read_lock();
+       seq = read_seqbegin(&rename_lock);
+       for(;;) {
+               struct inode *inode = d->d_inode;
+               if (inode && unlikely(!list_empty(&inode->inotify_watches))) {
+                       struct audit_chunk *chunk;
+                       chunk = audit_tree_lookup(inode);
+                       if (chunk) {
+                               if (unlikely(!put_tree_ref(context, chunk))) {
+                                       drop = chunk;
+                                       break;
+                               }
+                       }
+               }
+               parent = d->d_parent;
+               if (parent == d)
+                       break;
+               d = parent;
+       }
+       if (unlikely(read_seqretry(&rename_lock, seq) || drop)) {  /* in this order */
+               rcu_read_unlock();
+               if (!drop) {
+                       /* just a race with rename */
+                       unroll_tree_refs(context, p, count);
+                       goto retry;
+               }
+               audit_put_chunk(drop);
+               if (grow_tree_refs(context)) {
+                       /* OK, got more space */
+                       unroll_tree_refs(context, p, count);
+                       goto retry;
+               }
+               /* too bad */
+               printk(KERN_WARNING
+                       "out of memory, audit has lost a tree reference\n");
+               unroll_tree_refs(context, p, count);
+               audit_set_auditable(context);
+               return;
+       }
+       rcu_read_unlock();
+#endif
+}
+
 /**
  * audit_getname - add a name to the list
  * @name: name to add
@@ -1247,14 +1754,15 @@ void __audit_getname(const char *name)
        context->names[context->name_count].name_len = AUDIT_NAME_FULL;
        context->names[context->name_count].name_put = 1;
        context->names[context->name_count].ino  = (unsigned long)-1;
+       context->names[context->name_count].osid = 0;
        ++context->name_count;
-       if (!context->pwd) {
+       if (!context->pwd.dentry) {
                read_lock(&current->fs->lock);
-               context->pwd = dget(current->fs->pwd);
-               context->pwdmnt = mntget(current->fs->pwdmnt);
+               context->pwd = current->fs->pwd;
+               path_get(&current->fs->pwd);
                read_unlock(&current->fs->lock);
        }
-               
+
 }
 
 /* audit_putname - intercept a putname request
@@ -1300,8 +1808,58 @@ void audit_putname(const char *name)
 #endif
 }
 
+static int audit_inc_name_count(struct audit_context *context,
+                               const struct inode *inode)
+{
+       if (context->name_count >= AUDIT_NAMES) {
+               if (inode)
+                       printk(KERN_DEBUG "name_count maxed, losing inode data: "
+                              "dev=%02x:%02x, inode=%lu\n",
+                              MAJOR(inode->i_sb->s_dev),
+                              MINOR(inode->i_sb->s_dev),
+                              inode->i_ino);
+
+               else
+                       printk(KERN_DEBUG "name_count maxed, losing inode data\n");
+               return 1;
+       }
+       context->name_count++;
+#if AUDIT_DEBUG
+       context->ino_count++;
+#endif
+       return 0;
+}
+
+
+static inline int audit_copy_fcaps(struct audit_names *name, const struct dentry *dentry)
+{
+       struct cpu_vfs_cap_data caps;
+       int rc;
+
+       memset(&name->fcap.permitted, 0, sizeof(kernel_cap_t));
+       memset(&name->fcap.inheritable, 0, sizeof(kernel_cap_t));
+       name->fcap.fE = 0;
+       name->fcap_ver = 0;
+
+       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 inode *inode)
+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;
@@ -1309,20 +1867,22 @@ static void audit_copy_inode(struct audit_names *name, const struct inode *inode
        name->uid   = inode->i_uid;
        name->gid   = inode->i_gid;
        name->rdev  = inode->i_rdev;
-       selinux_get_inode_sid(inode, &name->osid);
+       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
- * @inode: inode being audited
+ * @dentry: dentry being audited
  *
  * Called from fs/namei.c:path_lookup().
  */
-void __audit_inode(const char *name, const struct inode *inode)
+void __audit_inode(const char *name, const struct dentry *dentry)
 {
        int idx;
        struct audit_context *context = current->audit_context;
+       const struct inode *inode = dentry->d_inode;
 
        if (!context->in_syscall)
                return;
@@ -1337,21 +1897,19 @@ void __audit_inode(const char *name, const struct inode *inode)
        else {
                /* FIXME: how much do we care about inodes that have no
                 * associated name? */
-               if (context->name_count >= AUDIT_NAMES - AUDIT_NAMES_RESERVED)
+               if (audit_inc_name_count(context, inode))
                        return;
-               idx = context->name_count++;
+               idx = context->name_count - 1;
                context->names[idx].name = NULL;
-#if AUDIT_DEBUG
-               ++context->ino_count;
-#endif
        }
-       audit_copy_inode(&context->names[idx], inode);
+       handle_path(dentry);
+       audit_copy_inode(&context->names[idx], dentry, inode);
 }
 
 /**
  * audit_inode_child - collect inode info for created/removed objects
  * @dname: inode's dentry name
- * @inode: inode being audited
+ * @dentry: dentry being audited
  * @parent: inode of dentry parent
  *
  * For syscalls that create or remove filesystem objects, audit_inode
@@ -1362,102 +1920,91 @@ void __audit_inode(const char *name, const struct inode *inode)
  * must be hooked prior, in order to capture the target inode during
  * unsuccessful attempts.
  */
-void __audit_inode_child(const char *dname, const struct inode *inode,
+void __audit_inode_child(const char *dname, const struct dentry *dentry,
                         const struct inode *parent)
 {
        int idx;
        struct audit_context *context = current->audit_context;
-       const char *found_name = NULL;
+       const char *found_parent = NULL, *found_child = NULL;
+       const struct inode *inode = dentry->d_inode;
        int dirlen = 0;
 
        if (!context->in_syscall)
                return;
 
+       if (inode)
+               handle_one(inode);
        /* determine matching parent */
        if (!dname)
-               goto update_context;
-       for (idx = 0; idx < context->name_count; idx++)
-               if (context->names[idx].ino == parent->i_ino) {
-                       const char *name = context->names[idx].name;
+               goto add_names;
 
-                       if (!name)
-                               continue;
+       /* parent is more likely, look for it first */
+       for (idx = 0; idx < context->name_count; idx++) {
+               struct audit_names *n = &context->names[idx];
 
-                       if (audit_compare_dname_path(dname, name, &dirlen) == 0) {
-                               context->names[idx].name_len = dirlen;
-                               found_name = name;
-                               break;
-                       }
+               if (!n->name)
+                       continue;
+
+               if (n->ino == parent->i_ino &&
+                   !audit_compare_dname_path(dname, n->name, &dirlen)) {
+                       n->name_len = dirlen; /* update parent data in place */
+                       found_parent = n->name;
+                       goto add_names;
                }
+       }
 
-update_context:
-       idx = context->name_count;
-       if (context->name_count == AUDIT_NAMES) {
-               printk(KERN_DEBUG "name_count maxed and losing %s\n",
-                       found_name ?: "(null)");
-               return;
+       /* no matching parent, look for matching child */
+       for (idx = 0; idx < context->name_count; idx++) {
+               struct audit_names *n = &context->names[idx];
+
+               if (!n->name)
+                       continue;
+
+               /* strcmp() is the more likely scenario */
+               if (!strcmp(dname, n->name) ||
+                    !audit_compare_dname_path(dname, n->name, &dirlen)) {
+                       if (inode)
+                               audit_copy_inode(n, NULL, inode);
+                       else
+                               n->ino = (unsigned long)-1;
+                       found_child = n->name;
+                       goto add_names;
+               }
        }
-       context->name_count++;
-#if AUDIT_DEBUG
-       context->ino_count++;
-#endif
-       /* Re-use the name belonging to the slot for a matching parent directory.
-        * All names for this context are relinquished in audit_free_names() */
-       context->names[idx].name = found_name;
-       context->names[idx].name_len = AUDIT_NAME_FULL;
-       context->names[idx].name_put = 0;       /* don't call __putname() */
-
-       if (!inode)
-               context->names[idx].ino = (unsigned long)-1;
-       else
-               audit_copy_inode(&context->names[idx], inode);
-
-       /* A parent was not found in audit_names, so copy the inode data for the
-        * provided parent. */
-       if (!found_name) {
-               idx = context->name_count;
-               if (context->name_count == AUDIT_NAMES) {
-                       printk(KERN_DEBUG
-                               "name_count maxed and losing parent inode data: dev=%02x:%02x, inode=%lu",
-                               MAJOR(parent->i_sb->s_dev),
-                               MINOR(parent->i_sb->s_dev),
-                               parent->i_ino);
+
+add_names:
+       if (!found_parent) {
+               if (audit_inc_name_count(context, parent))
                        return;
-               }
-               context->name_count++;
-#if AUDIT_DEBUG
-               context->ino_count++;
-#endif
-               audit_copy_inode(&context->names[idx], parent);
+               idx = context->name_count - 1;
+               context->names[idx].name = NULL;
+               audit_copy_inode(&context->names[idx], NULL, parent);
        }
-}
 
-/**
- * audit_inode_update - update inode info for last collected name
- * @inode: inode being audited
- *
- * When open() is called on an existing object with the O_CREAT flag, the inode
- * data audit initially collects is incorrect.  This additional hook ensures
- * audit has the inode data for the actual object to be opened.
- */
-void __audit_inode_update(const struct inode *inode)
-{
-       struct audit_context *context = current->audit_context;
-       int idx;
+       if (!found_child) {
+               if (audit_inc_name_count(context, inode))
+                       return;
+               idx = context->name_count - 1;
 
-       if (!context->in_syscall || !inode)
-               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) {
+                       context->names[idx].name = found_parent;
+                       context->names[idx].name_len = AUDIT_NAME_FULL;
+                       /* don't call __putname() */
+                       context->names[idx].name_put = 0;
+               } else {
+                       context->names[idx].name = NULL;
+               }
 
-       if (context->name_count == 0) {
-               context->name_count++;
-#if AUDIT_DEBUG
-               context->ino_count++;
-#endif
+               if (inode)
+                       audit_copy_inode(&context->names[idx], NULL, inode);
+               else
+                       context->names[idx].ino = (unsigned long)-1;
        }
-       idx = context->name_count - 1;
-
-       audit_copy_inode(&context->names[idx], inode);
 }
+EXPORT_SYMBOL_GPL(__audit_inode_child);
 
 /**
  * auditsc_get_stamp - get local copies of audit_context values
@@ -1478,6 +2025,9 @@ void auditsc_get_stamp(struct audit_context *ctx,
        ctx->auditable = 1;
 }
 
+/* global counter which is incremented every time something logs in */
+static atomic_t session_id = ATOMIC_INIT(0);
+
 /**
  * audit_set_loginuid - set a task's audit_context loginuid
  * @task: task whose audit context is being modified
@@ -1489,41 +2039,29 @@ void auditsc_get_stamp(struct audit_context *ctx,
  */
 int audit_set_loginuid(struct task_struct *task, uid_t loginuid)
 {
+       unsigned int sessionid = atomic_inc_return(&session_id);
        struct audit_context *context = task->audit_context;
 
-       if (context) {
-               /* Only log if audit is enabled */
-               if (context->in_syscall) {
-                       struct audit_buffer *ab;
-
-                       ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN);
-                       if (ab) {
-                               audit_log_format(ab, "login pid=%d uid=%u "
-                                       "old auid=%u new auid=%u",
-                                       task->pid, task->uid,
-                                       context->loginuid, loginuid);
-                               audit_log_end(ab);
-                       }
+       if (context && context->in_syscall) {
+               struct audit_buffer *ab;
+
+               ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN);
+               if (ab) {
+                       audit_log_format(ab, "login pid=%d uid=%u "
+                               "old auid=%u new auid=%u"
+                               " old ses=%u new ses=%u",
+                               task->pid, task->uid,
+                               task->loginuid, loginuid,
+                               task->sessionid, sessionid);
+                       audit_log_end(ab);
                }
-               context->loginuid = loginuid;
        }
+       task->sessionid = sessionid;
+       task->loginuid = loginuid;
        return 0;
 }
 
 /**
- * audit_get_loginuid - get the loginuid for an audit_context
- * @ctx: the audit_context
- *
- * Returns the context's loginuid or -1 if @ctx is NULL.
- */
-uid_t audit_get_loginuid(struct audit_context *ctx)
-{
-       return ctx ? ctx->loginuid : -1;
-}
-
-EXPORT_SYMBOL(audit_get_loginuid);
-
-/**
  * __audit_mq_open - record audit data for a POSIX MQ open
  * @oflag: open flag
  * @mode: mode bits
@@ -1745,8 +2283,7 @@ int __audit_ipc_obj(struct kern_ipc_perm *ipcp)
        ax->uid = ipcp->uid;
        ax->gid = ipcp->gid;
        ax->mode = ipcp->mode;
-       selinux_get_ipc_sid(ipcp, &ax->osid);
-
+       security_ipc_getsecid(ipcp, &ax->osid);
        ax->d.type = AUDIT_IPC;
        ax->d.next = context->aux;
        context->aux = (void *)ax;
@@ -1786,28 +2323,17 @@ int audit_bprm(struct linux_binprm *bprm)
 {
        struct audit_aux_data_execve *ax;
        struct audit_context *context = current->audit_context;
-       unsigned long p, next;
-       void *to;
 
        if (likely(!audit_enabled || !context || context->dummy))
                return 0;
 
-       ax = kmalloc(sizeof(*ax) + PAGE_SIZE * MAX_ARG_PAGES - bprm->p,
-                               GFP_KERNEL);
+       ax = kmalloc(sizeof(*ax), GFP_KERNEL);
        if (!ax)
                return -ENOMEM;
 
        ax->argc = bprm->argc;
        ax->envc = bprm->envc;
-       for (p = bprm->p, to = ax->mem; p < MAX_ARG_PAGES*PAGE_SIZE; p = next) {
-               struct page *page = bprm->page[p / PAGE_SIZE];
-               void *kaddr = kmap(page);
-               next = (p + PAGE_SIZE) & ~(PAGE_SIZE - 1);
-               memcpy(to, kaddr + (p & (PAGE_SIZE - 1)), next - p);
-               to += next - p;
-               kunmap(page);
-       }
-
+       ax->mm = bprm->mm;
        ax->d.type = AUDIT_EXECVE;
        ax->d.next = context->aux;
        context->aux = (void *)ax;
@@ -1906,61 +2432,112 @@ void __audit_ptrace(struct task_struct *t)
        struct audit_context *context = current->audit_context;
 
        context->target_pid = t->pid;
-       selinux_get_task_sid(t, &context->target_sid);
+       context->target_auid = audit_get_loginuid(t);
+       context->target_uid = t->uid;
+       context->target_sessionid = audit_get_sessionid(t);
+       security_task_getsecid(t, &context->target_sid);
+       memcpy(context->target_comm, t->comm, TASK_COMM_LEN);
 }
 
 /**
- * audit_avc_path - record the granting or denial of permissions
- * @dentry: dentry to record
- * @mnt: mnt to record
- *
- * Returns 0 for success or NULL context or < 0 on error.
+ * audit_signal_info - record signal info for shutting down audit subsystem
+ * @sig: signal value
+ * @t: task being signaled
  *
- * Called from security/selinux/avc.c::avc_audit()
+ * If the audit subsystem is being terminated, record the task (pid)
+ * and uid that is doing that.
  */
-int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt)
+int __audit_signal_info(int sig, struct task_struct *t)
 {
-       struct audit_aux_data_path *ax;
-       struct audit_context *context = current->audit_context;
+       struct audit_aux_data_pids *axp;
+       struct task_struct *tsk = current;
+       struct audit_context *ctx = tsk->audit_context;
 
-       if (likely(!context))
+       if (audit_pid && t->tgid == audit_pid) {
+               if (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1 || sig == SIGUSR2) {
+                       audit_sig_pid = tsk->pid;
+                       if (tsk->loginuid != -1)
+                               audit_sig_uid = tsk->loginuid;
+                       else
+                               audit_sig_uid = tsk->uid;
+                       security_task_getsecid(tsk, &audit_sig_sid);
+               }
+               if (!audit_signals || audit_dummy_context())
+                       return 0;
+       }
+
+       /* optimize the common case by putting first signal recipient directly
+        * in audit_context */
+       if (!ctx->target_pid) {
+               ctx->target_pid = t->tgid;
+               ctx->target_auid = audit_get_loginuid(t);
+               ctx->target_uid = t->uid;
+               ctx->target_sessionid = audit_get_sessionid(t);
+               security_task_getsecid(t, &ctx->target_sid);
+               memcpy(ctx->target_comm, t->comm, TASK_COMM_LEN);
                return 0;
+       }
 
-       ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
-       if (!ax)
-               return -ENOMEM;
+       axp = (void *)ctx->aux_pids;
+       if (!axp || axp->pid_count == AUDIT_AUX_PIDS) {
+               axp = kzalloc(sizeof(*axp), GFP_ATOMIC);
+               if (!axp)
+                       return -ENOMEM;
 
-       ax->dentry = dget(dentry);
-       ax->mnt = mntget(mnt);
+               axp->d.type = AUDIT_OBJ_PID;
+               axp->d.next = ctx->aux_pids;
+               ctx->aux_pids = (void *)axp;
+       }
+       BUG_ON(axp->pid_count >= AUDIT_AUX_PIDS);
+
+       axp->target_pid[axp->pid_count] = t->tgid;
+       axp->target_auid[axp->pid_count] = audit_get_loginuid(t);
+       axp->target_uid[axp->pid_count] = t->uid;
+       axp->target_sessionid[axp->pid_count] = audit_get_sessionid(t);
+       security_task_getsecid(t, &axp->target_sid[axp->pid_count]);
+       memcpy(axp->target_comm[axp->pid_count], t->comm, TASK_COMM_LEN);
+       axp->pid_count++;
 
-       ax->d.type = AUDIT_AVC_PATH;
-       ax->d.next = context->aux;
-       context->aux = (void *)ax;
        return 0;
 }
 
 /**
- * audit_signal_info - record signal info for shutting down audit subsystem
- * @sig: signal value
- * @t: task being signaled
+ * audit_core_dumps - record information about processes that end abnormally
+ * @signr: signal value
  *
- * If the audit subsystem is being terminated, record the task (pid)
- * and uid that is doing that.
+ * If a process ends with a core dump, something fishy is going on and we
+ * should record the event for investigation.
  */
-void __audit_signal_info(int sig, struct task_struct *t)
+void audit_core_dumps(long signr)
 {
-       extern pid_t audit_sig_pid;
-       extern uid_t audit_sig_uid;
-       extern u32 audit_sig_sid;
-
-       if (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1) {
-               struct task_struct *tsk = current;
-               struct audit_context *ctx = tsk->audit_context;
-               audit_sig_pid = tsk->pid;
-               if (ctx)
-                       audit_sig_uid = ctx->loginuid;
-               else
-                       audit_sig_uid = tsk->uid;
-               selinux_get_task_sid(tsk, &audit_sig_sid);
+       struct audit_buffer *ab;
+       u32 sid;
+       uid_t auid = audit_get_loginuid(current);
+       unsigned int sessionid = audit_get_sessionid(current);
+
+       if (!audit_enabled)
+               return;
+
+       if (signr == SIGQUIT)   /* don't care for those */
+               return;
+
+       ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND);
+       audit_log_format(ab, "auid=%u uid=%u gid=%u ses=%u",
+                       auid, current->uid, current->gid, sessionid);
+       security_task_getsecid(current, &sid);
+       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, " pid=%d comm=", current->pid);
+       audit_log_untrustedstring(ab, current->comm);
+       audit_log_format(ab, " sig=%ld", signr);
+       audit_log_end(ab);
 }