current->mm->cached_hole_size = 0;
 
        current->mm->mmap = NULL;
-       compute_creds(bprm);
+       install_exec_creds(bprm);
        current->flags &= ~PF_FORKNOEXEC;
 
        if (N_MAGIC(ex) == OMAGIC) {
 
        current->mm->free_area_cache = current->mm->mmap_base;
        current->mm->cached_hole_size = 0;
 
-       compute_creds(bprm);
+       install_exec_creds(bprm);
        current->flags &= ~PF_FORKNOEXEC;
 #ifdef __sparc__
        if (N_MAGIC(ex) == NMAGIC) {
 
        }
 #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */
 
-       compute_creds(bprm);
+       install_exec_creds(bprm);
        current->flags &= ~PF_FORKNOEXEC;
        retval = create_elf_tables(bprm, &loc->elf_ex,
                          load_addr, interp_load_addr);
 
        current->mm->start_stack = current->mm->start_brk + stack_size;
 #endif
 
-       compute_creds(bprm);
+       install_exec_creds(bprm);
        current->flags &= ~PF_FORKNOEXEC;
        if (create_elf_fdpic_tables(bprm, current->mm,
                                    &exec_params, &interp_params) < 0)
 
                                        (libinfo.lib_list[j].loaded)?
                                                libinfo.lib_list[j].start_data:UNLOADED_LIB;
 
-       compute_creds(bprm);
+       install_exec_creds(bprm);
        current->flags &= ~PF_FORKNOEXEC;
 
        set_binfmt(&flat_format);
 
        kfree(hpuxhdr);
 
        set_binfmt(&som_format);
-       compute_creds(bprm);
+       install_exec_creds(bprm);
        setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT);
 
        create_som_tables(bprm);
 
        if (!bprm)
                goto out_ret;
 
+       retval = mutex_lock_interruptible(¤t->cred_exec_mutex);
+       if (retval < 0)
+               goto out_free;
+
+       retval = -ENOMEM;
+       bprm->cred = prepare_exec_creds();
+       if (!bprm->cred)
+               goto out_unlock;
+       check_unsafe_exec(bprm);
+
        file = open_exec(filename);
        retval = PTR_ERR(file);
        if (IS_ERR(file))
-               goto out_kfree;
+               goto out_unlock;
 
        sched_exec();
 
 
        bprm->argc = compat_count(argv, MAX_ARG_STRINGS);
        if ((retval = bprm->argc) < 0)
-               goto out_mm;
+               goto out;
 
        bprm->envc = compat_count(envp, MAX_ARG_STRINGS);
        if ((retval = bprm->envc) < 0)
-               goto out_mm;
-
-       retval = security_bprm_alloc(bprm);
-       if (retval)
                goto out;
 
        retval = prepare_binprm(bprm);
                goto out;
 
        retval = search_binary_handler(bprm, regs);
-       if (retval >= 0) {
-               /* execve success */
-               security_bprm_free(bprm);
-               acct_update_integrals(current);
-               free_bprm(bprm);
-               return retval;
-       }
+       if (retval < 0)
+               goto out;
 
-out:
-       if (bprm->security)
-               security_bprm_free(bprm);
+       /* execve succeeded */
+       mutex_unlock(¤t->cred_exec_mutex);
+       acct_update_integrals(current);
+       free_bprm(bprm);
+       return retval;
 
-out_mm:
+out:
        if (bprm->mm)
                mmput(bprm->mm);
 
                fput(bprm->file);
        }
 
-out_kfree:
+out_unlock:
+       mutex_unlock(¤t->cred_exec_mutex);
+
+out_free:
        free_bprm(bprm);
 
 out_ret:
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 #include <asm/tlb.h>
+#include "internal.h"
 
 #ifdef __alpha__
 /* for /sbin/loader handling in search_binary_handler() */
         */
        current->mm->task_size = TASK_SIZE;
 
-       if (bprm->e_uid != current_euid() ||
-           bprm->e_gid != current_egid()) {
-               set_dumpable(current->mm, suid_dumpable);
+       /* install the new credentials */
+       if (bprm->cred->uid != current_euid() ||
+           bprm->cred->gid != current_egid()) {
                current->pdeath_signal = 0;
        } else if (file_permission(bprm->file, MAY_READ) ||
-                       (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) {
+                  bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP) {
                set_dumpable(current->mm, suid_dumpable);
        }
 
+       current->personality &= ~bprm->per_clear;
+
        /* An exec changes our domain. We are no longer part of the thread
           group */
 
 
 EXPORT_SYMBOL(flush_old_exec);
 
+/*
+ * install the new credentials for this executable
+ */
+void install_exec_creds(struct linux_binprm *bprm)
+{
+       security_bprm_committing_creds(bprm);
+
+       commit_creds(bprm->cred);
+       bprm->cred = NULL;
+
+       /* cred_exec_mutex must be held at least to this point to prevent
+        * ptrace_attach() from altering our determination of the task's
+        * credentials; any time after this it may be unlocked */
+
+       security_bprm_committed_creds(bprm);
+}
+EXPORT_SYMBOL(install_exec_creds);
+
+/*
+ * determine how safe it is to execute the proposed program
+ * - the caller must hold current->cred_exec_mutex to protect against
+ *   PTRACE_ATTACH
+ */
+void check_unsafe_exec(struct linux_binprm *bprm)
+{
+       struct task_struct *p = current;
+
+       bprm->unsafe = tracehook_unsafe_exec(p);
+
+       if (atomic_read(&p->fs->count) > 1 ||
+           atomic_read(&p->files->count) > 1 ||
+           atomic_read(&p->sighand->count) > 1)
+               bprm->unsafe |= LSM_UNSAFE_SHARE;
+}
+
 /* 
  * Fill the binprm structure from the inode. 
  * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes
+ *
+ * This may be called multiple times for binary chains (scripts for example).
  */
 int prepare_binprm(struct linux_binprm *bprm)
 {
-       int mode;
+       umode_t mode;
        struct inode * inode = bprm->file->f_path.dentry->d_inode;
        int retval;
 
        if (bprm->file->f_op == NULL)
                return -EACCES;
 
-       bprm->e_uid = current_euid();
-       bprm->e_gid = current_egid();
+       /* clear any previous set[ug]id data from a previous binary */
+       bprm->cred->euid = current_euid();
+       bprm->cred->egid = current_egid();
 
-       if(!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
+       if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
                /* Set-uid? */
                if (mode & S_ISUID) {
-                       current->personality &= ~PER_CLEAR_ON_SETID;
-                       bprm->e_uid = inode->i_uid;
+                       bprm->per_clear |= PER_CLEAR_ON_SETID;
+                       bprm->cred->euid = inode->i_uid;
                }
 
                /* Set-gid? */
                 * executable.
                 */
                if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
-                       current->personality &= ~PER_CLEAR_ON_SETID;
-                       bprm->e_gid = inode->i_gid;
+                       bprm->per_clear |= PER_CLEAR_ON_SETID;
+                       bprm->cred->egid = inode->i_gid;
                }
        }
 
        /* fill in binprm security blob */
-       retval = security_bprm_set(bprm);
+       retval = security_bprm_set_creds(bprm);
        if (retval)
                return retval;
+       bprm->cred_prepared = 1;
 
-       memset(bprm->buf,0,BINPRM_BUF_SIZE);
-       return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE);
+       memset(bprm->buf, 0, BINPRM_BUF_SIZE);
+       return kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE);
 }
 
 EXPORT_SYMBOL(prepare_binprm);
 
-static int unsafe_exec(struct task_struct *p)
-{
-       int unsafe = tracehook_unsafe_exec(p);
-
-       if (atomic_read(&p->fs->count) > 1 ||
-           atomic_read(&p->files->count) > 1 ||
-           atomic_read(&p->sighand->count) > 1)
-               unsafe |= LSM_UNSAFE_SHARE;
-
-       return unsafe;
-}
-
-void compute_creds(struct linux_binprm *bprm)
-{
-       int unsafe;
-
-       if (bprm->e_uid != current_uid())
-               current->pdeath_signal = 0;
-       exec_keys(current);
-
-       task_lock(current);
-       unsafe = unsafe_exec(current);
-       security_bprm_apply_creds(bprm, unsafe);
-       task_unlock(current);
-       security_bprm_post_apply_creds(bprm);
-}
-EXPORT_SYMBOL(compute_creds);
-
 /*
  * Arguments are '\0' separated strings found at the location bprm->p
  * points to; chop off the first by relocating brpm->p to right after
 void free_bprm(struct linux_binprm *bprm)
 {
        free_arg_pages(bprm);
+       if (bprm->cred)
+               abort_creds(bprm->cred);
        kfree(bprm);
 }
 
        if (!bprm)
                goto out_files;
 
+       retval = mutex_lock_interruptible(¤t->cred_exec_mutex);
+       if (retval < 0)
+               goto out_free;
+
+       retval = -ENOMEM;
+       bprm->cred = prepare_exec_creds();
+       if (!bprm->cred)
+               goto out_unlock;
+       check_unsafe_exec(bprm);
+
        file = open_exec(filename);
        retval = PTR_ERR(file);
        if (IS_ERR(file))
-               goto out_kfree;
+               goto out_unlock;
 
        sched_exec();
 
 
        bprm->argc = count(argv, MAX_ARG_STRINGS);
        if ((retval = bprm->argc) < 0)
-               goto out_mm;
+               goto out;
 
        bprm->envc = count(envp, MAX_ARG_STRINGS);
        if ((retval = bprm->envc) < 0)
-               goto out_mm;
-
-       retval = security_bprm_alloc(bprm);
-       if (retval)
                goto out;
 
        retval = prepare_binprm(bprm);
 
        current->flags &= ~PF_KTHREAD;
        retval = search_binary_handler(bprm,regs);
-       if (retval >= 0) {
-               /* execve success */
-               security_bprm_free(bprm);
-               acct_update_integrals(current);
-               free_bprm(bprm);
-               if (displaced)
-                       put_files_struct(displaced);
-               return retval;
-       }
+       if (retval < 0)
+               goto out;
 
-out:
-       if (bprm->security)
-               security_bprm_free(bprm);
+       /* execve succeeded */
+       mutex_unlock(¤t->cred_exec_mutex);
+       acct_update_integrals(current);
+       free_bprm(bprm);
+       if (displaced)
+               put_files_struct(displaced);
+       return retval;
 
-out_mm:
+out:
        if (bprm->mm)
                mmput (bprm->mm);
 
                allow_write_access(bprm->file);
                fput(bprm->file);
        }
-out_kfree:
+
+out_unlock:
+       mutex_unlock(¤t->cred_exec_mutex);
+
+out_free:
        free_bprm(bprm);
 
 out_files:
 
  */
 
 struct super_block;
+struct linux_binprm;
 
 /*
  * block_dev.c
  */
 extern void __init chrdev_init(void);
 
+/*
+ * exec.c
+ */
+extern void check_unsafe_exec(struct linux_binprm *);
+
 /*
  * namespace.c
  */
 
        return 0;
 }
 
-/*
- * ieieeeeee, an audit function without a return code!
- *
- * This function might fail!  I decided that it didn't matter.  We are too late
- * to fail the syscall and the information isn't REQUIRED for any purpose.  It's
- * just nice to have.  We should be able to look at past audit logs to figure
- * out this process's current cap set along with the fcaps from the PATH record
- * and use that to come up with the final set.  Yeah, its ugly, but all the info
- * is still in the audit log.  So I'm not going to bother mentioning we failed
- * if we couldn't allocate memory.
- *
- * If someone changes their mind they could create the aux record earlier and
- * then search here and use that earlier allocation.  But I don't wanna.
- *
- * -Eric
- */
 static inline int audit_log_bprm_fcaps(struct linux_binprm *bprm,
                                       const struct cred *new,
                                       const struct cred *old)
 
        struct mm_struct *mm;
        unsigned long p; /* current top of mem */
        unsigned int sh_bang:1,
-                    misc_bang:1;
+               misc_bang:1,
+               cred_prepared:1,/* true if creds already prepared (multiple
+                                * preps happen for interpreters) */
+               cap_effective:1;/* true if has elevated effective capabilities,
+                                * false if not; except for init which inherits
+                                * its parent's caps anyway */
 #ifdef __alpha__
        unsigned int taso:1;
 #endif
        unsigned int recursion_depth;
        struct file * file;
-       int e_uid, e_gid;
-       kernel_cap_t cap_post_exec_permitted;
-       bool cap_effective;
-       void *security;
+       struct cred *cred;      /* new credentials */
+       int unsafe;             /* how unsafe this exec is (mask of LSM_UNSAFE_*) */
+       unsigned int per_clear; /* bits to clear in current->personality */
        int argc, envc;
        char * filename;        /* Name of binary as seen by procps */
        char * interp;          /* Name of the binary really executed. Most
                           int executable_stack);
 extern int bprm_mm_init(struct linux_binprm *bprm);
 extern int copy_strings_kernel(int argc,char ** argv,struct linux_binprm *bprm);
-extern void compute_creds(struct linux_binprm *binprm);
+extern void install_exec_creds(struct linux_binprm *bprm);
 extern int do_coredump(long signr, int exit_code, struct pt_regs * regs);
 extern int set_binfmt(struct linux_binfmt *new);
 extern void free_bprm(struct linux_binprm *);
 
        struct key      *process_keyring;       /* keyring private to this process */
        struct rcu_head rcu;                    /* RCU deletion hook */
 };
-
-extern void release_tgcred(struct cred *cred);
 #endif
 
 /*
 extern void __put_cred(struct cred *);
 extern int copy_creds(struct task_struct *, unsigned long);
 extern struct cred *prepare_creds(void);
+extern struct cred *prepare_exec_creds(void);
 extern struct cred *prepare_usermodehelper_creds(void);
 extern int commit_creds(struct cred *);
 extern void abort_creds(struct cred *);
 
  * the userspace interface
  */
 extern int install_thread_keyring_to_cred(struct cred *cred);
-extern int exec_keys(struct task_struct *tsk);
 extern void key_fsuid_changed(struct task_struct *tsk);
 extern void key_fsgid_changed(struct task_struct *tsk);
 extern void key_init(void);
 #define make_key_ref(k, p)             NULL
 #define key_ref_to_ptr(k)              NULL
 #define is_key_possessed(k)            0
-#define exec_keys(t)                   do { } while(0)
 #define key_fsuid_changed(t)           do { } while(0)
 #define key_fsgid_changed(t)           do { } while(0)
 #define key_init()                     do { } while(0)
 
                      const kernel_cap_t *effective,
                      const kernel_cap_t *inheritable,
                      const kernel_cap_t *permitted);
-extern int cap_bprm_set_security(struct linux_binprm *bprm);
-extern int cap_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
+extern int cap_bprm_set_creds(struct linux_binprm *bprm);
 extern int cap_bprm_secureexec(struct linux_binprm *bprm);
 extern int cap_inode_setxattr(struct dentry *dentry, const char *name,
                              const void *value, size_t size, int flags);
 struct sched_param;
 struct request_sock;
 
-/* bprm_apply_creds unsafe reasons */
+/* bprm->unsafe reasons */
 #define LSM_UNSAFE_SHARE       1
 #define LSM_UNSAFE_PTRACE      2
 #define LSM_UNSAFE_PTRACE_CAP  4
  *
  * Security hooks for program execution operations.
  *
- * @bprm_alloc_security:
- *     Allocate and attach a security structure to the @bprm->security field.
- *     The security field is initialized to NULL when the bprm structure is
- *     allocated.
- *     @bprm contains the linux_binprm structure to be modified.
- *     Return 0 if operation was successful.
- * @bprm_free_security:
- *     @bprm contains the linux_binprm structure to be modified.
- *     Deallocate and clear the @bprm->security field.
- * @bprm_apply_creds:
- *     Compute and set the security attributes of a process being transformed
- *     by an execve operation based on the old attributes (current->security)
- *     and the information saved in @bprm->security by the set_security hook.
- *     Since this function may return an error, in which case the process will
- *      be killed.  However, it can leave the security attributes of the
- *     process unchanged if an access failure occurs at this point.
- *     bprm_apply_creds is called under task_lock.  @unsafe indicates various
- *     reasons why it may be unsafe to change security state.
- *     @bprm contains the linux_binprm structure.
- * @bprm_post_apply_creds:
- *     Runs after bprm_apply_creds with the task_lock dropped, so that
- *     functions which cannot be called safely under the task_lock can
- *     be used.  This hook is a good place to perform state changes on
- *     the process such as closing open file descriptors to which access
- *     is no longer granted if the attributes were changed.
- *     Note that a security module might need to save state between
- *     bprm_apply_creds and bprm_post_apply_creds to store the decision
- *     on whether the process may proceed.
- *     @bprm contains the linux_binprm structure.
- * @bprm_set_security:
+ * @bprm_set_creds:
  *     Save security information in the bprm->security field, typically based
  *     on information about the bprm->file, for later use by the apply_creds
  *     hook.  This hook may also optionally check permissions (e.g. for
  *     @bprm contains the linux_binprm structure.
  *     Return 0 if the hook is successful and permission is granted.
  * @bprm_check_security:
- *     This hook mediates the point when a search for a binary handler will
- *     begin.  It allows a check the @bprm->security value which is set in
- *     the preceding set_security call.  The primary difference from
- *     set_security is that the argv list and envp list are reliably
- *     available in @bprm.  This hook may be called multiple times
- *     during a single execve; and in each pass set_security is called
- *     first.
+ *     This hook mediates the point when a search for a binary handler will
+ *     begin.  It allows a check the @bprm->security value which is set in the
+ *     preceding set_creds call.  The primary difference from set_creds is
+ *     that the argv list and envp list are reliably available in @bprm.  This
+ *     hook may be called multiple times during a single execve; and in each
+ *     pass set_creds is called first.
  *     @bprm contains the linux_binprm structure.
  *     Return 0 if the hook is successful and permission is granted.
+ * @bprm_committing_creds:
+ *     Prepare to install the new security attributes of a process being
+ *     transformed by an execve operation, based on the old credentials
+ *     pointed to by @current->cred and the information set in @bprm->cred by
+ *     the bprm_set_creds hook.  @bprm points to the linux_binprm structure.
+ *     This hook is a good place to perform state changes on the process such
+ *     as closing open file descriptors to which access will no longer be
+ *     granted when the attributes are changed.  This is called immediately
+ *     before commit_creds().
+ * @bprm_committed_creds:
+ *     Tidy up after the installation of the new security attributes of a
+ *     process being transformed by an execve operation.  The new credentials
+ *     have, by this point, been set to @current->cred.  @bprm points to the
+ *     linux_binprm structure.  This hook is a good place to perform state
+ *     changes on the process such as clearing out non-inheritable signal
+ *     state.  This is called immediately after commit_creds().
  * @bprm_secureexec:
  *     Return a boolean value (0 or 1) indicating whether a "secure exec"
  *     is required.  The flag is passed in the auxiliary table
        int (*settime) (struct timespec *ts, struct timezone *tz);
        int (*vm_enough_memory) (struct mm_struct *mm, long pages);
 
-       int (*bprm_alloc_security) (struct linux_binprm *bprm);
-       void (*bprm_free_security) (struct linux_binprm *bprm);
-       int (*bprm_apply_creds) (struct linux_binprm *bprm, int unsafe);
-       void (*bprm_post_apply_creds) (struct linux_binprm *bprm);
-       int (*bprm_set_security) (struct linux_binprm *bprm);
+       int (*bprm_set_creds) (struct linux_binprm *bprm);
        int (*bprm_check_security) (struct linux_binprm *bprm);
        int (*bprm_secureexec) (struct linux_binprm *bprm);
+       void (*bprm_committing_creds) (struct linux_binprm *bprm);
+       void (*bprm_committed_creds) (struct linux_binprm *bprm);
 
        int (*sb_alloc_security) (struct super_block *sb);
        void (*sb_free_security) (struct super_block *sb);
 int security_vm_enough_memory(long pages);
 int security_vm_enough_memory_mm(struct mm_struct *mm, long pages);
 int security_vm_enough_memory_kern(long pages);
-int security_bprm_alloc(struct linux_binprm *bprm);
-void security_bprm_free(struct linux_binprm *bprm);
-int security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
-void security_bprm_post_apply_creds(struct linux_binprm *bprm);
-int security_bprm_set(struct linux_binprm *bprm);
+int security_bprm_set_creds(struct linux_binprm *bprm);
 int security_bprm_check(struct linux_binprm *bprm);
+void security_bprm_committing_creds(struct linux_binprm *bprm);
+void security_bprm_committed_creds(struct linux_binprm *bprm);
 int security_bprm_secureexec(struct linux_binprm *bprm);
 int security_sb_alloc(struct super_block *sb);
 void security_sb_free(struct super_block *sb);
        return cap_vm_enough_memory(mm, pages);
 }
 
-static inline int security_bprm_alloc(struct linux_binprm *bprm)
-{
-       return 0;
-}
-
-static inline void security_bprm_free(struct linux_binprm *bprm)
-{ }
-
-static inline int security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
+static inline int security_bprm_set_creds(struct linux_binprm *bprm)
 {
-       return cap_bprm_apply_creds(bprm, unsafe);
+       return cap_bprm_set_creds(bprm);
 }
 
-static inline void security_bprm_post_apply_creds(struct linux_binprm *bprm)
+static inline int security_bprm_check(struct linux_binprm *bprm)
 {
-       return;
+       return 0;
 }
 
-static inline int security_bprm_set(struct linux_binprm *bprm)
+static inline void security_bprm_committing_creds(struct linux_binprm *bprm)
 {
-       return cap_bprm_set_security(bprm);
 }
 
-static inline int security_bprm_check(struct linux_binprm *bprm)
+static inline void security_bprm_committed_creds(struct linux_binprm *bprm)
 {
-       return 0;
 }
 
 static inline int security_bprm_secureexec(struct linux_binprm *bprm)
 
 /*
  * Release a set of thread group credentials.
  */
-void release_tgcred(struct cred *cred)
+static void release_tgcred(struct cred *cred)
 {
 #ifdef CONFIG_KEYS
        struct thread_group_cred *tgcred = cred->tgcred;
 }
 EXPORT_SYMBOL(prepare_creds);
 
+/*
+ * Prepare credentials for current to perform an execve()
+ * - The caller must hold current->cred_exec_mutex
+ */
+struct cred *prepare_exec_creds(void)
+{
+       struct thread_group_cred *tgcred = NULL;
+       struct cred *new;
+
+#ifdef CONFIG_KEYS
+       tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
+       if (!tgcred)
+               return NULL;
+#endif
+
+       new = prepare_creds();
+       if (!new) {
+               kfree(tgcred);
+               return new;
+       }
+
+#ifdef CONFIG_KEYS
+       /* newly exec'd tasks don't get a thread keyring */
+       key_put(new->thread_keyring);
+       new->thread_keyring = NULL;
+
+       /* create a new per-thread-group creds for all this set of threads to
+        * share */
+       memcpy(tgcred, new->tgcred, sizeof(struct thread_group_cred));
+
+       atomic_set(&tgcred->usage, 1);
+       spin_lock_init(&tgcred->lock);
+
+       /* inherit the session keyring; new process keyring */
+       key_get(tgcred->session_keyring);
+       tgcred->process_keyring = NULL;
+
+       release_tgcred(new);
+       new->tgcred = tgcred;
+#endif
+
+       return new;
+}
+
 /*
  * prepare new credentials for the usermode helper dispatcher
  */
 
        return 0;
 }
 
-static int cap_bprm_alloc_security(struct linux_binprm *bprm)
+static int cap_bprm_check_security (struct linux_binprm *bprm)
 {
        return 0;
 }
 
-static void cap_bprm_free_security(struct linux_binprm *bprm)
+static void cap_bprm_committing_creds(struct linux_binprm *bprm)
 {
 }
 
-static void cap_bprm_post_apply_creds(struct linux_binprm *bprm)
+static void cap_bprm_committed_creds(struct linux_binprm *bprm)
 {
 }
 
-static int cap_bprm_check_security(struct linux_binprm *bprm)
-{
-       return 0;
-}
-
 static int cap_sb_alloc_security(struct super_block *sb)
 {
        return 0;
        set_to_cap_if_null(ops, syslog);
        set_to_cap_if_null(ops, settime);
        set_to_cap_if_null(ops, vm_enough_memory);
-       set_to_cap_if_null(ops, bprm_alloc_security);
-       set_to_cap_if_null(ops, bprm_free_security);
-       set_to_cap_if_null(ops, bprm_apply_creds);
-       set_to_cap_if_null(ops, bprm_post_apply_creds);
-       set_to_cap_if_null(ops, bprm_set_security);
+       set_to_cap_if_null(ops, bprm_set_creds);
+       set_to_cap_if_null(ops, bprm_committing_creds);
+       set_to_cap_if_null(ops, bprm_committed_creds);
        set_to_cap_if_null(ops, bprm_check_security);
        set_to_cap_if_null(ops, bprm_secureexec);
        set_to_cap_if_null(ops, sb_alloc_security);
 
 
 static inline void bprm_clear_caps(struct linux_binprm *bprm)
 {
-       cap_clear(bprm->cap_post_exec_permitted);
+       cap_clear(bprm->cred->cap_permitted);
        bprm->cap_effective = false;
 }
 
 }
 
 static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
-                                         struct linux_binprm *bprm)
+                                         struct linux_binprm *bprm,
+                                         bool *effective)
 {
+       struct cred *new = bprm->cred;
        unsigned i;
        int ret = 0;
 
        if (caps->magic_etc & VFS_CAP_FLAGS_EFFECTIVE)
-               bprm->cap_effective = true;
-       else
-               bprm->cap_effective = false;
+               *effective = true;
 
        CAP_FOR_EACH_U32(i) {
                __u32 permitted = caps->permitted.cap[i];
                /*
                 * pP' = (X & fP) | (pI & fI)
                 */
-               bprm->cap_post_exec_permitted.cap[i] =
-                       (current->cred->cap_bset.cap[i] & permitted) |
-                       (current->cred->cap_inheritable.cap[i] & inheritable);
+               new->cap_permitted.cap[i] =
+                       (new->cap_bset.cap[i] & permitted) |
+                       (new->cap_inheritable.cap[i] & inheritable);
 
-               if (permitted & ~bprm->cap_post_exec_permitted.cap[i]) {
-                       /*
-                        * insufficient to execute correctly
-                        */
+               if (permitted & ~new->cap_permitted.cap[i])
+                       /* insufficient to execute correctly */
                        ret = -EPERM;
-               }
        }
 
        /*
         * do not have enough capabilities, we return an error if they are
         * missing some "forced" (aka file-permitted) capabilities.
         */
-       return bprm->cap_effective ? ret : 0;
+       return *effective ? ret : 0;
 }
 
 int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps)
 
        size = inode->i_op->getxattr((struct dentry *)dentry, XATTR_NAME_CAPS, &caps,
                                   XATTR_CAPS_SZ);
-       if (size == -ENODATA || size == -EOPNOTSUPP) {
+       if (size == -ENODATA || size == -EOPNOTSUPP)
                /* no data, that's ok */
                return -ENODATA;
-       }
        if (size < 0)
                return size;
 
 
        cpu_caps->magic_etc = magic_etc = le32_to_cpu(caps.magic_etc);
 
-       switch ((magic_etc & VFS_CAP_REVISION_MASK)) {
+       switch (magic_etc & VFS_CAP_REVISION_MASK) {
        case VFS_CAP_REVISION_1:
                if (size != XATTR_CAPS_SZ_1)
                        return -EINVAL;
                cpu_caps->permitted.cap[i] = le32_to_cpu(caps.data[i].permitted);
                cpu_caps->inheritable.cap[i] = le32_to_cpu(caps.data[i].inheritable);
        }
+
        return 0;
 }
 
 /* Locate any VFS capabilities: */
-static int get_file_caps(struct linux_binprm *bprm)
+static int get_file_caps(struct linux_binprm *bprm, bool *effective)
 {
        struct dentry *dentry;
        int rc = 0;
                goto out;
        }
 
-       rc = bprm_caps_from_vfs_caps(&vcaps, bprm);
+       rc = bprm_caps_from_vfs_caps(&vcaps, bprm, effective);
+       if (rc == -EINVAL)
+               printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
+                      __func__, rc, bprm->filename);
 
 out:
        dput(dentry);
        return 0;
 }
 
-static inline int get_file_caps(struct linux_binprm *bprm)
+static inline int get_file_caps(struct linux_binprm *bprm, bool *effective)
 {
        bprm_clear_caps(bprm);
        return 0;
 }
 #endif
 
-int cap_bprm_set_security (struct linux_binprm *bprm)
+/*
+ * set up the new credentials for an exec'd task
+ */
+int cap_bprm_set_creds(struct linux_binprm *bprm)
 {
+       const struct cred *old = current_cred();
+       struct cred *new = bprm->cred;
+       bool effective;
        int ret;
 
-       ret = get_file_caps(bprm);
+       effective = false;
+       ret = get_file_caps(bprm, &effective);
+       if (ret < 0)
+               return ret;
 
        if (!issecure(SECURE_NOROOT)) {
                /*
                 * executables under compatibility mode, we override the
                 * capability sets for the file.
                 *
-                * If only the real uid is 0, we do not set the effective
-                * bit.
+                * If only the real uid is 0, we do not set the effective bit.
                 */
-               if (bprm->e_uid == 0 || current_uid() == 0) {
+               if (new->euid == 0 || new->uid == 0) {
                        /* pP' = (cap_bset & ~0) | (pI & ~0) */
-                       bprm->cap_post_exec_permitted = cap_combine(
-                               current->cred->cap_bset,
-                               current->cred->cap_inheritable);
-                       bprm->cap_effective = (bprm->e_uid == 0);
-                       ret = 0;
+                       new->cap_permitted = cap_combine(old->cap_bset,
+                                                        old->cap_inheritable);
                }
+               if (new->euid == 0)
+                       effective = true;
        }
 
-       return ret;
-}
-
-int cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
-{
-       const struct cred *old = current_cred();
-       struct cred *new;
-
-       new = prepare_creds();
-       if (!new)
-               return -ENOMEM;
-
-       if (bprm->e_uid != old->uid || bprm->e_gid != old->gid ||
-           !cap_issubset(bprm->cap_post_exec_permitted,
-                         old->cap_permitted)) {
-               set_dumpable(current->mm, suid_dumpable);
-               current->pdeath_signal = 0;
-
-               if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
-                       if (!capable(CAP_SETUID)) {
-                               bprm->e_uid = old->uid;
-                               bprm->e_gid = old->gid;
-                       }
-                       if (cap_limit_ptraced_target()) {
-                               bprm->cap_post_exec_permitted = cap_intersect(
-                                       bprm->cap_post_exec_permitted,
-                                       new->cap_permitted);
-                       }
+       /* Don't let someone trace a set[ug]id/setpcap binary with the revised
+        * credentials unless they have the appropriate permit
+        */
+       if ((new->euid != old->uid ||
+            new->egid != old->gid ||
+            !cap_issubset(new->cap_permitted, old->cap_permitted)) &&
+           bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
+               /* downgrade; they get no more than they had, and maybe less */
+               if (!capable(CAP_SETUID)) {
+                       new->euid = new->uid;
+                       new->egid = new->gid;
                }
+               if (cap_limit_ptraced_target())
+                       new->cap_permitted = cap_intersect(new->cap_permitted,
+                                                          old->cap_permitted);
        }
 
-       new->suid = new->euid = new->fsuid = bprm->e_uid;
-       new->sgid = new->egid = new->fsgid = bprm->e_gid;
+       new->suid = new->fsuid = new->euid;
+       new->sgid = new->fsgid = new->egid;
 
-       /* For init, we want to retain the capabilities set
-        * in the init_task struct. Thus we skip the usual
-        * capability rules */
+       /* For init, we want to retain the capabilities set in the initial
+        * task.  Thus we skip the usual capability rules
+        */
        if (!is_global_init(current)) {
-               new->cap_permitted = bprm->cap_post_exec_permitted;
-               if (bprm->cap_effective)
-                       new->cap_effective = bprm->cap_post_exec_permitted;
+               if (effective)
+                       new->cap_effective = new->cap_permitted;
                else
                        cap_clear(new->cap_effective);
        }
+       bprm->cap_effective = effective;
 
        /*
         * Audit candidate if current->cap_effective is set
         */
        if (!cap_isclear(new->cap_effective)) {
                if (!cap_issubset(CAP_FULL_SET, new->cap_effective) ||
-                   bprm->e_uid != 0 || new->uid != 0 ||
-                   issecure(SECURE_NOROOT))
-                       audit_log_bprm_fcaps(bprm, new, old);
+                   new->euid != 0 || new->uid != 0 ||
+                   issecure(SECURE_NOROOT)) {
+                       ret = audit_log_bprm_fcaps(bprm, new, old);
+                       if (ret < 0)
+                               return ret;
+               }
        }
 
        new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
-       return commit_creds(new);
+       return 0;
 }
 
-int cap_bprm_secureexec (struct linux_binprm *bprm)
+/*
+ * determine whether a secure execution is required
+ * - the creds have been committed at this point, and are no longer available
+ *   through bprm
+ */
+int cap_bprm_secureexec(struct linux_binprm *bprm)
 {
        const struct cred *cred = current_cred();
 
        if (cred->uid != 0) {
                if (bprm->cap_effective)
                        return 1;
-               if (!cap_isclear(bprm->cap_post_exec_permitted))
+               if (!cap_isclear(cred->cap_permitted))
                        return 1;
        }
 
 }
 
 /* moved from kernel/sys.c. */
-/* 
+/*
  * cap_emulate_setxuid() fixes the effective / permitted capabilities of
  * a process after a call to setuid, setreuid, or setresuid.
  *
  *  3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective
  *  capabilities are set to the permitted capabilities.
  *
- *  fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should 
+ *  fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should
  *  never happen.
  *
- *  -astor 
+ *  -astor
  *
  * cevans - New behaviour, Oct '99
  * A process may, via prctl(), elect to keep its capabilities when it
                cap_sys_admin = 1;
        return __vm_enough_memory(mm, pages, cap_sys_admin);
 }
-
 
        return commit_creds(new);
 }
 
-/*****************************************************************************/
-/*
- * deal with execve()
- */
-int exec_keys(struct task_struct *tsk)
-{
-       struct thread_group_cred *tgcred = NULL;
-       struct cred *new;
-
-#ifdef CONFIG_KEYS
-       tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
-       if (!tgcred)
-               return -ENOMEM;
-#endif
-
-       new = prepare_creds();
-       if (new < 0)
-               return -ENOMEM;
-
-       /* newly exec'd tasks don't get a thread keyring */
-       key_put(new->thread_keyring);
-       new->thread_keyring = NULL;
-
-       /* create a new per-thread-group creds for all this set of threads to
-        * share */
-       memcpy(tgcred, new->tgcred, sizeof(struct thread_group_cred));
-
-       atomic_set(&tgcred->usage, 1);
-       spin_lock_init(&tgcred->lock);
-
-       /* inherit the session keyring; new process keyring */
-       key_get(tgcred->session_keyring);
-       tgcred->process_keyring = NULL;
-
-       release_tgcred(new);
-       new->tgcred = tgcred;
-
-       commit_creds(new);
-       return 0;
-
-} /* end exec_keys() */
-
 /*****************************************************************************/
 /*
  * the filesystem user ID changed
 
        struct usb_device *dev;
 
        root_dbg("file %s, e_uid = %d, e_gid = %d\n",
-                bprm->filename, bprm->e_uid, bprm->e_gid);
+                bprm->filename, bprm->cred->euid, bprm->cred->egid);
 
-       if (bprm->e_gid == 0) {
+       if (bprm->cred->egid == 0) {
                dev = usb_find_device(vendor_id, product_id);
                if (!dev) {
                        root_dbg("e_gid = 0, and device not found, "
        .ptrace_may_access =            cap_ptrace_may_access,
        .ptrace_traceme =               cap_ptrace_traceme,
        .capget =                       cap_capget,
-       .capset_check =                 cap_capset_check,
-       .capset_set =                   cap_capset_set,
+       .capset =                       cap_capset,
        .capable =                      cap_capable,
 
-       .bprm_apply_creds =             cap_bprm_apply_creds,
-       .bprm_set_security =            cap_bprm_set_security,
+       .bprm_set_creds =               cap_bprm_set_creds,
 
-       .task_post_setuid =             cap_task_post_setuid,
-       .task_reparent_to_init =        cap_task_reparent_to_init,
+       .task_fix_setuid =              cap_task_fix_setuid,
        .task_prctl =                   cap_task_prctl,
 
        .bprm_check_security =          rootplug_bprm_check_security,
 
        return security_ops->vm_enough_memory(current->mm, pages);
 }
 
-int security_bprm_alloc(struct linux_binprm *bprm)
+int security_bprm_set_creds(struct linux_binprm *bprm)
 {
-       return security_ops->bprm_alloc_security(bprm);
+       return security_ops->bprm_set_creds(bprm);
 }
 
-void security_bprm_free(struct linux_binprm *bprm)
-{
-       security_ops->bprm_free_security(bprm);
-}
-
-int security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
-{
-       return security_ops->bprm_apply_creds(bprm, unsafe);
-}
-
-void security_bprm_post_apply_creds(struct linux_binprm *bprm)
+int security_bprm_check(struct linux_binprm *bprm)
 {
-       security_ops->bprm_post_apply_creds(bprm);
+       return security_ops->bprm_check_security(bprm);
 }
 
-int security_bprm_set(struct linux_binprm *bprm)
+void security_bprm_committing_creds(struct linux_binprm *bprm)
 {
-       return security_ops->bprm_set_security(bprm);
+       return security_ops->bprm_committing_creds(bprm);
 }
 
-int security_bprm_check(struct linux_binprm *bprm)
+void security_bprm_committed_creds(struct linux_binprm *bprm)
 {
-       return security_ops->bprm_check_security(bprm);
+       return security_ops->bprm_committed_creds(bprm);
 }
 
 int security_bprm_secureexec(struct linux_binprm *bprm)
 
 
 /* binprm security operations */
 
-static int selinux_bprm_alloc_security(struct linux_binprm *bprm)
+static int selinux_bprm_set_creds(struct linux_binprm *bprm)
 {
-       struct bprm_security_struct *bsec;
-
-       bsec = kzalloc(sizeof(struct bprm_security_struct), GFP_KERNEL);
-       if (!bsec)
-               return -ENOMEM;
-
-       bsec->sid = SECINITSID_UNLABELED;
-       bsec->set = 0;
-
-       bprm->security = bsec;
-       return 0;
-}
-
-static int selinux_bprm_set_security(struct linux_binprm *bprm)
-{
-       struct task_security_struct *tsec;
-       struct inode *inode = bprm->file->f_path.dentry->d_inode;
+       const struct task_security_struct *old_tsec;
+       struct task_security_struct *new_tsec;
        struct inode_security_struct *isec;
-       struct bprm_security_struct *bsec;
-       u32 newsid;
        struct avc_audit_data ad;
+       struct inode *inode = bprm->file->f_path.dentry->d_inode;
        int rc;
 
-       rc = secondary_ops->bprm_set_security(bprm);
+       rc = secondary_ops->bprm_set_creds(bprm);
        if (rc)
                return rc;
 
-       bsec = bprm->security;
-
-       if (bsec->set)
+       /* SELinux context only depends on initial program or script and not
+        * the script interpreter */
+       if (bprm->cred_prepared)
                return 0;
 
-       tsec = current_security();
+       old_tsec = current_security();
+       new_tsec = bprm->cred->security;
        isec = inode->i_security;
 
        /* Default to the current task SID. */
-       bsec->sid = tsec->sid;
+       new_tsec->sid = old_tsec->sid;
+       new_tsec->osid = old_tsec->sid;
 
        /* Reset fs, key, and sock SIDs on execve. */
-       tsec->create_sid = 0;
-       tsec->keycreate_sid = 0;
-       tsec->sockcreate_sid = 0;
+       new_tsec->create_sid = 0;
+       new_tsec->keycreate_sid = 0;
+       new_tsec->sockcreate_sid = 0;
 
-       if (tsec->exec_sid) {
-               newsid = tsec->exec_sid;
+       if (old_tsec->exec_sid) {
+               new_tsec->sid = old_tsec->exec_sid;
                /* Reset exec SID on execve. */
-               tsec->exec_sid = 0;
+               new_tsec->exec_sid = 0;
        } else {
                /* Check for a default transition on this program. */
-               rc = security_transition_sid(tsec->sid, isec->sid,
-                                            SECCLASS_PROCESS, &newsid);
+               rc = security_transition_sid(old_tsec->sid, isec->sid,
+                                            SECCLASS_PROCESS, &new_tsec->sid);
                if (rc)
                        return rc;
        }
        ad.u.fs.path = bprm->file->f_path;
 
        if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
-               newsid = tsec->sid;
+               new_tsec->sid = old_tsec->sid;
 
-       if (tsec->sid == newsid) {
-               rc = avc_has_perm(tsec->sid, isec->sid,
+       if (new_tsec->sid == old_tsec->sid) {
+               rc = avc_has_perm(old_tsec->sid, isec->sid,
                                  SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
                if (rc)
                        return rc;
        } else {
                /* Check permissions for the transition. */
-               rc = avc_has_perm(tsec->sid, newsid,
+               rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
                                  SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
                if (rc)
                        return rc;
 
-               rc = avc_has_perm(newsid, isec->sid,
+               rc = avc_has_perm(new_tsec->sid, isec->sid,
                                  SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
                if (rc)
                        return rc;
 
-               /* Clear any possibly unsafe personality bits on exec: */
-               current->personality &= ~PER_CLEAR_ON_SETID;
+               /* Check for shared state */
+               if (bprm->unsafe & LSM_UNSAFE_SHARE) {
+                       rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
+                                         SECCLASS_PROCESS, PROCESS__SHARE,
+                                         NULL);
+                       if (rc)
+                               return -EPERM;
+               }
+
+               /* Make sure that anyone attempting to ptrace over a task that
+                * changes its SID has the appropriate permit */
+               if (bprm->unsafe &
+                   (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
+                       struct task_struct *tracer;
+                       struct task_security_struct *sec;
+                       u32 ptsid = 0;
+
+                       rcu_read_lock();
+                       tracer = tracehook_tracer_task(current);
+                       if (likely(tracer != NULL)) {
+                               sec = __task_cred(tracer)->security;
+                               ptsid = sec->sid;
+                       }
+                       rcu_read_unlock();
+
+                       if (ptsid != 0) {
+                               rc = avc_has_perm(ptsid, new_tsec->sid,
+                                                 SECCLASS_PROCESS,
+                                                 PROCESS__PTRACE, NULL);
+                               if (rc)
+                                       return -EPERM;
+                       }
+               }
 
-               /* Set the security field to the new SID. */
-               bsec->sid = newsid;
+               /* Clear any possibly unsafe personality bits on exec: */
+               bprm->per_clear |= PER_CLEAR_ON_SETID;
        }
 
-       bsec->set = 1;
        return 0;
 }
 
        return secondary_ops->bprm_check_security(bprm);
 }
 
-
 static int selinux_bprm_secureexec(struct linux_binprm *bprm)
 {
        const struct cred *cred = current_cred();
                   the noatsecure permission is granted between
                   the two SIDs, i.e. ahp returns 0. */
                atsecure = avc_has_perm(osid, sid,
-                                        SECCLASS_PROCESS,
-                                        PROCESS__NOATSECURE, NULL);
+                                       SECCLASS_PROCESS,
+                                       PROCESS__NOATSECURE, NULL);
        }
 
        return (atsecure || secondary_ops->bprm_secureexec(bprm));
 }
 
-static void selinux_bprm_free_security(struct linux_binprm *bprm)
-{
-       kfree(bprm->security);
-       bprm->security = NULL;
-}
-
 extern struct vfsmount *selinuxfs_mount;
 extern struct dentry *selinux_null;
 
        spin_unlock(&files->file_lock);
 }
 
-static int selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
+/*
+ * Prepare a process for imminent new credential changes due to exec
+ */
+static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
 {
-       struct task_security_struct *tsec;
-       struct bprm_security_struct *bsec;
-       struct cred *new;
-       u32 sid;
-       int rc;
-
-       rc = secondary_ops->bprm_apply_creds(bprm, unsafe);
-       if (rc < 0)
-               return rc;
-
-       new = prepare_creds();
-       if (!new)
-               return -ENOMEM;
+       struct task_security_struct *new_tsec;
+       struct rlimit *rlim, *initrlim;
+       int rc, i;
 
-       tsec = new->security;
+       secondary_ops->bprm_committing_creds(bprm);
 
-       bsec = bprm->security;
-       sid = bsec->sid;
-
-       tsec->osid = tsec->sid;
-       bsec->unsafe = 0;
-       if (tsec->sid != sid) {
-               /* Check for shared state.  If not ok, leave SID
-                  unchanged and kill. */
-               if (unsafe & LSM_UNSAFE_SHARE) {
-                       rc = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
-                                       PROCESS__SHARE, NULL);
-                       if (rc) {
-                               bsec->unsafe = 1;
-                               goto out;
-                       }
-               }
+       new_tsec = bprm->cred->security;
+       if (new_tsec->sid == new_tsec->osid)
+               return;
 
-               /* Check for ptracing, and update the task SID if ok.
-                  Otherwise, leave SID unchanged and kill. */
-               if (unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
-                       struct task_struct *tracer;
-                       struct task_security_struct *sec;
-                       u32 ptsid = 0;
+       /* Close files for which the new task SID is not authorized. */
+       flush_unauthorized_files(bprm->cred, current->files);
 
-                       rcu_read_lock();
-                       tracer = tracehook_tracer_task(current);
-                       if (likely(tracer != NULL)) {
-                               sec = __task_cred(tracer)->security;
-                               ptsid = sec->sid;
-                       }
-                       rcu_read_unlock();
+       /* Always clear parent death signal on SID transitions. */
+       current->pdeath_signal = 0;
 
-                       if (ptsid != 0) {
-                               rc = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
-                                                 PROCESS__PTRACE, NULL);
-                               if (rc) {
-                                       bsec->unsafe = 1;
-                                       goto out;
-                               }
-                       }
+       /* Check whether the new SID can inherit resource limits from the old
+        * SID.  If not, reset all soft limits to the lower of the current
+        * task's hard limit and the init task's soft limit.
+        *
+        * Note that the setting of hard limits (even to lower them) can be
+        * controlled by the setrlimit check.  The inclusion of the init task's
+        * soft limit into the computation is to avoid resetting soft limits
+        * higher than the default soft limit for cases where the default is
+        * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
+        */
+       rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
+                         PROCESS__RLIMITINH, NULL);
+       if (rc) {
+               for (i = 0; i < RLIM_NLIMITS; i++) {
+                       rlim = current->signal->rlim + i;
+                       initrlim = init_task.signal->rlim + i;
+                       rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
                }
-               tsec->sid = sid;
+               update_rlimit_cpu(rlim->rlim_cur);
        }
-
-out:
-       commit_creds(new);
-       return 0;
 }
 
 /*
- * called after apply_creds without the task lock held
+ * Clean up the process immediately after the installation of new credentials
+ * due to exec
  */
-static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm)
+static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
 {
-       const struct cred *cred = current_cred();
-       struct task_security_struct *tsec;
-       struct rlimit *rlim, *initrlim;
+       const struct task_security_struct *tsec = current_security();
        struct itimerval itimer;
-       struct bprm_security_struct *bsec;
        struct sighand_struct *psig;
+       u32 osid, sid;
        int rc, i;
        unsigned long flags;
 
-       tsec = current_security();
-       bsec = bprm->security;
+       secondary_ops->bprm_committed_creds(bprm);
 
-       if (bsec->unsafe) {
-               force_sig_specific(SIGKILL, current);
-               return;
-       }
-       if (tsec->osid == tsec->sid)
+       osid = tsec->osid;
+       sid = tsec->sid;
+
+       if (sid == osid)
                return;
 
-       /* Close files for which the new task SID is not authorized. */
-       flush_unauthorized_files(cred, current->files);
-
-       /* Check whether the new SID can inherit signal state
-          from the old SID.  If not, clear itimers to avoid
-          subsequent signal generation and flush and unblock
-          signals. This must occur _after_ the task SID has
-         been updated so that any kill done after the flush
-         will be checked against the new SID. */
-       rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS,
-                         PROCESS__SIGINH, NULL);
+       /* Check whether the new SID can inherit signal state from the old SID.
+        * If not, clear itimers to avoid subsequent signal generation and
+        * flush and unblock signals.
+        *
+        * This must occur _after_ the task SID has been updated so that any
+        * kill done after the flush will be checked against the new SID.
+        */
+       rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
        if (rc) {
                memset(&itimer, 0, sizeof itimer);
                for (i = 0; i < 3; i++)
                spin_unlock_irq(¤t->sighand->siglock);
        }
 
-       /* Always clear parent death signal on SID transitions. */
-       current->pdeath_signal = 0;
-
-       /* Check whether the new SID can inherit resource limits
-          from the old SID.  If not, reset all soft limits to
-          the lower of the current task's hard limit and the init
-          task's soft limit.  Note that the setting of hard limits
-          (even to lower them) can be controlled by the setrlimit
-          check. The inclusion of the init task's soft limit into
-          the computation is to avoid resetting soft limits higher
-          than the default soft limit for cases where the default
-          is lower than the hard limit, e.g. RLIMIT_CORE or
-          RLIMIT_STACK.*/
-       rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS,
-                         PROCESS__RLIMITINH, NULL);
-       if (rc) {
-               for (i = 0; i < RLIM_NLIMITS; i++) {
-                       rlim = current->signal->rlim + i;
-                       initrlim = init_task.signal->rlim+i;
-                       rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
-               }
-               update_rlimit_cpu(rlim->rlim_cur);
-       }
-
-       /* Wake up the parent if it is waiting so that it can
-          recheck wait permission to the new task SID. */
+       /* Wake up the parent if it is waiting so that it can recheck
+        * wait permission to the new task SID. */
        read_lock_irq(&tasklist_lock);
        psig = current->parent->sighand;
        spin_lock_irqsave(&psig->siglock, flags);
        .netlink_send =                 selinux_netlink_send,
        .netlink_recv =                 selinux_netlink_recv,
 
-       .bprm_alloc_security =          selinux_bprm_alloc_security,
-       .bprm_free_security =           selinux_bprm_free_security,
-       .bprm_apply_creds =             selinux_bprm_apply_creds,
-       .bprm_post_apply_creds =        selinux_bprm_post_apply_creds,
-       .bprm_set_security =            selinux_bprm_set_security,
+       .bprm_set_creds =               selinux_bprm_set_creds,
        .bprm_check_security =          selinux_bprm_check_security,
+       .bprm_committing_creds =        selinux_bprm_committing_creds,
+       .bprm_committed_creds =         selinux_bprm_committed_creds,
        .bprm_secureexec =              selinux_bprm_secureexec,
 
        .sb_alloc_security =            selinux_sb_alloc_security,
 
        u32 sid;        /* SID of IPC resource */
 };
 
-struct bprm_security_struct {
-       u32 sid;                /* SID for transformed process */
-       unsigned char set;
-
-       /*
-        * unsafe is used to share failure information from bprm_apply_creds()
-        * to bprm_post_apply_creds().
-        */
-       char unsafe;
-};
-
 struct netif_security_struct {
        int ifindex;                    /* device index */
        u32 sid;                        /* SID for this interface */
 
        .settime =                      cap_settime,
        .vm_enough_memory =             cap_vm_enough_memory,
 
-       .bprm_apply_creds =             cap_bprm_apply_creds,
-       .bprm_set_security =            cap_bprm_set_security,
+       .bprm_set_creds =               cap_bprm_set_creds,
        .bprm_secureexec =              cap_bprm_secureexec,
 
        .sb_alloc_security =            smack_sb_alloc_security,