security: pass mount flags to security_sb_kern_mount()
[linux-3.10.git] / security / selinux / hooks.c
index df99869..7465d71 100644 (file)
@@ -156,33 +156,62 @@ static int selinux_secmark_enabled(void)
        return (atomic_read(&selinux_secmark_refcount) > 0);
 }
 
-/* Allocate and free functions for each kind of security blob. */
-
-static int task_alloc_security(struct task_struct *task)
+/*
+ * initialise the security for the init task
+ */
+static void cred_init_security(void)
 {
+       struct cred *cred = (struct cred *) current->real_cred;
        struct task_security_struct *tsec;
 
        tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
        if (!tsec)
-               return -ENOMEM;
+               panic("SELinux:  Failed to initialize initial task.\n");
 
-       tsec->osid = tsec->sid = SECINITSID_UNLABELED;
-       task->security = tsec;
+       tsec->osid = tsec->sid = SECINITSID_KERNEL;
+       cred->security = tsec;
+}
 
-       return 0;
+/*
+ * get the security ID of a set of credentials
+ */
+static inline u32 cred_sid(const struct cred *cred)
+{
+       const struct task_security_struct *tsec;
+
+       tsec = cred->security;
+       return tsec->sid;
 }
 
-static void task_free_security(struct task_struct *task)
+/*
+ * get the objective security ID of a task
+ */
+static inline u32 task_sid(const struct task_struct *task)
 {
-       struct task_security_struct *tsec = task->security;
-       task->security = NULL;
-       kfree(tsec);
+       u32 sid;
+
+       rcu_read_lock();
+       sid = cred_sid(__task_cred(task));
+       rcu_read_unlock();
+       return sid;
+}
+
+/*
+ * get the subjective security ID of the current task
+ */
+static inline u32 current_sid(void)
+{
+       const struct task_security_struct *tsec = current_cred()->security;
+
+       return tsec->sid;
 }
 
+/* Allocate and free functions for each kind of security blob. */
+
 static int inode_alloc_security(struct inode *inode)
 {
-       struct task_security_struct *tsec = current->security;
        struct inode_security_struct *isec;
+       u32 sid = current_sid();
 
        isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
        if (!isec)
@@ -193,7 +222,7 @@ static int inode_alloc_security(struct inode *inode)
        isec->inode = inode;
        isec->sid = SECINITSID_UNLABELED;
        isec->sclass = SECCLASS_FILE;
-       isec->task_sid = tsec->sid;
+       isec->task_sid = sid;
        inode->i_security = isec;
 
        return 0;
@@ -215,15 +244,15 @@ static void inode_free_security(struct inode *inode)
 
 static int file_alloc_security(struct file *file)
 {
-       struct task_security_struct *tsec = current->security;
        struct file_security_struct *fsec;
+       u32 sid = current_sid();
 
        fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL);
        if (!fsec)
                return -ENOMEM;
 
-       fsec->sid = tsec->sid;
-       fsec->fown_sid = tsec->sid;
+       fsec->sid = sid;
+       fsec->fown_sid = sid;
        file->f_security = fsec;
 
        return 0;
@@ -338,8 +367,9 @@ static const match_table_t tokens = {
 
 static int may_context_mount_sb_relabel(u32 sid,
                        struct superblock_security_struct *sbsec,
-                       struct task_security_struct *tsec)
+                       const struct cred *cred)
 {
+       const struct task_security_struct *tsec = cred->security;
        int rc;
 
        rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
@@ -354,8 +384,9 @@ static int may_context_mount_sb_relabel(u32 sid,
 
 static int may_context_mount_inode_relabel(u32 sid,
                        struct superblock_security_struct *sbsec,
-                       struct task_security_struct *tsec)
+                       const struct cred *cred)
 {
+       const struct task_security_struct *tsec = cred->security;
        int rc;
        rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
                          FILESYSTEM__RELABELFROM, NULL);
@@ -553,8 +584,8 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag,
 static int selinux_set_mnt_opts(struct super_block *sb,
                                struct security_mnt_opts *opts)
 {
+       const struct cred *cred = current_cred();
        int rc = 0, i;
-       struct task_security_struct *tsec = current->security;
        struct superblock_security_struct *sbsec = sb->s_security;
        const char *name = sb->s_type->name;
        struct inode *inode = sbsec->sb->s_root->d_inode;
@@ -671,7 +702,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
                sbsec->proc = 1;
 
        /* Determine the labeling behavior to use for this filesystem type. */
-       rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid);
+       rc = security_fs_use(sbsec->proc ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid);
        if (rc) {
                printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
                       __func__, sb->s_type->name, rc);
@@ -680,8 +711,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 
        /* sets the context of the superblock for the fs being mounted. */
        if (fscontext_sid) {
-
-               rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, tsec);
+               rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
                if (rc)
                        goto out;
 
@@ -695,12 +725,14 @@ static int selinux_set_mnt_opts(struct super_block *sb,
         */
        if (context_sid) {
                if (!fscontext_sid) {
-                       rc = may_context_mount_sb_relabel(context_sid, sbsec, tsec);
+                       rc = may_context_mount_sb_relabel(context_sid, sbsec,
+                                                         cred);
                        if (rc)
                                goto out;
                        sbsec->sid = context_sid;
                } else {
-                       rc = may_context_mount_inode_relabel(context_sid, sbsec, tsec);
+                       rc = may_context_mount_inode_relabel(context_sid, sbsec,
+                                                            cred);
                        if (rc)
                                goto out;
                }
@@ -712,7 +744,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
        }
 
        if (rootcontext_sid) {
-               rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec, tsec);
+               rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec,
+                                                    cred);
                if (rc)
                        goto out;
 
@@ -730,7 +763,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 
                if (defcontext_sid != sbsec->def_sid) {
                        rc = may_context_mount_inode_relabel(defcontext_sid,
-                                                            sbsec, tsec);
+                                                            sbsec, cred);
                        if (rc)
                                goto out;
                }
@@ -1345,18 +1378,53 @@ static inline u32 signal_to_av(int sig)
        return perm;
 }
 
-/* Check permission betweeen a pair of tasks, e.g. signal checks,
-   fork check, ptrace check, etc. */
-static int task_has_perm(struct task_struct *tsk1,
-                        struct task_struct *tsk2,
+/*
+ * Check permission between a pair of credentials
+ * fork check, ptrace check, etc.
+ */
+static int cred_has_perm(const struct cred *actor,
+                        const struct cred *target,
                         u32 perms)
 {
-       struct task_security_struct *tsec1, *tsec2;
+       u32 asid = cred_sid(actor), tsid = cred_sid(target);
+
+       return avc_has_perm(asid, tsid, SECCLASS_PROCESS, perms, NULL);
+}
+
+/*
+ * Check permission between a pair of tasks, e.g. signal checks,
+ * fork check, ptrace check, etc.
+ * tsk1 is the actor and tsk2 is the target
+ * - this uses the default subjective creds of tsk1
+ */
+static int task_has_perm(const struct task_struct *tsk1,
+                        const struct task_struct *tsk2,
+                        u32 perms)
+{
+       const struct task_security_struct *__tsec1, *__tsec2;
+       u32 sid1, sid2;
+
+       rcu_read_lock();
+       __tsec1 = __task_cred(tsk1)->security;  sid1 = __tsec1->sid;
+       __tsec2 = __task_cred(tsk2)->security;  sid2 = __tsec2->sid;
+       rcu_read_unlock();
+       return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL);
+}
+
+/*
+ * Check permission between current and another task, e.g. signal checks,
+ * fork check, ptrace check, etc.
+ * current is the actor and tsk2 is the target
+ * - this uses current's subjective creds
+ */
+static int current_has_perm(const struct task_struct *tsk,
+                           u32 perms)
+{
+       u32 sid, tsid;
 
-       tsec1 = tsk1->security;
-       tsec2 = tsk2->security;
-       return avc_has_perm(tsec1->sid, tsec2->sid,
-                           SECCLASS_PROCESS, perms, NULL);
+       sid = current_sid();
+       tsid = task_sid(tsk);
+       return avc_has_perm(sid, tsid, SECCLASS_PROCESS, perms, NULL);
 }
 
 #if CAP_LAST_CAP > 63
@@ -1367,15 +1435,13 @@ static int task_has_perm(struct task_struct *tsk1,
 static int task_has_capability(struct task_struct *tsk,
                               int cap, int audit)
 {
-       struct task_security_struct *tsec;
        struct avc_audit_data ad;
        struct av_decision avd;
        u16 sclass;
+       u32 sid = task_sid(tsk);
        u32 av = CAP_TO_MASK(cap);
        int rc;
 
-       tsec = tsk->security;
-
        AVC_AUDIT_DATA_INIT(&ad, CAP);
        ad.tsk = tsk;
        ad.u.cap = cap;
@@ -1393,9 +1459,9 @@ static int task_has_capability(struct task_struct *tsk,
                BUG();
        }
 
-       rc = avc_has_perm_noaudit(tsec->sid, tsec->sid, sclass, av, 0, &avd);
+       rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
        if (audit == SECURITY_CAP_AUDIT)
-               avc_audit(tsec->sid, tsec->sid, sclass, av, &avd, rc, &ad);
+               avc_audit(sid, sid, sclass, av, &avd, rc, &ad);
        return rc;
 }
 
@@ -1403,30 +1469,28 @@ static int task_has_capability(struct task_struct *tsk,
 static int task_has_system(struct task_struct *tsk,
                           u32 perms)
 {
-       struct task_security_struct *tsec;
-
-       tsec = tsk->security;
+       u32 sid = task_sid(tsk);
 
-       return avc_has_perm(tsec->sid, SECINITSID_KERNEL,
+       return avc_has_perm(sid, SECINITSID_KERNEL,
                            SECCLASS_SYSTEM, perms, NULL);
 }
 
 /* Check whether a task has a particular permission to an inode.
    The 'adp' parameter is optional and allows other audit
    data to be passed (e.g. the dentry). */
-static int inode_has_perm(struct task_struct *tsk,
+static int inode_has_perm(const struct cred *cred,
                          struct inode *inode,
                          u32 perms,
                          struct avc_audit_data *adp)
 {
-       struct task_security_struct *tsec;
        struct inode_security_struct *isec;
        struct avc_audit_data ad;
+       u32 sid;
 
        if (unlikely(IS_PRIVATE(inode)))
                return 0;
 
-       tsec = tsk->security;
+       sid = cred_sid(cred);
        isec = inode->i_security;
 
        if (!adp) {
@@ -1435,23 +1499,24 @@ static int inode_has_perm(struct task_struct *tsk,
                ad.u.fs.inode = inode;
        }
 
-       return avc_has_perm(tsec->sid, isec->sid, isec->sclass, perms, adp);
+       return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp);
 }
 
 /* Same as inode_has_perm, but pass explicit audit data containing
    the dentry to help the auditing code to more easily generate the
    pathname if needed. */
-static inline int dentry_has_perm(struct task_struct *tsk,
+static inline int dentry_has_perm(const struct cred *cred,
                                  struct vfsmount *mnt,
                                  struct dentry *dentry,
                                  u32 av)
 {
        struct inode *inode = dentry->d_inode;
        struct avc_audit_data ad;
+
        AVC_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.mnt = mnt;
        ad.u.fs.path.dentry = dentry;
-       return inode_has_perm(tsk, inode, av, &ad);
+       return inode_has_perm(cred, inode, av, &ad);
 }
 
 /* Check whether a task can use an open file descriptor to
@@ -1462,33 +1527,35 @@ static inline int dentry_has_perm(struct task_struct *tsk,
    has the same SID as the process.  If av is zero, then
    access to the file is not checked, e.g. for cases
    where only the descriptor is affected like seek. */
-static int file_has_perm(struct task_struct *tsk,
-                               struct file *file,
-                               u32 av)
+static int file_has_perm(const struct cred *cred,
+                        struct file *file,
+                        u32 av)
 {
-       struct task_security_struct *tsec = tsk->security;
        struct file_security_struct *fsec = file->f_security;
        struct inode *inode = file->f_path.dentry->d_inode;
        struct avc_audit_data ad;
+       u32 sid = cred_sid(cred);
        int rc;
 
        AVC_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path = file->f_path;
 
-       if (tsec->sid != fsec->sid) {
-               rc = avc_has_perm(tsec->sid, fsec->sid,
+       if (sid != fsec->sid) {
+               rc = avc_has_perm(sid, fsec->sid,
                                  SECCLASS_FD,
                                  FD__USE,
                                  &ad);
                if (rc)
-                       return rc;
+                       goto out;
        }
 
        /* av is zero if only checking access to the descriptor. */
+       rc = 0;
        if (av)
-               return inode_has_perm(tsk, inode, av, &ad);
+               rc = inode_has_perm(cred, inode, av, &ad);
 
-       return 0;
+out:
+       return rc;
 }
 
 /* Check whether a task can create a file. */
@@ -1496,36 +1563,36 @@ static int may_create(struct inode *dir,
                      struct dentry *dentry,
                      u16 tclass)
 {
-       struct task_security_struct *tsec;
+       const struct cred *cred = current_cred();
+       const struct task_security_struct *tsec = cred->security;
        struct inode_security_struct *dsec;
        struct superblock_security_struct *sbsec;
-       u32 newsid;
+       u32 sid, newsid;
        struct avc_audit_data ad;
        int rc;
 
-       tsec = current->security;
        dsec = dir->i_security;
        sbsec = dir->i_sb->s_security;
 
+       sid = tsec->sid;
+       newsid = tsec->create_sid;
+
        AVC_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = dentry;
 
-       rc = avc_has_perm(tsec->sid, dsec->sid, SECCLASS_DIR,
+       rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
                          DIR__ADD_NAME | DIR__SEARCH,
                          &ad);
        if (rc)
                return rc;
 
-       if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
-               newsid = tsec->create_sid;
-       } else {
-               rc = security_transition_sid(tsec->sid, dsec->sid, tclass,
-                                            &newsid);
+       if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
+               rc = security_transition_sid(sid, dsec->sid, tclass, &newsid);
                if (rc)
                        return rc;
        }
 
-       rc = avc_has_perm(tsec->sid, newsid, tclass, FILE__CREATE, &ad);
+       rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad);
        if (rc)
                return rc;
 
@@ -1538,11 +1605,9 @@ static int may_create(struct inode *dir,
 static int may_create_key(u32 ksid,
                          struct task_struct *ctx)
 {
-       struct task_security_struct *tsec;
+       u32 sid = task_sid(ctx);
 
-       tsec = ctx->security;
-
-       return avc_has_perm(tsec->sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
+       return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
 }
 
 #define MAY_LINK       0
@@ -1555,13 +1620,12 @@ static int may_link(struct inode *dir,
                    int kind)
 
 {
-       struct task_security_struct *tsec;
        struct inode_security_struct *dsec, *isec;
        struct avc_audit_data ad;
+       u32 sid = current_sid();
        u32 av;
        int rc;
 
-       tsec = current->security;
        dsec = dir->i_security;
        isec = dentry->d_inode->i_security;
 
@@ -1570,7 +1634,7 @@ static int may_link(struct inode *dir,
 
        av = DIR__SEARCH;
        av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
-       rc = avc_has_perm(tsec->sid, dsec->sid, SECCLASS_DIR, av, &ad);
+       rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad);
        if (rc)
                return rc;
 
@@ -1590,7 +1654,7 @@ static int may_link(struct inode *dir,
                return 0;
        }
 
-       rc = avc_has_perm(tsec->sid, isec->sid, isec->sclass, av, &ad);
+       rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
        return rc;
 }
 
@@ -1599,14 +1663,13 @@ static inline int may_rename(struct inode *old_dir,
                             struct inode *new_dir,
                             struct dentry *new_dentry)
 {
-       struct task_security_struct *tsec;
        struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
        struct avc_audit_data ad;
+       u32 sid = current_sid();
        u32 av;
        int old_is_dir, new_is_dir;
        int rc;
 
-       tsec = current->security;
        old_dsec = old_dir->i_security;
        old_isec = old_dentry->d_inode->i_security;
        old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
@@ -1615,16 +1678,16 @@ static inline int may_rename(struct inode *old_dir,
        AVC_AUDIT_DATA_INIT(&ad, FS);
 
        ad.u.fs.path.dentry = old_dentry;
-       rc = avc_has_perm(tsec->sid, old_dsec->sid, SECCLASS_DIR,
+       rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
                          DIR__REMOVE_NAME | DIR__SEARCH, &ad);
        if (rc)
                return rc;
-       rc = avc_has_perm(tsec->sid, old_isec->sid,
+       rc = avc_has_perm(sid, old_isec->sid,
                          old_isec->sclass, FILE__RENAME, &ad);
        if (rc)
                return rc;
        if (old_is_dir && new_dir != old_dir) {
-               rc = avc_has_perm(tsec->sid, old_isec->sid,
+               rc = avc_has_perm(sid, old_isec->sid,
                                  old_isec->sclass, DIR__REPARENT, &ad);
                if (rc)
                        return rc;
@@ -1634,13 +1697,13 @@ static inline int may_rename(struct inode *old_dir,
        av = DIR__ADD_NAME | DIR__SEARCH;
        if (new_dentry->d_inode)
                av |= DIR__REMOVE_NAME;
-       rc = avc_has_perm(tsec->sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
+       rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
        if (rc)
                return rc;
        if (new_dentry->d_inode) {
                new_isec = new_dentry->d_inode->i_security;
                new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
-               rc = avc_has_perm(tsec->sid, new_isec->sid,
+               rc = avc_has_perm(sid, new_isec->sid,
                                  new_isec->sclass,
                                  (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
                if (rc)
@@ -1651,18 +1714,16 @@ static inline int may_rename(struct inode *old_dir,
 }
 
 /* Check whether a task can perform a filesystem operation. */
-static int superblock_has_perm(struct task_struct *tsk,
+static int superblock_has_perm(const struct cred *cred,
                               struct super_block *sb,
                               u32 perms,
                               struct avc_audit_data *ad)
 {
-       struct task_security_struct *tsec;
        struct superblock_security_struct *sbsec;
+       u32 sid = cred_sid(cred);
 
-       tsec = tsk->security;
        sbsec = sb->s_security;
-       return avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
-                           perms, ad);
+       return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
 }
 
 /* Convert a Linux mode and permission mask to an access vector. */
@@ -1758,13 +1819,12 @@ static int selinux_ptrace_may_access(struct task_struct *child,
                return rc;
 
        if (mode == PTRACE_MODE_READ) {
-               struct task_security_struct *tsec = current->security;
-               struct task_security_struct *csec = child->security;
-               return avc_has_perm(tsec->sid, csec->sid,
-                                   SECCLASS_FILE, FILE__READ, NULL);
+               u32 sid = current_sid();
+               u32 csid = task_sid(child);
+               return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
        }
 
-       return task_has_perm(current, child, PROCESS__PTRACE);
+       return current_has_perm(child, PROCESS__PTRACE);
 }
 
 static int selinux_ptrace_traceme(struct task_struct *parent)
@@ -1783,29 +1843,26 @@ static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
 {
        int error;
 
-       error = task_has_perm(current, target, PROCESS__GETCAP);
+       error = current_has_perm(target, PROCESS__GETCAP);
        if (error)
                return error;
 
        return secondary_ops->capget(target, effective, inheritable, permitted);
 }
 
-static int selinux_capset_check(kernel_cap_t *effective,
-                               kernel_cap_t *inheritable, kernel_cap_t *permitted)
+static int selinux_capset(struct cred *new, const struct cred *old,
+                         const kernel_cap_t *effective,
+                         const kernel_cap_t *inheritable,
+                         const kernel_cap_t *permitted)
 {
        int error;
 
-       error = secondary_ops->capset_check(effective, inheritable, permitted);
+       error = secondary_ops->capset(new, old,
+                                     effective, inheritable, permitted);
        if (error)
                return error;
 
-       return task_has_perm(current, current, PROCESS__SETCAP);
-}
-
-static void selinux_capset_set(kernel_cap_t *effective,
-                              kernel_cap_t *inheritable, kernel_cap_t *permitted)
-{
-       secondary_ops->capset_set(effective, inheritable, permitted);
+       return cred_has_perm(old, new, PROCESS__SETCAP);
 }
 
 static int selinux_capable(struct task_struct *tsk, int cap, int audit)
@@ -1864,15 +1921,14 @@ static int selinux_sysctl(ctl_table *table, int op)
 {
        int error = 0;
        u32 av;
-       struct task_security_struct *tsec;
-       u32 tsid;
+       u32 tsid, sid;
        int rc;
 
        rc = secondary_ops->sysctl(table, op);
        if (rc)
                return rc;
 
-       tsec = current->security;
+       sid = current_sid();
 
        rc = selinux_sysctl_get_sid(table, (op == 0001) ?
                                    SECCLASS_DIR : SECCLASS_FILE, &tsid);
@@ -1884,7 +1940,7 @@ static int selinux_sysctl(ctl_table *table, int op)
        /* The op values are "defined" in sysctl.c, thereby creating
         * a bad coupling between this module and sysctl.c */
        if (op == 001) {
-               error = avc_has_perm(tsec->sid, tsid,
+               error = avc_has_perm(sid, tsid,
                                     SECCLASS_DIR, DIR__SEARCH, NULL);
        } else {
                av = 0;
@@ -1893,7 +1949,7 @@ static int selinux_sysctl(ctl_table *table, int op)
                if (op & 002)
                        av |= FILE__WRITE;
                if (av)
-                       error = avc_has_perm(tsec->sid, tsid,
+                       error = avc_has_perm(sid, tsid,
                                             SECCLASS_FILE, av, NULL);
        }
 
@@ -1902,6 +1958,7 @@ static int selinux_sysctl(ctl_table *table, int op)
 
 static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
 {
+       const struct cred *cred = current_cred();
        int rc = 0;
 
        if (!sb)
@@ -1913,14 +1970,12 @@ static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
        case Q_QUOTAOFF:
        case Q_SETINFO:
        case Q_SETQUOTA:
-               rc = superblock_has_perm(current, sb, FILESYSTEM__QUOTAMOD,
-                                        NULL);
+               rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL);
                break;
        case Q_GETFMT:
        case Q_GETINFO:
        case Q_GETQUOTA:
-               rc = superblock_has_perm(current, sb, FILESYSTEM__QUOTAGET,
-                                        NULL);
+               rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL);
                break;
        default:
                rc = 0;  /* let the kernel handle invalid cmds */
@@ -1931,7 +1986,9 @@ static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
 
 static int selinux_quota_on(struct dentry *dentry)
 {
-       return dentry_has_perm(current, NULL, dentry, FILE__QUOTAON);
+       const struct cred *cred = current_cred();
+
+       return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON);
 }
 
 static int selinux_syslog(int type)
@@ -1989,59 +2046,45 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
 
 /* binprm security operations */
 
-static int selinux_bprm_alloc_security(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)
+static int selinux_bprm_set_creds(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;
        }
@@ -2050,33 +2093,63 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm)
        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;
 }
 
@@ -2085,35 +2158,34 @@ static int selinux_bprm_check_security(struct linux_binprm *bprm)
        return secondary_ops->bprm_check_security(bprm);
 }
 
-
 static int selinux_bprm_secureexec(struct linux_binprm *bprm)
 {
-       struct task_security_struct *tsec = current->security;
+       const struct cred *cred = current_cred();
+       const struct task_security_struct *tsec = cred->security;
+       u32 sid, osid;
        int atsecure = 0;
 
-       if (tsec->osid != tsec->sid) {
+       sid = tsec->sid;
+       osid = tsec->osid;
+
+       if (osid != sid) {
                /* Enable secure mode for SIDs transitions unless
                   the noatsecure permission is granted between
                   the two SIDs, i.e. ahp returns 0. */
-               atsecure = avc_has_perm(tsec->osid, tsec->sid,
-                                        SECCLASS_PROCESS,
-                                        PROCESS__NOATSECURE, NULL);
+               atsecure = avc_has_perm(osid, sid,
+                                       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;
 
 /* Derived from fs/exec.c:flush_old_files. */
-static inline void flush_unauthorized_files(struct files_struct *files)
+static inline void flush_unauthorized_files(const struct cred *cred,
+                                           struct files_struct *files)
 {
        struct avc_audit_data ad;
        struct file *file, *devnull = NULL;
@@ -2135,7 +2207,7 @@ static inline void flush_unauthorized_files(struct files_struct *files)
                           interested in the inode-based check here. */
                        file = list_first_entry(&tty->tty_files, struct file, f_u.fu_list);
                        inode = file->f_path.dentry->d_inode;
-                       if (inode_has_perm(current, inode,
+                       if (inode_has_perm(cred, inode,
                                           FILE__READ | FILE__WRITE, NULL)) {
                                drop_tty = 1;
                        }
@@ -2170,7 +2242,7 @@ static inline void flush_unauthorized_files(struct files_struct *files)
                                file = fget(i);
                                if (!file)
                                        continue;
-                               if (file_has_perm(current,
+                               if (file_has_perm(cred,
                                                  file,
                                                  file_to_av(file))) {
                                        sys_close(i);
@@ -2184,7 +2256,10 @@ static inline void flush_unauthorized_files(struct files_struct *files)
                                        if (devnull) {
                                                get_file(devnull);
                                        } else {
-                                               devnull = dentry_open(dget(selinux_null), mntget(selinuxfs_mount), O_RDWR);
+                                               devnull = dentry_open(
+                                                       dget(selinux_null),
+                                                       mntget(selinuxfs_mount),
+                                                       O_RDWR, cred);
                                                if (IS_ERR(devnull)) {
                                                        devnull = NULL;
                                                        put_unused_fd(fd);
@@ -2203,96 +2278,78 @@ static inline void flush_unauthorized_files(struct files_struct *files)
        spin_unlock(&files->file_lock);
 }
 
-static void 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;
-       u32 sid;
-       int rc;
-
-       secondary_ops->bprm_apply_creds(bprm, unsafe);
-
-       tsec = current->security;
+       struct task_security_struct *new_tsec;
+       struct rlimit *rlim, *initrlim;
+       int rc, i;
 
-       bsec = bprm->security;
-       sid = bsec->sid;
+       secondary_ops->bprm_committing_creds(bprm);
 
-       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;
-                               return;
-                       }
-               }
+       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 = 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;
-                                       return;
-                               }
-                       }
+       /* 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);
        }
 }
 
 /*
- * 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)
 {
-       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(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++)
@@ -2305,32 +2362,8 @@ static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm)
                spin_unlock_irq(&current->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);
@@ -2441,8 +2474,9 @@ out:
        return rc;
 }
 
-static int selinux_sb_kern_mount(struct super_block *sb, void *data)
+static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
 {
+       const struct cred *cred = current_cred();
        struct avc_audit_data ad;
        int rc;
 
@@ -2452,16 +2486,17 @@ static int selinux_sb_kern_mount(struct super_block *sb, void *data)
 
        AVC_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = sb->s_root;
-       return superblock_has_perm(current, sb, FILESYSTEM__MOUNT, &ad);
+       return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
 }
 
 static int selinux_sb_statfs(struct dentry *dentry)
 {
+       const struct cred *cred = current_cred();
        struct avc_audit_data ad;
 
        AVC_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = dentry->d_sb->s_root;
-       return superblock_has_perm(current, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
+       return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
 }
 
 static int selinux_mount(char *dev_name,
@@ -2470,6 +2505,7 @@ static int selinux_mount(char *dev_name,
                         unsigned long flags,
                         void *data)
 {
+       const struct cred *cred = current_cred();
        int rc;
 
        rc = secondary_ops->sb_mount(dev_name, path, type, flags, data);
@@ -2477,22 +2513,23 @@ static int selinux_mount(char *dev_name,
                return rc;
 
        if (flags & MS_REMOUNT)
-               return superblock_has_perm(current, path->mnt->mnt_sb,
+               return superblock_has_perm(cred, path->mnt->mnt_sb,
                                           FILESYSTEM__REMOUNT, NULL);
        else
-               return dentry_has_perm(current, path->mnt, path->dentry,
+               return dentry_has_perm(cred, path->mnt, path->dentry,
                                       FILE__MOUNTON);
 }
 
 static int selinux_umount(struct vfsmount *mnt, int flags)
 {
+       const struct cred *cred = current_cred();
        int rc;
 
        rc = secondary_ops->sb_umount(mnt, flags);
        if (rc)
                return rc;
 
-       return superblock_has_perm(current, mnt->mnt_sb,
+       return superblock_has_perm(cred, mnt->mnt_sb,
                                   FILESYSTEM__UNMOUNT, NULL);
 }
 
@@ -2512,21 +2549,22 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
                                       char **name, void **value,
                                       size_t *len)
 {
-       struct task_security_struct *tsec;
+       const struct cred *cred = current_cred();
+       const struct task_security_struct *tsec = cred->security;
        struct inode_security_struct *dsec;
        struct superblock_security_struct *sbsec;
-       u32 newsid, clen;
+       u32 sid, newsid, clen;
        int rc;
        char *namep = NULL, *context;
 
-       tsec = current->security;
        dsec = dir->i_security;
        sbsec = dir->i_sb->s_security;
 
-       if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
-               newsid = tsec->create_sid;
-       } else {
-               rc = security_transition_sid(tsec->sid, dsec->sid,
+       sid = tsec->sid;
+       newsid = tsec->create_sid;
+
+       if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
+               rc = security_transition_sid(sid, dsec->sid,
                                             inode_mode_to_security_class(inode->i_mode),
                                             &newsid);
                if (rc) {
@@ -2629,21 +2667,25 @@ static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dent
 
 static int selinux_inode_readlink(struct dentry *dentry)
 {
-       return dentry_has_perm(current, NULL, dentry, FILE__READ);
+       const struct cred *cred = current_cred();
+
+       return dentry_has_perm(cred, NULL, dentry, FILE__READ);
 }
 
 static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
 {
+       const struct cred *cred = current_cred();
        int rc;
 
        rc = secondary_ops->inode_follow_link(dentry, nameidata);
        if (rc)
                return rc;
-       return dentry_has_perm(current, NULL, dentry, FILE__READ);
+       return dentry_has_perm(cred, NULL, dentry, FILE__READ);
 }
 
 static int selinux_inode_permission(struct inode *inode, int mask)
 {
+       const struct cred *cred = current_cred();
        int rc;
 
        rc = secondary_ops->inode_permission(inode, mask);
@@ -2655,12 +2697,13 @@ static int selinux_inode_permission(struct inode *inode, int mask)
                return 0;
        }
 
-       return inode_has_perm(current, inode,
+       return inode_has_perm(cred, inode,
                              file_mask_to_av(inode->i_mode, mask), NULL);
 }
 
 static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
 {
+       const struct cred *cred = current_cred();
        int rc;
 
        rc = secondary_ops->inode_setattr(dentry, iattr);
@@ -2672,18 +2715,22 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
 
        if (iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
                               ATTR_ATIME_SET | ATTR_MTIME_SET))
-               return dentry_has_perm(current, NULL, dentry, FILE__SETATTR);
+               return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
 
-       return dentry_has_perm(current, NULL, dentry, FILE__WRITE);
+       return dentry_has_perm(cred, NULL, dentry, FILE__WRITE);
 }
 
 static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
 {
-       return dentry_has_perm(current, mnt, dentry, FILE__GETATTR);
+       const struct cred *cred = current_cred();
+
+       return dentry_has_perm(cred, mnt, dentry, FILE__GETATTR);
 }
 
 static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
 {
+       const struct cred *cred = current_cred();
+
        if (!strncmp(name, XATTR_SECURITY_PREFIX,
                     sizeof XATTR_SECURITY_PREFIX - 1)) {
                if (!strcmp(name, XATTR_NAME_CAPS)) {
@@ -2698,18 +2745,17 @@ static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
 
        /* Not an attribute we recognize, so just check the
           ordinary setattr permission. */
-       return dentry_has_perm(current, NULL, dentry, FILE__SETATTR);
+       return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
 }
 
 static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
                                  const void *value, size_t size, int flags)
 {
-       struct task_security_struct *tsec = current->security;
        struct inode *inode = dentry->d_inode;
        struct inode_security_struct *isec = inode->i_security;
        struct superblock_security_struct *sbsec;
        struct avc_audit_data ad;
-       u32 newsid;
+       u32 newsid, sid = current_sid();
        int rc = 0;
 
        if (strcmp(name, XATTR_NAME_SELINUX))
@@ -2725,7 +2771,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
        AVC_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = dentry;
 
-       rc = avc_has_perm(tsec->sid, isec->sid, isec->sclass,
+       rc = avc_has_perm(sid, isec->sid, isec->sclass,
                          FILE__RELABELFROM, &ad);
        if (rc)
                return rc;
@@ -2739,12 +2785,12 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
        if (rc)
                return rc;
 
-       rc = avc_has_perm(tsec->sid, newsid, isec->sclass,
+       rc = avc_has_perm(sid, newsid, isec->sclass,
                          FILE__RELABELTO, &ad);
        if (rc)
                return rc;
 
-       rc = security_validate_transition(isec->sid, newsid, tsec->sid,
+       rc = security_validate_transition(isec->sid, newsid, sid,
                                          isec->sclass);
        if (rc)
                return rc;
@@ -2784,12 +2830,16 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
 
 static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
 {
-       return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
+       const struct cred *cred = current_cred();
+
+       return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
 }
 
 static int selinux_inode_listxattr(struct dentry *dentry)
 {
-       return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
+       const struct cred *cred = current_cred();
+
+       return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
 }
 
 static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
@@ -2893,6 +2943,7 @@ static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
 
 static int selinux_revalidate_file_permission(struct file *file, int mask)
 {
+       const struct cred *cred = current_cred();
        int rc;
        struct inode *inode = file->f_path.dentry->d_inode;
 
@@ -2905,7 +2956,7 @@ static int selinux_revalidate_file_permission(struct file *file, int mask)
        if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
                mask |= MAY_APPEND;
 
-       rc = file_has_perm(current, file,
+       rc = file_has_perm(cred, file,
                           file_mask_to_av(inode->i_mode, mask));
        if (rc)
                return rc;
@@ -2916,16 +2967,16 @@ static int selinux_revalidate_file_permission(struct file *file, int mask)
 static int selinux_file_permission(struct file *file, int mask)
 {
        struct inode *inode = file->f_path.dentry->d_inode;
-       struct task_security_struct *tsec = current->security;
        struct file_security_struct *fsec = file->f_security;
        struct inode_security_struct *isec = inode->i_security;
+       u32 sid = current_sid();
 
        if (!mask) {
                /* No permission to check.  Existence test. */
                return 0;
        }
 
-       if (tsec->sid == fsec->sid && fsec->isid == isec->sid
+       if (sid == fsec->sid && fsec->isid == isec->sid
            && fsec->pseqno == avc_policy_seqno())
                return selinux_netlbl_inode_permission(inode, mask);
 
@@ -2945,6 +2996,7 @@ static void selinux_file_free_security(struct file *file)
 static int selinux_file_ioctl(struct file *file, unsigned int cmd,
                              unsigned long arg)
 {
+       const struct cred *cred = current_cred();
        u32 av = 0;
 
        if (_IOC_DIR(cmd) & _IOC_WRITE)
@@ -2954,11 +3006,14 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
        if (!av)
                av = FILE__IOCTL;
 
-       return file_has_perm(current, file, av);
+       return file_has_perm(cred, file, av);
 }
 
 static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
 {
+       const struct cred *cred = current_cred();
+       int rc = 0;
+
 #ifndef CONFIG_PPC32
        if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
                /*
@@ -2966,9 +3021,9 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared
                 * private file mapping that will also be writable.
                 * This has an additional check.
                 */
-               int rc = task_has_perm(current, current, PROCESS__EXECMEM);
+               rc = cred_has_perm(cred, cred, PROCESS__EXECMEM);
                if (rc)
-                       return rc;
+                       goto error;
        }
 #endif
 
@@ -2983,9 +3038,11 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared
                if (prot & PROT_EXEC)
                        av |= FILE__EXECUTE;
 
-               return file_has_perm(current, file, av);
+               return file_has_perm(cred, file, av);
        }
-       return 0;
+
+error:
+       return rc;
 }
 
 static int selinux_file_mmap(struct file *file, unsigned long reqprot,
@@ -2993,7 +3050,7 @@ static int selinux_file_mmap(struct file *file, unsigned long reqprot,
                             unsigned long addr, unsigned long addr_only)
 {
        int rc = 0;
-       u32 sid = ((struct task_security_struct *)(current->security))->sid;
+       u32 sid = current_sid();
 
        if (addr < mmap_min_addr)
                rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
@@ -3012,6 +3069,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
                                 unsigned long reqprot,
                                 unsigned long prot)
 {
+       const struct cred *cred = current_cred();
        int rc;
 
        rc = secondary_ops->file_mprotect(vma, reqprot, prot);
@@ -3026,12 +3084,11 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
                rc = 0;
                if (vma->vm_start >= vma->vm_mm->start_brk &&
                    vma->vm_end <= vma->vm_mm->brk) {
-                       rc = task_has_perm(current, current,
-                                          PROCESS__EXECHEAP);
+                       rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
                } else if (!vma->vm_file &&
                           vma->vm_start <= vma->vm_mm->start_stack &&
                           vma->vm_end >= vma->vm_mm->start_stack) {
-                       rc = task_has_perm(current, current, PROCESS__EXECSTACK);
+                       rc = current_has_perm(current, PROCESS__EXECSTACK);
                } else if (vma->vm_file && vma->anon_vma) {
                        /*
                         * We are making executable a file mapping that has
@@ -3040,8 +3097,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
                         * modified content.  This typically should only
                         * occur for text relocations.
                         */
-                       rc = file_has_perm(current, vma->vm_file,
-                                          FILE__EXECMOD);
+                       rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
                }
                if (rc)
                        return rc;
@@ -3053,12 +3109,15 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
 
 static int selinux_file_lock(struct file *file, unsigned int cmd)
 {
-       return file_has_perm(current, file, FILE__LOCK);
+       const struct cred *cred = current_cred();
+
+       return file_has_perm(cred, file, FILE__LOCK);
 }
 
 static int selinux_file_fcntl(struct file *file, unsigned int cmd,
                              unsigned long arg)
 {
+       const struct cred *cred = current_cred();
        int err = 0;
 
        switch (cmd) {
@@ -3069,7 +3128,7 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd,
                }
 
                if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
-                       err = file_has_perm(current, file, FILE__WRITE);
+                       err = file_has_perm(cred, file, FILE__WRITE);
                        break;
                }
                /* fall through */
@@ -3079,7 +3138,7 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd,
        case F_GETOWN:
        case F_GETSIG:
                /* Just check FD__USE permission */
-               err = file_has_perm(current, file, 0);
+               err = file_has_perm(cred, file, 0);
                break;
        case F_GETLK:
        case F_SETLK:
@@ -3093,7 +3152,7 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd,
                        err = -EINVAL;
                        break;
                }
-               err = file_has_perm(current, file, FILE__LOCK);
+               err = file_has_perm(cred, file, FILE__LOCK);
                break;
        }
 
@@ -3102,12 +3161,10 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd,
 
 static int selinux_file_set_fowner(struct file *file)
 {
-       struct task_security_struct *tsec;
        struct file_security_struct *fsec;
 
-       tsec = current->security;
        fsec = file->f_security;
-       fsec->fown_sid = tsec->sid;
+       fsec->fown_sid = current_sid();
 
        return 0;
 }
@@ -3116,14 +3173,13 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk,
                                       struct fown_struct *fown, int signum)
 {
        struct file *file;
+       u32 sid = current_sid();
        u32 perm;
-       struct task_security_struct *tsec;
        struct file_security_struct *fsec;
 
        /* struct fown_struct is never outside the context of a struct file */
        file = container_of(fown, struct file, f_owner);
 
-       tsec = tsk->security;
        fsec = file->f_security;
 
        if (!signum)
@@ -3131,20 +3187,23 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk,
        else
                perm = signal_to_av(signum);
 
-       return avc_has_perm(fsec->fown_sid, tsec->sid,
+       return avc_has_perm(fsec->fown_sid, sid,
                            SECCLASS_PROCESS, perm, NULL);
 }
 
 static int selinux_file_receive(struct file *file)
 {
-       return file_has_perm(current, file, file_to_av(file));
+       const struct cred *cred = current_cred();
+
+       return file_has_perm(cred, file, file_to_av(file));
 }
 
-static int selinux_dentry_open(struct file *file)
+static int selinux_dentry_open(struct file *file, const struct cred *cred)
 {
        struct file_security_struct *fsec;
        struct inode *inode;
        struct inode_security_struct *isec;
+
        inode = file->f_path.dentry->d_inode;
        fsec = file->f_security;
        isec = inode->i_security;
@@ -3165,7 +3224,7 @@ static int selinux_dentry_open(struct file *file)
         * new inode label or new policy.
         * This check is not redundant - do not remove.
         */
-       return inode_has_perm(current, inode, open_file_to_av(file), NULL);
+       return inode_has_perm(cred, inode, open_file_to_av(file), NULL);
 }
 
 /* task security operations */
@@ -3178,36 +3237,88 @@ static int selinux_task_create(unsigned long clone_flags)
        if (rc)
                return rc;
 
-       return task_has_perm(current, current, PROCESS__FORK);
+       return current_has_perm(current, PROCESS__FORK);
+}
+
+/*
+ * detach and free the LSM part of a set of credentials
+ */
+static void selinux_cred_free(struct cred *cred)
+{
+       struct task_security_struct *tsec = cred->security;
+       cred->security = NULL;
+       kfree(tsec);
 }
 
-static int selinux_task_alloc_security(struct task_struct *tsk)
+/*
+ * prepare a new set of credentials for modification
+ */
+static int selinux_cred_prepare(struct cred *new, const struct cred *old,
+                               gfp_t gfp)
 {
-       struct task_security_struct *tsec1, *tsec2;
-       int rc;
+       const struct task_security_struct *old_tsec;
+       struct task_security_struct *tsec;
 
-       tsec1 = current->security;
+       old_tsec = old->security;
 
-       rc = task_alloc_security(tsk);
-       if (rc)
-               return rc;
-       tsec2 = tsk->security;
+       tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
+       if (!tsec)
+               return -ENOMEM;
 
-       tsec2->osid = tsec1->osid;
-       tsec2->sid = tsec1->sid;
+       new->security = tsec;
+       return 0;
+}
 
-       /* Retain the exec, fs, key, and sock SIDs across fork */
-       tsec2->exec_sid = tsec1->exec_sid;
-       tsec2->create_sid = tsec1->create_sid;
-       tsec2->keycreate_sid = tsec1->keycreate_sid;
-       tsec2->sockcreate_sid = tsec1->sockcreate_sid;
+/*
+ * commit new credentials
+ */
+static void selinux_cred_commit(struct cred *new, const struct cred *old)
+{
+       secondary_ops->cred_commit(new, old);
+}
 
-       return 0;
+/*
+ * set the security data for a kernel service
+ * - all the creation contexts are set to unlabelled
+ */
+static int selinux_kernel_act_as(struct cred *new, u32 secid)
+{
+       struct task_security_struct *tsec = new->security;
+       u32 sid = current_sid();
+       int ret;
+
+       ret = avc_has_perm(sid, secid,
+                          SECCLASS_KERNEL_SERVICE,
+                          KERNEL_SERVICE__USE_AS_OVERRIDE,
+                          NULL);
+       if (ret == 0) {
+               tsec->sid = secid;
+               tsec->create_sid = 0;
+               tsec->keycreate_sid = 0;
+               tsec->sockcreate_sid = 0;
+       }
+       return ret;
 }
 
-static void selinux_task_free_security(struct task_struct *tsk)
+/*
+ * set the file creation context in a security record to the same as the
+ * objective context of the specified inode
+ */
+static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
 {
-       task_free_security(tsk);
+       struct inode_security_struct *isec = inode->i_security;
+       struct task_security_struct *tsec = new->security;
+       u32 sid = current_sid();
+       int ret;
+
+       ret = avc_has_perm(sid, isec->sid,
+                          SECCLASS_KERNEL_SERVICE,
+                          KERNEL_SERVICE__CREATE_FILES_AS,
+                          NULL);
+
+       if (ret == 0)
+               tsec->create_sid = isec->sid;
+       return 0;
 }
 
 static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
@@ -3221,9 +3332,10 @@ static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
        return 0;
 }
 
-static int selinux_task_post_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
+static int selinux_task_fix_setuid(struct cred *new, const struct cred *old,
+                                  int flags)
 {
-       return secondary_ops->task_post_setuid(id0, id1, id2, flags);
+       return secondary_ops->task_fix_setuid(new, old, flags);
 }
 
 static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
@@ -3234,23 +3346,22 @@ static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
 
 static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
 {
-       return task_has_perm(current, p, PROCESS__SETPGID);
+       return current_has_perm(p, PROCESS__SETPGID);
 }
 
 static int selinux_task_getpgid(struct task_struct *p)
 {
-       return task_has_perm(current, p, PROCESS__GETPGID);
+       return current_has_perm(p, PROCESS__GETPGID);
 }
 
 static int selinux_task_getsid(struct task_struct *p)
 {
-       return task_has_perm(current, p, PROCESS__GETSESSION);
+       return current_has_perm(p, PROCESS__GETSESSION);
 }
 
 static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
 {
-       struct task_security_struct *tsec = p->security;
-       *secid = tsec->sid;
+       *secid = task_sid(p);
 }
 
 static int selinux_task_setgroups(struct group_info *group_info)
@@ -3267,7 +3378,7 @@ static int selinux_task_setnice(struct task_struct *p, int nice)
        if (rc)
                return rc;
 
-       return task_has_perm(current, p, PROCESS__SETSCHED);
+       return current_has_perm(p, PROCESS__SETSCHED);
 }
 
 static int selinux_task_setioprio(struct task_struct *p, int ioprio)
@@ -3278,12 +3389,12 @@ static int selinux_task_setioprio(struct task_struct *p, int ioprio)
        if (rc)
                return rc;
 
-       return task_has_perm(current, p, PROCESS__SETSCHED);
+       return current_has_perm(p, PROCESS__SETSCHED);
 }
 
 static int selinux_task_getioprio(struct task_struct *p)
 {
-       return task_has_perm(current, p, PROCESS__GETSCHED);
+       return current_has_perm(p, PROCESS__GETSCHED);
 }
 
 static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
@@ -3298,9 +3409,9 @@ static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim
        /* Control the ability to change the hard limit (whether
           lowering or raising it), so that the hard limit can
           later be used as a safe reset point for the soft limit
-          upon context transitions. See selinux_bprm_apply_creds. */
+          upon context transitions.  See selinux_bprm_committing_creds. */
        if (old_rlim->rlim_max != new_rlim->rlim_max)
-               return task_has_perm(current, current, PROCESS__SETRLIMIT);
+               return current_has_perm(current, PROCESS__SETRLIMIT);
 
        return 0;
 }
@@ -3313,17 +3424,17 @@ static int selinux_task_setscheduler(struct task_struct *p, int policy, struct s
        if (rc)
                return rc;
 
-       return task_has_perm(current, p, PROCESS__SETSCHED);
+       return current_has_perm(p, PROCESS__SETSCHED);
 }
 
 static int selinux_task_getscheduler(struct task_struct *p)
 {
-       return task_has_perm(current, p, PROCESS__GETSCHED);
+       return current_has_perm(p, PROCESS__GETSCHED);
 }
 
 static int selinux_task_movememory(struct task_struct *p)
 {
-       return task_has_perm(current, p, PROCESS__SETSCHED);
+       return current_has_perm(p, PROCESS__SETSCHED);
 }
 
 static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
@@ -3331,7 +3442,6 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
 {
        u32 perm;
        int rc;
-       struct task_security_struct *tsec;
 
        rc = secondary_ops->task_kill(p, info, sig, secid);
        if (rc)
@@ -3341,11 +3451,11 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
                perm = PROCESS__SIGNULL; /* null signal; existence test */
        else
                perm = signal_to_av(sig);
-       tsec = p->security;
        if (secid)
-               rc = avc_has_perm(secid, tsec->sid, SECCLASS_PROCESS, perm, NULL);
+               rc = avc_has_perm(secid, task_sid(p),
+                                 SECCLASS_PROCESS, perm, NULL);
        else
-               rc = task_has_perm(current, p, perm);
+               rc = current_has_perm(p, perm);
        return rc;
 }
 
@@ -3353,13 +3463,12 @@ static int selinux_task_prctl(int option,
                              unsigned long arg2,
                              unsigned long arg3,
                              unsigned long arg4,
-                             unsigned long arg5,
-                             long *rc_p)
+                             unsigned long arg5)
 {
        /* The current prctl operations do not appear to require
           any SELinux controls since they merely observe or modify
           the state of the current process. */
-       return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5, rc_p);
+       return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5);
 }
 
 static int selinux_task_wait(struct task_struct *p)
@@ -3367,27 +3476,14 @@ static int selinux_task_wait(struct task_struct *p)
        return task_has_perm(p, current, PROCESS__SIGCHLD);
 }
 
-static void selinux_task_reparent_to_init(struct task_struct *p)
-{
-       struct task_security_struct *tsec;
-
-       secondary_ops->task_reparent_to_init(p);
-
-       tsec = p->security;
-       tsec->osid = tsec->sid;
-       tsec->sid = SECINITSID_KERNEL;
-       return;
-}
-
 static void selinux_task_to_inode(struct task_struct *p,
                                  struct inode *inode)
 {
-       struct task_security_struct *tsec = p->security;
        struct inode_security_struct *isec = inode->i_security;
+       u32 sid = task_sid(p);
 
-       isec->sid = tsec->sid;
+       isec->sid = sid;
        isec->initialized = 1;
-       return;
 }
 
 /* Returns error only if unable to parse addresses */
@@ -3626,19 +3722,19 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock,
                           u32 perms)
 {
        struct inode_security_struct *isec;
-       struct task_security_struct *tsec;
        struct avc_audit_data ad;
+       u32 sid;
        int err = 0;
 
-       tsec = task->security;
        isec = SOCK_INODE(sock)->i_security;
 
        if (isec->sid == SECINITSID_KERNEL)
                goto out;
+       sid = task_sid(task);
 
        AVC_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.sk = sock->sk;
-       err = avc_has_perm(tsec->sid, isec->sid, isec->sclass, perms, &ad);
+       err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
 
 out:
        return err;
@@ -3647,18 +3743,20 @@ out:
 static int selinux_socket_create(int family, int type,
                                 int protocol, int kern)
 {
+       const struct cred *cred = current_cred();
+       const struct task_security_struct *tsec = cred->security;
+       u32 sid, newsid;
+       u16 secclass;
        int err = 0;
-       struct task_security_struct *tsec;
-       u32 newsid;
 
        if (kern)
                goto out;
 
-       tsec = current->security;
-       newsid = tsec->sockcreate_sid ? : tsec->sid;
-       err = avc_has_perm(tsec->sid, newsid,
-                          socket_type_to_security_class(family, type,
-                          protocol), SOCKET__CREATE, NULL);
+       sid = tsec->sid;
+       newsid = tsec->sockcreate_sid ?: sid;
+
+       secclass = socket_type_to_security_class(family, type, protocol);
+       err = avc_has_perm(sid, newsid, secclass, SOCKET__CREATE, NULL);
 
 out:
        return err;
@@ -3667,18 +3765,26 @@ out:
 static int selinux_socket_post_create(struct socket *sock, int family,
                                      int type, int protocol, int kern)
 {
-       int err = 0;
+       const struct cred *cred = current_cred();
+       const struct task_security_struct *tsec = cred->security;
        struct inode_security_struct *isec;
-       struct task_security_struct *tsec;
        struct sk_security_struct *sksec;
-       u32 newsid;
+       u32 sid, newsid;
+       int err = 0;
+
+       sid = tsec->sid;
+       newsid = tsec->sockcreate_sid;
 
        isec = SOCK_INODE(sock)->i_security;
 
-       tsec = current->security;
-       newsid = tsec->sockcreate_sid ? : tsec->sid;
+       if (kern)
+               isec->sid = SECINITSID_KERNEL;
+       else if (newsid)
+               isec->sid = newsid;
+       else
+               isec->sid = sid;
+
        isec->sclass = socket_type_to_security_class(family, type, protocol);
-       isec->sid = kern ? SECINITSID_KERNEL : newsid;
        isec->initialized = 1;
 
        if (sock->sk) {
@@ -3713,7 +3819,6 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
        if (family == PF_INET || family == PF_INET6) {
                char *addrp;
                struct inode_security_struct *isec;
-               struct task_security_struct *tsec;
                struct avc_audit_data ad;
                struct sockaddr_in *addr4 = NULL;
                struct sockaddr_in6 *addr6 = NULL;
@@ -3721,7 +3826,6 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                struct sock *sk = sock->sk;
                u32 sid, node_perm;
 
-               tsec = current->security;
                isec = SOCK_INODE(sock)->i_security;
 
                if (family == PF_INET) {
@@ -4762,15 +4866,16 @@ static int ipc_alloc_security(struct task_struct *task,
                              struct kern_ipc_perm *perm,
                              u16 sclass)
 {
-       struct task_security_struct *tsec = task->security;
        struct ipc_security_struct *isec;
+       u32 sid;
 
        isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
        if (!isec)
                return -ENOMEM;
 
+       sid = task_sid(task);
        isec->sclass = sclass;
-       isec->sid = tsec->sid;
+       isec->sid = sid;
        perm->security = isec;
 
        return 0;
@@ -4808,17 +4913,16 @@ static void msg_msg_free_security(struct msg_msg *msg)
 static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
                        u32 perms)
 {
-       struct task_security_struct *tsec;
        struct ipc_security_struct *isec;
        struct avc_audit_data ad;
+       u32 sid = current_sid();
 
-       tsec = current->security;
        isec = ipc_perms->security;
 
        AVC_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = ipc_perms->key;
 
-       return avc_has_perm(tsec->sid, isec->sid, isec->sclass, perms, &ad);
+       return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
 }
 
 static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
@@ -4834,22 +4938,21 @@ static void selinux_msg_msg_free_security(struct msg_msg *msg)
 /* message queue security operations */
 static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
 {
-       struct task_security_struct *tsec;
        struct ipc_security_struct *isec;
        struct avc_audit_data ad;
+       u32 sid = current_sid();
        int rc;
 
        rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ);
        if (rc)
                return rc;
 
-       tsec = current->security;
        isec = msq->q_perm.security;
 
        AVC_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = msq->q_perm.key;
 
-       rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_MSGQ,
+       rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
                          MSGQ__CREATE, &ad);
        if (rc) {
                ipc_free_security(&msq->q_perm);
@@ -4865,17 +4968,16 @@ static void selinux_msg_queue_free_security(struct msg_queue *msq)
 
 static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
 {
-       struct task_security_struct *tsec;
        struct ipc_security_struct *isec;
        struct avc_audit_data ad;
+       u32 sid = current_sid();
 
-       tsec = current->security;
        isec = msq->q_perm.security;
 
        AVC_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = msq->q_perm.key;
 
-       return avc_has_perm(tsec->sid, isec->sid, SECCLASS_MSGQ,
+       return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
                            MSGQ__ASSOCIATE, &ad);
 }
 
@@ -4909,13 +5011,12 @@ static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
 
 static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg)
 {
-       struct task_security_struct *tsec;
        struct ipc_security_struct *isec;
        struct msg_security_struct *msec;
        struct avc_audit_data ad;
+       u32 sid = current_sid();
        int rc;
 
-       tsec = current->security;
        isec = msq->q_perm.security;
        msec = msg->security;
 
@@ -4927,9 +5028,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
                 * Compute new sid based on current process and
                 * message queue this message will be stored in
                 */
-               rc = security_transition_sid(tsec->sid,
-                                            isec->sid,
-                                            SECCLASS_MSG,
+               rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
                                             &msec->sid);
                if (rc)
                        return rc;
@@ -4939,16 +5038,16 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
        ad.u.ipc_id = msq->q_perm.key;
 
        /* Can this process write to the queue? */
-       rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_MSGQ,
+       rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
                          MSGQ__WRITE, &ad);
        if (!rc)
                /* Can this process send the message */
-               rc = avc_has_perm(tsec->sid, msec->sid,
-                                 SECCLASS_MSG, MSG__SEND, &ad);
+               rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
+                                 MSG__SEND, &ad);
        if (!rc)
                /* Can the message be put in the queue? */
-               rc = avc_has_perm(msec->sid, isec->sid,
-                                 SECCLASS_MSGQ, MSGQ__ENQUEUE, &ad);
+               rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
+                                 MSGQ__ENQUEUE, &ad);
 
        return rc;
 }
@@ -4957,23 +5056,22 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
                                    struct task_struct *target,
                                    long type, int mode)
 {
-       struct task_security_struct *tsec;
        struct ipc_security_struct *isec;
        struct msg_security_struct *msec;
        struct avc_audit_data ad;
+       u32 sid = task_sid(target);
        int rc;
 
-       tsec = target->security;
        isec = msq->q_perm.security;
        msec = msg->security;
 
        AVC_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = msq->q_perm.key;
 
-       rc = avc_has_perm(tsec->sid, isec->sid,
+       rc = avc_has_perm(sid, isec->sid,
                          SECCLASS_MSGQ, MSGQ__READ, &ad);
        if (!rc)
-               rc = avc_has_perm(tsec->sid, msec->sid,
+               rc = avc_has_perm(sid, msec->sid,
                                  SECCLASS_MSG, MSG__RECEIVE, &ad);
        return rc;
 }
@@ -4981,22 +5079,21 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
 /* Shared Memory security operations */
 static int selinux_shm_alloc_security(struct shmid_kernel *shp)
 {
-       struct task_security_struct *tsec;
        struct ipc_security_struct *isec;
        struct avc_audit_data ad;
+       u32 sid = current_sid();
        int rc;
 
        rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM);
        if (rc)
                return rc;
 
-       tsec = current->security;
        isec = shp->shm_perm.security;
 
        AVC_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = shp->shm_perm.key;
 
-       rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_SHM,
+       rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
                          SHM__CREATE, &ad);
        if (rc) {
                ipc_free_security(&shp->shm_perm);
@@ -5012,17 +5109,16 @@ static void selinux_shm_free_security(struct shmid_kernel *shp)
 
 static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
 {
-       struct task_security_struct *tsec;
        struct ipc_security_struct *isec;
        struct avc_audit_data ad;
+       u32 sid = current_sid();
 
-       tsec = current->security;
        isec = shp->shm_perm.security;
 
        AVC_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = shp->shm_perm.key;
 
-       return avc_has_perm(tsec->sid, isec->sid, SECCLASS_SHM,
+       return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
                            SHM__ASSOCIATE, &ad);
 }
 
@@ -5080,22 +5176,21 @@ static int selinux_shm_shmat(struct shmid_kernel *shp,
 /* Semaphore security operations */
 static int selinux_sem_alloc_security(struct sem_array *sma)
 {
-       struct task_security_struct *tsec;
        struct ipc_security_struct *isec;
        struct avc_audit_data ad;
+       u32 sid = current_sid();
        int rc;
 
        rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM);
        if (rc)
                return rc;
 
-       tsec = current->security;
        isec = sma->sem_perm.security;
 
        AVC_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = sma->sem_perm.key;
 
-       rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_SEM,
+       rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
                          SEM__CREATE, &ad);
        if (rc) {
                ipc_free_security(&sma->sem_perm);
@@ -5111,17 +5206,16 @@ static void selinux_sem_free_security(struct sem_array *sma)
 
 static int selinux_sem_associate(struct sem_array *sma, int semflg)
 {
-       struct task_security_struct *tsec;
        struct ipc_security_struct *isec;
        struct avc_audit_data ad;
+       u32 sid = current_sid();
 
-       tsec = current->security;
        isec = sma->sem_perm.security;
 
        AVC_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = sma->sem_perm.key;
 
-       return avc_has_perm(tsec->sid, isec->sid, SECCLASS_SEM,
+       return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
                            SEM__ASSOCIATE, &ad);
 }
 
@@ -5211,33 +5305,35 @@ static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
 static int selinux_getprocattr(struct task_struct *p,
                               char *name, char **value)
 {
-       struct task_security_struct *tsec;
+       const struct task_security_struct *__tsec;
        u32 sid;
        int error;
        unsigned len;
 
        if (current != p) {
-               error = task_has_perm(current, p, PROCESS__GETATTR);
+               error = current_has_perm(p, PROCESS__GETATTR);
                if (error)
                        return error;
        }
 
-       tsec = p->security;
+       rcu_read_lock();
+       __tsec = __task_cred(p)->security;
 
        if (!strcmp(name, "current"))
-               sid = tsec->sid;
+               sid = __tsec->sid;
        else if (!strcmp(name, "prev"))
-               sid = tsec->osid;
+               sid = __tsec->osid;
        else if (!strcmp(name, "exec"))
-               sid = tsec->exec_sid;
+               sid = __tsec->exec_sid;
        else if (!strcmp(name, "fscreate"))
-               sid = tsec->create_sid;
+               sid = __tsec->create_sid;
        else if (!strcmp(name, "keycreate"))
-               sid = tsec->keycreate_sid;
+               sid = __tsec->keycreate_sid;
        else if (!strcmp(name, "sockcreate"))
-               sid = tsec->sockcreate_sid;
+               sid = __tsec->sockcreate_sid;
        else
-               return -EINVAL;
+               goto invalid;
+       rcu_read_unlock();
 
        if (!sid)
                return 0;
@@ -5246,6 +5342,10 @@ static int selinux_getprocattr(struct task_struct *p,
        if (error)
                return error;
        return len;
+
+invalid:
+       rcu_read_unlock();
+       return -EINVAL;
 }
 
 static int selinux_setprocattr(struct task_struct *p,
@@ -5253,7 +5353,8 @@ static int selinux_setprocattr(struct task_struct *p,
 {
        struct task_security_struct *tsec;
        struct task_struct *tracer;
-       u32 sid = 0;
+       struct cred *new;
+       u32 sid = 0, ptsid;
        int error;
        char *str = value;
 
@@ -5269,15 +5370,15 @@ static int selinux_setprocattr(struct task_struct *p,
         * above restriction is ever removed.
         */
        if (!strcmp(name, "exec"))
-               error = task_has_perm(current, p, PROCESS__SETEXEC);
+               error = current_has_perm(p, PROCESS__SETEXEC);
        else if (!strcmp(name, "fscreate"))
-               error = task_has_perm(current, p, PROCESS__SETFSCREATE);
+               error = current_has_perm(p, PROCESS__SETFSCREATE);
        else if (!strcmp(name, "keycreate"))
-               error = task_has_perm(current, p, PROCESS__SETKEYCREATE);
+               error = current_has_perm(p, PROCESS__SETKEYCREATE);
        else if (!strcmp(name, "sockcreate"))
-               error = task_has_perm(current, p, PROCESS__SETSOCKCREATE);
+               error = current_has_perm(p, PROCESS__SETSOCKCREATE);
        else if (!strcmp(name, "current"))
-               error = task_has_perm(current, p, PROCESS__SETCURRENT);
+               error = current_has_perm(p, PROCESS__SETCURRENT);
        else
                error = -EINVAL;
        if (error)
@@ -5300,87 +5401,75 @@ static int selinux_setprocattr(struct task_struct *p,
                        return error;
        }
 
+       new = prepare_creds();
+       if (!new)
+               return -ENOMEM;
+
        /* Permission checking based on the specified context is
           performed during the actual operation (execve,
           open/mkdir/...), when we know the full context of the
-          operation.  See selinux_bprm_set_security for the execve
+          operation.  See selinux_bprm_set_creds for the execve
           checks and may_create for the file creation checks. The
           operation will then fail if the context is not permitted. */
-       tsec = p->security;
-       if (!strcmp(name, "exec"))
+       tsec = new->security;
+       if (!strcmp(name, "exec")) {
                tsec->exec_sid = sid;
-       else if (!strcmp(name, "fscreate"))
+       } else if (!strcmp(name, "fscreate")) {
                tsec->create_sid = sid;
-       else if (!strcmp(name, "keycreate")) {
+       } else if (!strcmp(name, "keycreate")) {
                error = may_create_key(sid, p);
                if (error)
-                       return error;
+                       goto abort_change;
                tsec->keycreate_sid = sid;
-       } else if (!strcmp(name, "sockcreate"))
+       } else if (!strcmp(name, "sockcreate")) {
                tsec->sockcreate_sid = sid;
-       else if (!strcmp(name, "current")) {
-               struct av_decision avd;
-
+       } else if (!strcmp(name, "current")) {
+               error = -EINVAL;
                if (sid == 0)
-                       return -EINVAL;
-               /*
-                * SELinux allows to change context in the following case only.
-                *  - Single threaded processes.
-                *  - Multi threaded processes intend to change its context into
-                *    more restricted domain (defined by TYPEBOUNDS statement).
-                */
-               if (atomic_read(&p->mm->mm_users) != 1) {
-                       struct task_struct *g, *t;
-                       struct mm_struct *mm = p->mm;
-                       read_lock(&tasklist_lock);
-                       do_each_thread(g, t) {
-                               if (t->mm == mm && t != p) {
-                                       read_unlock(&tasklist_lock);
-                                       error = security_bounded_transition(tsec->sid, sid);
-                                       if (!error)
-                                               goto boundary_ok;
-
-                                       return error;
-                               }
-                       } while_each_thread(g, t);
-                       read_unlock(&tasklist_lock);
+                       goto abort_change;
+
+               /* Only allow single threaded processes to change context */
+               error = -EPERM;
+               if (!is_single_threaded(p)) {
+                       error = security_bounded_transition(tsec->sid, sid);
+                       if (error)
+                               goto abort_change;
                }
-boundary_ok:
 
                /* Check permissions for the transition. */
                error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
                                     PROCESS__DYNTRANSITION, NULL);
                if (error)
-                       return error;
+                       goto abort_change;
 
                /* Check for ptracing, and update the task SID if ok.
                   Otherwise, leave SID unchanged and fail. */
+               ptsid = 0;
                task_lock(p);
-               rcu_read_lock();
                tracer = tracehook_tracer_task(p);
-               if (tracer != NULL) {
-                       struct task_security_struct *ptsec = tracer->security;
-                       u32 ptsid = ptsec->sid;
-                       rcu_read_unlock();
-                       error = avc_has_perm_noaudit(ptsid, sid,
-                                                    SECCLASS_PROCESS,
-                                                    PROCESS__PTRACE, 0, &avd);
-                       if (!error)
-                               tsec->sid = sid;
-                       task_unlock(p);
-                       avc_audit(ptsid, sid, SECCLASS_PROCESS,
-                                 PROCESS__PTRACE, &avd, error, NULL);
+               if (tracer)
+                       ptsid = task_sid(tracer);
+               task_unlock(p);
+
+               if (tracer) {
+                       error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
+                                            PROCESS__PTRACE, NULL);
                        if (error)
-                               return error;
-               } else {
-                       rcu_read_unlock();
-                       tsec->sid = sid;
-                       task_unlock(p);
+                               goto abort_change;
                }
-       } else
-               return -EINVAL;
 
+               tsec->sid = sid;
+       } else {
+               error = -EINVAL;
+               goto abort_change;
+       }
+
+       commit_creds(new);
        return size;
+
+abort_change:
+       abort_creds(new);
+       return error;
 }
 
 static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
@@ -5400,22 +5489,23 @@ static void selinux_release_secctx(char *secdata, u32 seclen)
 
 #ifdef CONFIG_KEYS
 
-static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
+static int selinux_key_alloc(struct key *k, const struct cred *cred,
                             unsigned long flags)
 {
-       struct task_security_struct *tsec = tsk->security;
+       const struct task_security_struct *tsec;
        struct key_security_struct *ksec;
 
        ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
        if (!ksec)
                return -ENOMEM;
 
+       tsec = cred->security;
        if (tsec->keycreate_sid)
                ksec->sid = tsec->keycreate_sid;
        else
                ksec->sid = tsec->sid;
-       k->security = ksec;
 
+       k->security = ksec;
        return 0;
 }
 
@@ -5428,17 +5518,12 @@ static void selinux_key_free(struct key *k)
 }
 
 static int selinux_key_permission(key_ref_t key_ref,
-                           struct task_struct *ctx,
-                           key_perm_t perm)
+                                 const struct cred *cred,
+                                 key_perm_t perm)
 {
        struct key *key;
-       struct task_security_struct *tsec;
        struct key_security_struct *ksec;
-
-       key = key_ref_to_ptr(key_ref);
-
-       tsec = ctx->security;
-       ksec = key->security;
+       u32 sid;
 
        /* if no specific permissions are requested, we skip the
           permission check. No serious, additional covert channels
@@ -5446,8 +5531,12 @@ static int selinux_key_permission(key_ref_t key_ref,
        if (perm == 0)
                return 0;
 
-       return avc_has_perm(tsec->sid, ksec->sid,
-                           SECCLASS_KEY, perm, NULL);
+       sid = cred_sid(cred);
+
+       key = key_ref_to_ptr(key_ref);
+       ksec = key->security;
+
+       return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
 }
 
 static int selinux_key_getsecurity(struct key *key, char **_buffer)
@@ -5472,8 +5561,7 @@ static struct security_operations selinux_ops = {
        .ptrace_may_access =            selinux_ptrace_may_access,
        .ptrace_traceme =               selinux_ptrace_traceme,
        .capget =                       selinux_capget,
-       .capset_check =                 selinux_capset_check,
-       .capset_set =                   selinux_capset_set,
+       .capset =                       selinux_capset,
        .sysctl =                       selinux_sysctl,
        .capable =                      selinux_capable,
        .quotactl =                     selinux_quotactl,
@@ -5484,12 +5572,10 @@ static struct security_operations selinux_ops = {
        .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,
@@ -5548,10 +5634,13 @@ static struct security_operations selinux_ops = {
        .dentry_open =                  selinux_dentry_open,
 
        .task_create =                  selinux_task_create,
-       .task_alloc_security =          selinux_task_alloc_security,
-       .task_free_security =           selinux_task_free_security,
+       .cred_free =                    selinux_cred_free,
+       .cred_prepare =                 selinux_cred_prepare,
+       .cred_commit =                  selinux_cred_commit,
+       .kernel_act_as =                selinux_kernel_act_as,
+       .kernel_create_files_as =       selinux_kernel_create_files_as,
        .task_setuid =                  selinux_task_setuid,
-       .task_post_setuid =             selinux_task_post_setuid,
+       .task_fix_setuid =              selinux_task_fix_setuid,
        .task_setgid =                  selinux_task_setgid,
        .task_setpgid =                 selinux_task_setpgid,
        .task_getpgid =                 selinux_task_getpgid,
@@ -5568,7 +5657,6 @@ static struct security_operations selinux_ops = {
        .task_kill =                    selinux_task_kill,
        .task_wait =                    selinux_task_wait,
        .task_prctl =                   selinux_task_prctl,
-       .task_reparent_to_init =        selinux_task_reparent_to_init,
        .task_to_inode =                selinux_task_to_inode,
 
        .ipc_permission =               selinux_ipc_permission,
@@ -5664,8 +5752,6 @@ static struct security_operations selinux_ops = {
 
 static __init int selinux_init(void)
 {
-       struct task_security_struct *tsec;
-
        if (!security_module_enable(&selinux_ops)) {
                selinux_enabled = 0;
                return 0;
@@ -5679,10 +5765,7 @@ static __init int selinux_init(void)
        printk(KERN_INFO "SELinux:  Initializing.\n");
 
        /* Set the security state for the initial task. */
-       if (task_alloc_security(current))
-               panic("SELinux:  Failed to initialize initial task.\n");
-       tsec = current->security;
-       tsec->osid = tsec->sid = SECINITSID_KERNEL;
+       cred_init_security();
 
        sel_inode_cache = kmem_cache_create("selinux_inode_security",
                                            sizeof(struct inode_security_struct),