Move into the cred struct the part of the task security data that defines how a
task acts upon an object.  The part that defines how something acts upon a task
remains attached to the task.

For SELinux this requires some of task_security_struct to be split off into
cred_security_struct which is then attached to struct cred.  Note that the
contents of cred_security_struct may not be changed without the generation of a
new struct cred.

The split is as follows:

 (*) create_sid, keycreate_sid and sockcreate_sid just move across.

 (*) sid is split into victim_sid - which remains - and action_sid - which
     migrates.

 (*) osid, exec_sid and ptrace_sid remain.

victim_sid is the SID used to govern actions upon the task.  action_sid is used
to govern actions made by the task.

When accessing the cred_security_struct of another process, RCU read procedures
must be observed.

Signed-off-by: David Howells <[EMAIL PROTECTED]>
---

 include/linux/cred.h              |    1 
 include/linux/security.h          |   33 ++
 kernel/cred.c                     |    7 +
 security/dummy.c                  |   11 +
 security/selinux/exports.c        |    6 
 security/selinux/hooks.c          |  497 +++++++++++++++++++++++--------------
 security/selinux/include/objsec.h |   16 +
 security/selinux/selinuxfs.c      |    8 -
 security/selinux/xfrm.c           |    6 
 9 files changed, 379 insertions(+), 206 deletions(-)

diff --git a/include/linux/cred.h b/include/linux/cred.h
index f3d98a8..98d5279 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -26,6 +26,7 @@ struct cred {
        gid_t                   gid;            /* fsgid as was */
        struct rcu_head         exterminate;    /* cred destroyer */
        struct group_info       *group_info;
+       void                    *security;
 
        /* caches for references to the three task keyrings
         * - note that key_ref_t isn't typedef'd at this point, hence the odd
diff --git a/include/linux/security.h b/include/linux/security.h
index 1a15526..74cc204 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -504,6 +504,17 @@ struct request_sock;
  *     @file contains the file structure being received.
  *     Return 0 if permission is granted.
  *
+ * Security hooks for credential structure operations.
+ *
+ * @cred_dup:
+ *     Duplicate the credentials onto a duplicated cred structure.
+ *     @cred points to the credentials structure.  cred->security points to the
+ *     security struct that was attached to the original cred struct, but it
+ *     lacks a reference for the duplication if reference counting is needed.
+ * @cred_destroy:
+ *     Destroy the credentials attached to a cred structure.
+ *     @cred points to the credentials structure that is to be destroyed.
+ *
  * Security hooks for task operations.
  *
  * @task_create:
@@ -1257,6 +1268,9 @@ struct security_operations {
                                    struct fown_struct * fown, int sig);
        int (*file_receive) (struct file * file);
 
+       int (*cred_dup)(struct cred *cred);
+       void (*cred_destroy)(struct cred *cred);
+
        int (*task_create) (unsigned long clone_flags);
        int (*task_alloc_security) (struct task_struct * p);
        void (*task_free_security) (struct task_struct * p);
@@ -1864,6 +1878,16 @@ static inline int security_file_receive (struct file 
*file)
        return security_ops->file_receive (file);
 }
 
+static inline int security_cred_dup(struct cred *cred)
+{
+       return security_ops->cred_dup(cred);
+}
+
+static inline void security_cred_destroy(struct cred *cred)
+{
+       return security_ops->cred_destroy(cred);
+}
+
 static inline int security_task_create (unsigned long clone_flags)
 {
        return security_ops->task_create (clone_flags);
@@ -2546,6 +2570,15 @@ static inline int security_file_receive (struct file 
*file)
        return 0;
 }
 
+static inline int security_cred_dup(struct cred *cred)
+{
+       return 0;
+}
+
+static inline void security_cred_destroy(struct cred *cred)
+{
+}
+
 static inline int security_task_create (unsigned long clone_flags)
 {
        return 0;
diff --git a/kernel/cred.c b/kernel/cred.c
index 4710b60..5b827cb 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -92,6 +92,12 @@ struct cred *dup_cred(const struct cred *pcred)
        if (likely(cred)) {
                *cred = *pcred;
                atomic_set(&cred->usage, 1);
+
+               if (security_cred_dup(cred) < 0) {
+                       kfree(cred);
+                       return NULL;
+               }
+
                get_group_info(cred->group_info);
                key_get(key_ref_to_ptr(cred->session_keyring));
                key_get(key_ref_to_ptr(cred->process_keyring));
@@ -109,6 +115,7 @@ static void put_cred_rcu(struct rcu_head *rcu)
 {
        struct cred *cred = container_of(rcu, struct cred, exterminate);
 
+       security_cred_destroy(cred);
        put_group_info(cred->group_info);
        key_ref_put(cred->session_keyring);
        key_ref_put(cred->process_keyring);
diff --git a/security/dummy.c b/security/dummy.c
index 62de89c..f535cc6 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -468,6 +468,15 @@ static int dummy_file_receive (struct file *file)
        return 0;
 }
 
+static int dummy_cred_dup(struct cred *cred)
+{
+       return 0;
+}
+
+static void dummy_cred_destroy(struct cred *cred)
+{
+}
+
 static int dummy_task_create (unsigned long clone_flags)
 {
        return 0;
@@ -1038,6 +1047,8 @@ void security_fixup_ops (struct security_operations *ops)
        set_to_dummy_if_null(ops, file_set_fowner);
        set_to_dummy_if_null(ops, file_send_sigiotask);
        set_to_dummy_if_null(ops, file_receive);
+       set_to_dummy_if_null(ops, cred_dup);
+       set_to_dummy_if_null(ops, cred_destroy);
        set_to_dummy_if_null(ops, task_create);
        set_to_dummy_if_null(ops, task_alloc_security);
        set_to_dummy_if_null(ops, task_free_security);
diff --git a/security/selinux/exports.c b/security/selinux/exports.c
index b6f9694..29cb87a 100644
--- a/security/selinux/exports.c
+++ b/security/selinux/exports.c
@@ -57,7 +57,7 @@ void selinux_get_task_sid(struct task_struct *tsk, u32 *sid)
 {
        if (selinux_enabled) {
                struct task_security_struct *tsec = tsk->security;
-               *sid = tsec->sid;
+               *sid = tsec->victim_sid;
                return;
        }
        *sid = 0;
@@ -77,9 +77,9 @@ EXPORT_SYMBOL_GPL(selinux_string_to_sid);
 int selinux_relabel_packet_permission(u32 sid)
 {
        if (selinux_enabled) {
-               struct task_security_struct *tsec = current->security;
+               struct cred_security_struct *csec = current->cred->security;
 
-               return avc_has_perm(tsec->sid, sid, SECCLASS_PACKET,
+               return avc_has_perm(csec->action_sid, sid, SECCLASS_PACKET,
                                    PACKET__RELABELTO, NULL);
        }
        return 0;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 0753b20..4e72dbb 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -162,7 +162,8 @@ static int task_alloc_security(struct task_struct *task)
                return -ENOMEM;
 
        tsec->task = task;
-       tsec->osid = tsec->sid = tsec->ptrace_sid = SECINITSID_UNLABELED;
+       tsec->osid = tsec->victim_sid = tsec->ptrace_sid =
+               SECINITSID_UNLABELED;
        task->security = tsec;
 
        return 0;
@@ -177,7 +178,7 @@ static void task_free_security(struct task_struct *task)
 
 static int inode_alloc_security(struct inode *inode)
 {
-       struct task_security_struct *tsec = current->security;
+       struct cred_security_struct *csec = current->cred->security;
        struct inode_security_struct *isec;
 
        isec = kmem_cache_zalloc(sel_inode_cache, GFP_KERNEL);
@@ -189,7 +190,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 = csec->action_sid;
        inode->i_security = isec;
 
        return 0;
@@ -211,7 +212,7 @@ static void inode_free_security(struct inode *inode)
 
 static int file_alloc_security(struct file *file)
 {
-       struct task_security_struct *tsec = current->security;
+       struct cred_security_struct *csec = current->cred->security;
        struct file_security_struct *fsec;
 
        fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL);
@@ -219,8 +220,8 @@ static int file_alloc_security(struct file *file)
                return -ENOMEM;
 
        fsec->file = file;
-       fsec->sid = tsec->sid;
-       fsec->fown_sid = tsec->sid;
+       fsec->sid = csec->action_sid;
+       fsec->fown_sid = csec->action_sid;
        file->f_security = fsec;
 
        return 0;
@@ -335,26 +336,26 @@ static match_table_t tokens = {
 
 static int may_context_mount_sb_relabel(u32 sid,
                        struct superblock_security_struct *sbsec,
-                       struct task_security_struct *tsec)
+                       struct cred_security_struct *csec)
 {
        int rc;
 
-       rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
+       rc = avc_has_perm(csec->action_sid, sbsec->sid, SECCLASS_FILESYSTEM,
                          FILESYSTEM__RELABELFROM, NULL);
        if (rc)
                return rc;
 
-       rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM,
+       rc = avc_has_perm(csec->action_sid, sid, SECCLASS_FILESYSTEM,
                          FILESYSTEM__RELABELTO, NULL);
        return rc;
 }
 
 static int may_context_mount_inode_relabel(u32 sid,
                        struct superblock_security_struct *sbsec,
-                       struct task_security_struct *tsec)
+                       struct cred_security_struct *csec)
 {
        int rc;
-       rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
+       rc = avc_has_perm(csec->action_sid, sbsec->sid, SECCLASS_FILESYSTEM,
                          FILESYSTEM__RELABELFROM, NULL);
        if (rc)
                return rc;
@@ -371,7 +372,7 @@ static int try_context_mount(struct super_block *sb, void 
*data)
        const char *name;
        u32 sid;
        int alloc = 0, rc = 0, seen = 0;
-       struct task_security_struct *tsec = current->security;
+       struct cred_security_struct *csec = current->cred->security;
        struct superblock_security_struct *sbsec = sb->s_security;
 
        if (!data)
@@ -503,7 +504,7 @@ static int try_context_mount(struct super_block *sb, void 
*data)
                        goto out_free;
                }
 
-               rc = may_context_mount_sb_relabel(sid, sbsec, tsec);
+               rc = may_context_mount_sb_relabel(sid, sbsec, csec);
                if (rc)
                        goto out_free;
 
@@ -525,12 +526,12 @@ static int try_context_mount(struct super_block *sb, void 
*data)
                }
 
                if (!fscontext) {
-                       rc = may_context_mount_sb_relabel(sid, sbsec, tsec);
+                       rc = may_context_mount_sb_relabel(sid, sbsec, csec);
                        if (rc)
                                goto out_free;
                        sbsec->sid = sid;
                } else {
-                       rc = may_context_mount_inode_relabel(sid, sbsec, tsec);
+                       rc = may_context_mount_inode_relabel(sid, sbsec, csec);
                        if (rc)
                                goto out_free;
                }
@@ -550,7 +551,7 @@ static int try_context_mount(struct super_block *sb, void 
*data)
                        goto out_free;
                }
 
-               rc = may_context_mount_inode_relabel(sid, sbsec, tsec);
+               rc = may_context_mount_inode_relabel(sid, sbsec, csec);
                if (rc)
                        goto out_free;
 
@@ -570,7 +571,7 @@ static int try_context_mount(struct super_block *sb, void 
*data)
                if (sid == sbsec->def_sid)
                        goto out_free;
 
-               rc = may_context_mount_inode_relabel(sid, sbsec, tsec);
+               rc = may_context_mount_inode_relabel(sid, sbsec, csec);
                if (rc)
                        goto out_free;
 
@@ -1025,15 +1026,22 @@ static inline u32 signal_to_av(int sig)
 
 /* 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,
+static int task_has_perm(struct task_struct *actor,
+                        struct task_struct *victim,
                         u32 perms)
 {
-       struct task_security_struct *tsec1, *tsec2;
+       struct cred_security_struct *csec;
+       struct task_security_struct *tsec;
+       u32 action_sid;
+
+       /* the actor may not be the current task */
+       rcu_read_lock();
+       csec = task_cred(actor)->security;
+       action_sid = csec->action_sid;
+       rcu_read_unlock();
 
-       tsec1 = tsk1->security;
-       tsec2 = tsk2->security;
-       return avc_has_perm(tsec1->sid, tsec2->sid,
+       tsec = victim->security;
+       return avc_has_perm(action_sid, tsec->victim_sid,
                            SECCLASS_PROCESS, perms, NULL);
 }
 
@@ -1041,16 +1049,16 @@ static int task_has_perm(struct task_struct *tsk1,
 static int task_has_capability(struct task_struct *tsk,
                               int cap)
 {
-       struct task_security_struct *tsec;
+       struct cred_security_struct *csec;
        struct avc_audit_data ad;
 
-       tsec = tsk->security;
+       csec = tsk->cred->security;
 
        AVC_AUDIT_DATA_INIT(&ad,CAP);
        ad.tsk = tsk;
        ad.u.cap = cap;
 
-       return avc_has_perm(tsec->sid, tsec->sid,
+       return avc_has_perm(csec->action_sid, csec->action_sid,
                            SECCLASS_CAPABILITY, CAP_TO_MASK(cap), &ad);
 }
 
@@ -1058,11 +1066,11 @@ 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;
+       struct cred_security_struct *csec;
 
-       tsec = tsk->security;
+       csec = tsk->cred->security;
 
-       return avc_has_perm(tsec->sid, SECINITSID_KERNEL,
+       return avc_has_perm(csec->action_sid, SECINITSID_KERNEL,
                            SECCLASS_SYSTEM, perms, NULL);
 }
 
@@ -1074,14 +1082,14 @@ static int inode_has_perm(struct task_struct *tsk,
                          u32 perms,
                          struct avc_audit_data *adp)
 {
-       struct task_security_struct *tsec;
+       struct cred_security_struct *csec;
        struct inode_security_struct *isec;
        struct avc_audit_data ad;
 
        if (unlikely (IS_PRIVATE (inode)))
                return 0;
 
-       tsec = tsk->security;
+       csec = tsk->cred->security;
        isec = inode->i_security;
 
        if (!adp) {
@@ -1090,7 +1098,8 @@ 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(csec->action_sid, isec->sid, isec->sclass, perms,
+                           adp);
 }
 
 /* Same as inode_has_perm, but pass explicit audit data containing
@@ -1121,7 +1130,7 @@ static int file_has_perm(struct task_struct *tsk,
                                struct file *file,
                                u32 av)
 {
-       struct task_security_struct *tsec = tsk->security;
+       struct cred_security_struct *csec = tsk->cred->security;
        struct file_security_struct *fsec = file->f_security;
        struct vfsmount *mnt = file->f_path.mnt;
        struct dentry *dentry = file->f_path.dentry;
@@ -1133,8 +1142,8 @@ static int file_has_perm(struct task_struct *tsk,
        ad.u.fs.mnt = mnt;
        ad.u.fs.dentry = dentry;
 
-       if (tsec->sid != fsec->sid) {
-               rc = avc_has_perm(tsec->sid, fsec->sid,
+       if (csec->action_sid != fsec->sid) {
+               rc = avc_has_perm(csec->action_sid, fsec->sid,
                                  SECCLASS_FD,
                                  FD__USE,
                                  &ad);
@@ -1154,36 +1163,36 @@ static int may_create(struct inode *dir,
                      struct dentry *dentry,
                      u16 tclass)
 {
-       struct task_security_struct *tsec;
+       struct cred_security_struct *csec;
        struct inode_security_struct *dsec;
        struct superblock_security_struct *sbsec;
        u32 newsid;
        struct avc_audit_data ad;
        int rc;
 
-       tsec = current->security;
+       csec = current->cred->security;
        dsec = dir->i_security;
        sbsec = dir->i_sb->s_security;
 
        AVC_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.dentry = dentry;
 
-       rc = avc_has_perm(tsec->sid, dsec->sid, SECCLASS_DIR,
+       rc = avc_has_perm(csec->action_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;
+       if (csec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
+               newsid = csec->create_sid;
        } else {
-               rc = security_transition_sid(tsec->sid, dsec->sid, tclass,
-                                            &newsid);
+               rc = security_transition_sid(csec->action_sid, dsec->sid,
+                                            tclass, &newsid);
                if (rc)
                        return rc;
        }
 
-       rc = avc_has_perm(tsec->sid, newsid, tclass, FILE__CREATE, &ad);
+       rc = avc_has_perm(csec->action_sid, newsid, tclass, FILE__CREATE, &ad);
        if (rc)
                return rc;
 
@@ -1196,11 +1205,12 @@ static int may_create(struct inode *dir,
 static int may_create_key(u32 ksid,
                          struct task_struct *ctx)
 {
-       struct task_security_struct *tsec;
+       struct cred_security_struct *csec;
 
-       tsec = ctx->security;
+       csec = ctx->cred->security;
 
-       return avc_has_perm(tsec->sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
+       return avc_has_perm(csec->action_sid, ksid, SECCLASS_KEY, KEY__CREATE,
+                           NULL);
 }
 
 #define MAY_LINK   0
@@ -1213,13 +1223,13 @@ static int may_link(struct inode *dir,
                    int kind)
 
 {
-       struct task_security_struct *tsec;
+       struct cred_security_struct *csec;
        struct inode_security_struct *dsec, *isec;
        struct avc_audit_data ad;
        u32 av;
        int rc;
 
-       tsec = current->security;
+       csec = current->cred->security;
        dsec = dir->i_security;
        isec = dentry->d_inode->i_security;
 
@@ -1228,7 +1238,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(csec->action_sid, dsec->sid, SECCLASS_DIR, av, &ad);
        if (rc)
                return rc;
 
@@ -1247,7 +1257,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(csec->action_sid, isec->sid, isec->sclass, av, &ad);
        return rc;
 }
 
@@ -1256,14 +1266,14 @@ static inline int may_rename(struct inode *old_dir,
                             struct inode *new_dir,
                             struct dentry *new_dentry)
 {
-       struct task_security_struct *tsec;
+       struct cred_security_struct *csec;
        struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
        struct avc_audit_data ad;
        u32 av;
        int old_is_dir, new_is_dir;
        int rc;
 
-       tsec = current->security;
+       csec = current->cred->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);
@@ -1272,16 +1282,16 @@ static inline int may_rename(struct inode *old_dir,
        AVC_AUDIT_DATA_INIT(&ad, FS);
 
        ad.u.fs.dentry = old_dentry;
-       rc = avc_has_perm(tsec->sid, old_dsec->sid, SECCLASS_DIR,
+       rc = avc_has_perm(csec->action_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(csec->action_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(csec->action_sid, old_isec->sid,
                                  old_isec->sclass, DIR__REPARENT, &ad);
                if (rc)
                        return rc;
@@ -1291,15 +1301,17 @@ 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(csec->action_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(csec->action_sid, new_isec->sid,
                                  new_isec->sclass,
-                                 (new_is_dir ? DIR__RMDIR : FILE__UNLINK), 
&ad);
+                                 (new_is_dir ? DIR__RMDIR : FILE__UNLINK),
+                                 &ad);
                if (rc)
                        return rc;
        }
@@ -1313,12 +1325,12 @@ static int superblock_has_perm(struct task_struct *tsk,
                               u32 perms,
                               struct avc_audit_data *ad)
 {
-       struct task_security_struct *tsec;
+       struct cred_security_struct *csec;
        struct superblock_security_struct *sbsec;
 
-       tsec = tsk->security;
+       csec = tsk->cred->security;
        sbsec = sb->s_security;
-       return avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
+       return avc_has_perm(csec->action_sid, sbsec->sid, SECCLASS_FILESYSTEM,
                            perms, ad);
 }
 
@@ -1371,7 +1383,7 @@ static inline u32 file_to_av(struct file *file)
 
 static int selinux_ptrace(struct task_struct *parent, struct task_struct 
*child)
 {
-       struct task_security_struct *psec = parent->security;
+       struct cred_security_struct *psec;
        struct task_security_struct *csec = child->security;
        int rc;
 
@@ -1381,8 +1393,12 @@ static int selinux_ptrace(struct task_struct *parent, 
struct task_struct *child)
 
        rc = task_has_perm(parent, child, PROCESS__PTRACE);
        /* Save the SID of the tracing process for later use in apply_creds. */
-       if (!(child->ptrace & PT_PTRACED) && !rc)
-               csec->ptrace_sid = psec->sid;
+       if (!(child->ptrace & PT_PTRACED) && !rc) {
+               rcu_read_lock();
+               psec = task_cred(parent)->security;
+               csec->ptrace_sid = psec->action_sid;
+               rcu_read_unlock();
+       }
        return rc;
 }
 
@@ -1472,7 +1488,7 @@ static int selinux_sysctl(ctl_table *table, int op)
 {
        int error = 0;
        u32 av;
-       struct task_security_struct *tsec;
+       struct cred_security_struct *csec;
        u32 tsid;
        int rc;
 
@@ -1480,7 +1496,7 @@ static int selinux_sysctl(ctl_table *table, int op)
        if (rc)
                return rc;
 
-       tsec = current->security;
+       csec = current->cred->security;
 
        rc = selinux_sysctl_get_sid(table, (op == 0001) ?
                                    SECCLASS_DIR : SECCLASS_FILE, &tsid);
@@ -1492,7 +1508,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(csec->action_sid, tsid,
                                     SECCLASS_DIR, DIR__SEARCH, NULL);
        } else {
                av = 0;
@@ -1501,7 +1517,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(csec->action_sid, tsid,
                                             SECCLASS_FILE, av, NULL);
         }
 
@@ -1589,11 +1605,11 @@ static int selinux_syslog(int type)
 static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
 {
        int rc, cap_sys_admin = 0;
-       struct task_security_struct *tsec = current->security;
+       struct cred_security_struct *csec = current->cred->security;
 
        rc = secondary_ops->capable(current, CAP_SYS_ADMIN);
        if (rc == 0)
-               rc = avc_has_perm_noaudit(tsec->sid, tsec->sid,
+               rc = avc_has_perm_noaudit(csec->action_sid, csec->action_sid,
                                          SECCLASS_CAPABILITY,
                                          CAP_TO_MASK(CAP_SYS_ADMIN),
                                          0,
@@ -1626,6 +1642,7 @@ static int selinux_bprm_alloc_security(struct 
linux_binprm *bprm)
 static int selinux_bprm_set_security(struct linux_binprm *bprm)
 {
        struct task_security_struct *tsec;
+       struct cred_security_struct *csec;
        struct inode *inode = bprm->file->f_path.dentry->d_inode;
        struct inode_security_struct *isec;
        struct bprm_security_struct *bsec;
@@ -1643,15 +1660,16 @@ static int selinux_bprm_set_security(struct 
linux_binprm *bprm)
                return 0;
 
        tsec = current->security;
+       csec = bprm->cred->security;
        isec = inode->i_security;
 
        /* Default to the current task SID. */
-       bsec->sid = tsec->sid;
+       bsec->sid = csec->action_sid;
 
        /* Reset fs, key, and sock SIDs on execve. */
-       tsec->create_sid = 0;
-       tsec->keycreate_sid = 0;
-       tsec->sockcreate_sid = 0;
+       csec->create_sid = 0;
+       csec->keycreate_sid = 0;
+       csec->sockcreate_sid = 0;
 
        if (tsec->exec_sid) {
                newsid = tsec->exec_sid;
@@ -1659,7 +1677,7 @@ static int selinux_bprm_set_security(struct linux_binprm 
*bprm)
                tsec->exec_sid = 0;
        } else {
                /* Check for a default transition on this program. */
-               rc = security_transition_sid(tsec->sid, isec->sid,
+               rc = security_transition_sid(csec->action_sid, isec->sid,
                                             SECCLASS_PROCESS, &newsid);
                if (rc)
                        return rc;
@@ -1670,16 +1688,16 @@ static int selinux_bprm_set_security(struct 
linux_binprm *bprm)
        ad.u.fs.dentry = bprm->file->f_path.dentry;
 
        if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
-               newsid = tsec->sid;
+               newsid = csec->action_sid;
 
-        if (tsec->sid == newsid) {
-               rc = avc_has_perm(tsec->sid, isec->sid,
+        if (csec->action_sid == newsid) {
+               rc = avc_has_perm(csec->action_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(csec->action_sid, newsid,
                                  SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
                if (rc)
                        return rc;
@@ -1711,11 +1729,11 @@ static int selinux_bprm_secureexec (struct linux_binprm 
*bprm)
        struct task_security_struct *tsec = current->security;
        int atsecure = 0;
 
-       if (tsec->osid != tsec->sid) {
+       if (tsec->osid != tsec->victim_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,
+               atsecure = avc_has_perm(tsec->osid, tsec->victim_sid,
                                         SECCLASS_PROCESS,
                                         PROCESS__NOATSECURE, NULL);
        }
@@ -1825,6 +1843,7 @@ static inline void flush_unauthorized_files(struct 
files_struct * files)
 static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
 {
        struct task_security_struct *tsec;
+       struct cred_security_struct *csec;
        struct bprm_security_struct *bsec;
        u32 sid;
        int rc;
@@ -1832,17 +1851,17 @@ static void selinux_bprm_apply_creds(struct 
linux_binprm *bprm, int unsafe)
        secondary_ops->bprm_apply_creds(bprm, unsafe);
 
        tsec = current->security;
-
+       csec = bprm->cred->security;
        bsec = bprm->security;
        sid = bsec->sid;
 
-       tsec->osid = tsec->sid;
+       tsec->osid = tsec->victim_sid;
        bsec->unsafe = 0;
-       if (tsec->sid != sid) {
+       if (tsec->victim_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,
+                       rc = avc_has_perm(tsec->victim_sid, sid, 
SECCLASS_PROCESS,
                                        PROCESS__SHARE, NULL);
                        if (rc) {
                                bsec->unsafe = 1;
@@ -1861,7 +1880,9 @@ static void selinux_bprm_apply_creds(struct linux_binprm 
*bprm, int unsafe)
                                return;
                        }
                }
-               tsec->sid = sid;
+               if (csec->action_sid == tsec->victim_sid)
+                       csec->action_sid = sid;
+               tsec->victim_sid = sid;
        }
 }
 
@@ -1883,7 +1904,7 @@ static void selinux_bprm_post_apply_creds(struct 
linux_binprm *bprm)
                force_sig_specific(SIGKILL, current);
                return;
        }
-       if (tsec->osid == tsec->sid)
+       if (tsec->osid == tsec->victim_sid)
                return;
 
        /* Close files for which the new task SID is not authorized. */
@@ -1895,7 +1916,7 @@ static void selinux_bprm_post_apply_creds(struct 
linux_binprm *bprm)
           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,
+       rc = avc_has_perm(tsec->osid, tsec->victim_sid, SECCLASS_PROCESS,
                          PROCESS__SIGINH, NULL);
        if (rc) {
                memset(&itimer, 0, sizeof itimer);
@@ -1922,7 +1943,7 @@ static void selinux_bprm_post_apply_creds(struct 
linux_binprm *bprm)
           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,
+       rc = avc_has_perm(tsec->osid, tsec->victim_sid, SECCLASS_PROCESS,
                          PROCESS__RLIMITINH, NULL);
        if (rc) {
                for (i = 0; i < RLIM_NLIMITS; i++) {
@@ -2124,21 +2145,21 @@ static int selinux_inode_init_security(struct inode 
*inode, struct inode *dir,
                                       char **name, void **value,
                                       size_t *len)
 {
-       struct task_security_struct *tsec;
+       struct cred_security_struct *csec;
        struct inode_security_struct *dsec;
        struct superblock_security_struct *sbsec;
        u32 newsid, clen;
        int rc;
        char *namep = NULL, *context;
 
-       tsec = current->security;
+       csec = current->cred->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;
+       if (csec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
+               newsid = csec->create_sid;
        } else {
-               rc = security_transition_sid(tsec->sid, dsec->sid,
+               rc = security_transition_sid(csec->action_sid, dsec->sid,
                                             
inode_mode_to_security_class(inode->i_mode),
                                             &newsid);
                if (rc) {
@@ -2297,7 +2318,7 @@ static int selinux_inode_getattr(struct vfsmount *mnt, 
struct dentry *dentry)
 
 static int selinux_inode_setxattr(struct dentry *dentry, char *name, void 
*value, size_t size, int flags)
 {
-       struct task_security_struct *tsec = current->security;
+       struct cred_security_struct *csec = current->cred->security;
        struct inode *inode = dentry->d_inode;
        struct inode_security_struct *isec = inode->i_security;
        struct superblock_security_struct *sbsec;
@@ -2329,7 +2350,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, 
char *name, void *value
        AVC_AUDIT_DATA_INIT(&ad,FS);
        ad.u.fs.dentry = dentry;
 
-       rc = avc_has_perm(tsec->sid, isec->sid, isec->sclass,
+       rc = avc_has_perm(csec->action_sid, isec->sid, isec->sclass,
                          FILE__RELABELFROM, &ad);
        if (rc)
                return rc;
@@ -2338,12 +2359,12 @@ static int selinux_inode_setxattr(struct dentry 
*dentry, char *name, void *value
        if (rc)
                return rc;
 
-       rc = avc_has_perm(tsec->sid, newsid, isec->sclass,
+       rc = avc_has_perm(csec->action_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, csec->action_sid,
                                          isec->sclass);
        if (rc)
                return rc;
@@ -2577,8 +2598,9 @@ static int selinux_file_mmap(struct file *file, unsigned 
long reqprot,
                             unsigned long prot, unsigned long flags,
                             unsigned long addr, unsigned long addr_only)
 {
+       struct cred_security_struct *csec = current->cred->security;
        int rc = 0;
-       u32 sid = ((struct task_security_struct*)(current->security))->sid;
+       u32 sid = csec->action_sid;
 
        if (addr < mmap_min_addr)
                rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
@@ -2692,7 +2714,7 @@ static int selinux_file_set_fowner(struct file *file)
 
        tsec = current->security;
        fsec = file->f_security;
-       fsec->fown_sid = tsec->sid;
+       fsec->fown_sid = tsec->victim_sid;
 
        return 0;
 }
@@ -2716,7 +2738,7 @@ 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, tsec->victim_sid,
                            SECCLASS_PROCESS, perm, NULL);
 }
 
@@ -2725,6 +2747,31 @@ static int selinux_file_receive(struct file *file)
        return file_has_perm(current, file, file_to_av(file));
 }
 
+/* credential security operations */
+
+/*
+ * duplicate the security information attached to a credentials record that is
+ * itself undergoing duplication
+ */
+static int selinux_cred_dup(struct cred *cred)
+{
+       cred->security = kmemdup(cred->security,
+                                sizeof(struct cred_security_struct),
+                                GFP_KERNEL);
+       return cred->security ? 0 : -ENOMEM;
+}
+
+/*
+ * destroy the security information attached to a credentials record
+ * - this is done under RCU, and may not be associated with the task that set 
it
+ *   up
+ */
+static void selinux_cred_destroy(struct cred *cred)
+{
+       kfree(cred->security);
+}
+
+
 /* task security operations */
 
 static int selinux_task_create(unsigned long clone_flags)
@@ -2751,13 +2798,10 @@ static int selinux_task_alloc_security(struct 
task_struct *tsk)
        tsec2 = tsk->security;
 
        tsec2->osid = tsec1->osid;
-       tsec2->sid = tsec1->sid;
+       tsec2->victim_sid = tsec1->victim_sid;
 
-       /* Retain the exec, fs, key, and sock SIDs across fork */
+       /* Retain the exec SID 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;
 
        /* Retain ptracer SID across fork, if any.
           This will be reset by the ptrace hook upon any
@@ -2895,7 +2939,8 @@ static int selinux_task_kill(struct task_struct *p, 
struct siginfo *info,
                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, tsec->victim_sid,
+                                 SECCLASS_PROCESS, perm, NULL);
        else
                rc = task_has_perm(current, p, perm);
        return rc;
@@ -2929,8 +2974,8 @@ static void selinux_task_reparent_to_init(struct 
task_struct *p)
        secondary_ops->task_reparent_to_init(p);
 
        tsec = p->security;
-       tsec->osid = tsec->sid;
-       tsec->sid = SECINITSID_KERNEL;
+       tsec->osid = tsec->victim_sid;
+       tsec->victim_sid = SECINITSID_KERNEL;
        return;
 }
 
@@ -2940,7 +2985,7 @@ static void selinux_task_to_inode(struct task_struct *p,
        struct task_security_struct *tsec = p->security;
        struct inode_security_struct *isec = inode->i_security;
 
-       isec->sid = tsec->sid;
+       isec->sid = tsec->victim_sid;
        isec->initialized = 1;
        return;
 }
@@ -3165,11 +3210,11 @@ 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 cred_security_struct *csec;
        struct avc_audit_data ad;
        int err = 0;
 
-       tsec = task->security;
+       csec = task->cred->security;
        isec = SOCK_INODE(sock)->i_security;
 
        if (isec->sid == SECINITSID_KERNEL)
@@ -3177,7 +3222,8 @@ static int socket_has_perm(struct task_struct *task, 
struct socket *sock,
 
        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(csec->action_sid, isec->sid, isec->sclass, perms,
+                          &ad);
 
 out:
        return err;
@@ -3187,15 +3233,15 @@ static int selinux_socket_create(int family, int type,
                                 int protocol, int kern)
 {
        int err = 0;
-       struct task_security_struct *tsec;
+       struct cred_security_struct *csec;
        u32 newsid;
 
        if (kern)
                goto out;
 
-       tsec = current->security;
-       newsid = tsec->sockcreate_sid ? : tsec->sid;
-       err = avc_has_perm(tsec->sid, newsid,
+       csec = current->cred->security;
+       newsid = csec->sockcreate_sid ? : csec->action_sid;
+       err = avc_has_perm(csec->action_sid, newsid,
                           socket_type_to_security_class(family, type,
                           protocol), SOCKET__CREATE, NULL);
 
@@ -3208,14 +3254,14 @@ static int selinux_socket_post_create(struct socket 
*sock, int family,
 {
        int err = 0;
        struct inode_security_struct *isec;
-       struct task_security_struct *tsec;
+       struct cred_security_struct *csec;
        struct sk_security_struct *sksec;
        u32 newsid;
 
        isec = SOCK_INODE(sock)->i_security;
 
-       tsec = current->security;
-       newsid = tsec->sockcreate_sid ? : tsec->sid;
+       csec = current->cred->security;
+       newsid = csec->sockcreate_sid ? : csec->action_sid;
        isec->sclass = socket_type_to_security_class(family, type, protocol);
        isec->sid = kern ? SECINITSID_KERNEL : newsid;
        isec->initialized = 1;
@@ -4029,7 +4075,7 @@ static int ipc_alloc_security(struct task_struct *task,
                              struct kern_ipc_perm *perm,
                              u16 sclass)
 {
-       struct task_security_struct *tsec = task->security;
+       struct cred_security_struct *csec = task->cred->security;
        struct ipc_security_struct *isec;
 
        isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
@@ -4038,7 +4084,7 @@ static int ipc_alloc_security(struct task_struct *task,
 
        isec->sclass = sclass;
        isec->ipc_perm = perm;
-       isec->sid = tsec->sid;
+       isec->sid = csec->action_sid;
        perm->security = isec;
 
        return 0;
@@ -4077,17 +4123,18 @@ 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 cred_security_struct *csec;
        struct ipc_security_struct *isec;
        struct avc_audit_data ad;
 
-       tsec = current->security;
+       csec = current->cred->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(csec->action_sid, isec->sid, isec->sclass, perms,
+                           &ad);
 }
 
 static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
@@ -4103,7 +4150,7 @@ 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 cred_security_struct *csec;
        struct ipc_security_struct *isec;
        struct avc_audit_data ad;
        int rc;
@@ -4112,13 +4159,13 @@ static int selinux_msg_queue_alloc_security(struct 
msg_queue *msq)
        if (rc)
                return rc;
 
-       tsec = current->security;
+       csec = current->cred->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(csec->action_sid, isec->sid, SECCLASS_MSGQ,
                          MSGQ__CREATE, &ad);
        if (rc) {
                ipc_free_security(&msq->q_perm);
@@ -4134,17 +4181,17 @@ 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 cred_security_struct *csec;
        struct ipc_security_struct *isec;
        struct avc_audit_data ad;
 
-       tsec = current->security;
+       csec = current->cred->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(csec->action_sid, isec->sid, SECCLASS_MSGQ,
                            MSGQ__ASSOCIATE, &ad);
 }
 
@@ -4178,13 +4225,13 @@ 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 cred_security_struct *csec;
        struct ipc_security_struct *isec;
        struct msg_security_struct *msec;
        struct avc_audit_data ad;
        int rc;
 
-       tsec = current->security;
+       csec = current->cred->security;
        isec = msq->q_perm.security;
        msec = msg->security;
 
@@ -4196,7 +4243,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,
+               rc = security_transition_sid(csec->action_sid,
                                             isec->sid,
                                             SECCLASS_MSG,
                                             &msec->sid);
@@ -4208,11 +4255,11 @@ 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(csec->action_sid, isec->sid, SECCLASS_MSGQ,
                          MSGQ__WRITE, &ad);
        if (!rc)
                /* Can this process send the message */
-               rc = avc_has_perm(tsec->sid, msec->sid,
+               rc = avc_has_perm(csec->action_sid, msec->sid,
                                  SECCLASS_MSG, MSG__SEND, &ad);
        if (!rc)
                /* Can the message be put in the queue? */
@@ -4239,10 +4286,10 @@ static int selinux_msg_queue_msgrcv(struct msg_queue 
*msq, struct msg_msg *msg,
        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(tsec->victim_sid, isec->sid,
                          SECCLASS_MSGQ, MSGQ__READ, &ad);
        if (!rc)
-               rc = avc_has_perm(tsec->sid, msec->sid,
+               rc = avc_has_perm(tsec->victim_sid, msec->sid,
                                  SECCLASS_MSG, MSG__RECEIVE, &ad);
        return rc;
 }
@@ -4250,7 +4297,7 @@ 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 cred_security_struct *csec;
        struct ipc_security_struct *isec;
        struct avc_audit_data ad;
        int rc;
@@ -4259,13 +4306,13 @@ static int selinux_shm_alloc_security(struct 
shmid_kernel *shp)
        if (rc)
                return rc;
 
-       tsec = current->security;
+       csec = current->cred->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(csec->action_sid, isec->sid, SECCLASS_SHM,
                          SHM__CREATE, &ad);
        if (rc) {
                ipc_free_security(&shp->shm_perm);
@@ -4281,17 +4328,17 @@ 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 cred_security_struct *csec;
        struct ipc_security_struct *isec;
        struct avc_audit_data ad;
 
-       tsec = current->security;
+       csec = current->cred->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(csec->action_sid, isec->sid, SECCLASS_SHM,
                            SHM__ASSOCIATE, &ad);
 }
 
@@ -4349,7 +4396,7 @@ 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 cred_security_struct *csec;
        struct ipc_security_struct *isec;
        struct avc_audit_data ad;
        int rc;
@@ -4358,13 +4405,13 @@ static int selinux_sem_alloc_security(struct sem_array 
*sma)
        if (rc)
                return rc;
 
-       tsec = current->security;
+       csec = current->cred->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(csec->action_sid, isec->sid, SECCLASS_SEM,
                          SEM__CREATE, &ad);
        if (rc) {
                ipc_free_security(&sma->sem_perm);
@@ -4380,17 +4427,17 @@ 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 cred_security_struct *csec;
        struct ipc_security_struct *isec;
        struct avc_audit_data ad;
 
-       tsec = current->security;
+       csec = current->cred->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(csec->action_sid, isec->sid, SECCLASS_SEM,
                            SEM__ASSOCIATE, &ad);
 }
 
@@ -4506,6 +4553,7 @@ static int selinux_getprocattr(struct task_struct *p,
                               char *name, char **value)
 {
        struct task_security_struct *tsec;
+       struct cred_security_struct *csec;
        u32 sid;
        int error;
        unsigned len;
@@ -4517,22 +4565,25 @@ static int selinux_getprocattr(struct task_struct *p,
        }
 
        tsec = p->security;
+       rcu_read_lock();
+       csec = task_cred(p)->security;
 
        if (!strcmp(name, "current"))
-               sid = tsec->sid;
+               sid = tsec->victim_sid;
        else if (!strcmp(name, "prev"))
                sid = tsec->osid;
        else if (!strcmp(name, "exec"))
                sid = tsec->exec_sid;
        else if (!strcmp(name, "fscreate"))
-               sid = tsec->create_sid;
+               sid = csec->create_sid;
        else if (!strcmp(name, "keycreate"))
-               sid = tsec->keycreate_sid;
+               sid = csec->keycreate_sid;
        else if (!strcmp(name, "sockcreate"))
-               sid = tsec->sockcreate_sid;
+               sid = csec->sockcreate_sid;
        else
-               return -EINVAL;
+               goto invalid;
 
+       rcu_read_unlock();
        if (!sid)
                return 0;
 
@@ -4540,13 +4591,20 @@ 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,
                               char *name, void *value, size_t size)
 {
        struct task_security_struct *tsec;
-       u32 sid = 0;
+       struct cred_security_struct *csec;
+       struct av_decision avd;
+       struct cred *cred;
+       u32 sid = 0, perm;
        int error;
        char *str = value;
 
@@ -4562,17 +4620,19 @@ 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);
+               perm = PROCESS__SETEXEC;
        else if (!strcmp(name, "fscreate"))
-               error = task_has_perm(current, p, PROCESS__SETFSCREATE);
+               perm = PROCESS__SETFSCREATE;
        else if (!strcmp(name, "keycreate"))
-               error = task_has_perm(current, p, PROCESS__SETKEYCREATE);
+               perm = PROCESS__SETKEYCREATE;
        else if (!strcmp(name, "sockcreate"))
-               error = task_has_perm(current, p, PROCESS__SETSOCKCREATE);
+               perm = PROCESS__SETSOCKCREATE;
        else if (!strcmp(name, "current"))
-               error = task_has_perm(current, p, PROCESS__SETCURRENT);
+               perm = PROCESS__SETCURRENT;
        else
-               error = -EINVAL;
+               return -EINVAL;
+
+       error = task_has_perm(current, p, perm);
        if (error)
                return error;
 
@@ -4594,20 +4654,37 @@ static int selinux_setprocattr(struct task_struct *p,
           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"))
+       csec = p->cred->security;
+       switch (perm) {
+       case PROCESS__SETEXEC:
                tsec->exec_sid = sid;
-       else if (!strcmp(name, "fscreate"))
-               tsec->create_sid = sid;
-       else if (!strcmp(name, "keycreate")) {
+               break;
+
+       case PROCESS__SETKEYCREATE:
                error = may_create_key(sid, p);
                if (error)
                        return error;
-               tsec->keycreate_sid = sid;
-       } else if (!strcmp(name, "sockcreate"))
-               tsec->sockcreate_sid = sid;
-       else if (!strcmp(name, "current")) {
-               struct av_decision avd;
+       case PROCESS__SETFSCREATE:
+       case PROCESS__SETSOCKCREATE:
+               cred = dup_cred(current->cred);
+               if (!cred)
+                       return -ENOMEM;
+               csec = cred->security;
+               switch (perm) {
+               case PROCESS__SETKEYCREATE:
+                       csec->keycreate_sid = sid;
+                       break;
+               case PROCESS__SETFSCREATE:
+                       csec->create_sid = sid;
+                       break;
+               case PROCESS__SETSOCKCREATE:
+                       csec->sockcreate_sid = sid;
+                       break;
+               }
+               set_current_cred(cred);
+               break;
 
+       case PROCESS__SETCURRENT:
                if (sid == 0)
                        return -EINVAL;
 
@@ -4626,11 +4703,16 @@ static int selinux_setprocattr(struct task_struct *p,
                 }
 
                /* Check permissions for the transition. */
-               error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
+               error = avc_has_perm(csec->action_sid, sid, SECCLASS_PROCESS,
                                     PROCESS__DYNTRANSITION, NULL);
                if (error)
                        return error;
 
+               cred = dup_cred(current->cred);
+               if (!cred)
+                       return -ENOMEM;
+               csec = cred->security;
+
                /* Check for ptracing, and update the task SID if ok.
                   Otherwise, leave SID unchanged and fail. */
                task_lock(p);
@@ -4638,20 +4720,25 @@ static int selinux_setprocattr(struct task_struct *p,
                        error = avc_has_perm_noaudit(tsec->ptrace_sid, sid,
                                                     SECCLASS_PROCESS,
                                                     PROCESS__PTRACE, 0, &avd);
-                       if (!error)
-                               tsec->sid = sid;
+                       if (!error) {
+                               csec->action_sid = tsec->victim_sid = sid;
+                       }
                        task_unlock(p);
                        avc_audit(tsec->ptrace_sid, sid, SECCLASS_PROCESS,
                                  PROCESS__PTRACE, &avd, error, NULL);
-                       if (error)
+                       if (error) {
+                               put_cred(cred);
                                return error;
+                       }
                } else {
-                       tsec->sid = sid;
+                       csec->action_sid = tsec->victim_sid = sid;
                        task_unlock(p);
                }
-       }
-       else
+               set_current_cred(cred);
+               break;
+       default:
                return -EINVAL;
+       }
 
        return size;
 }
@@ -4671,18 +4758,21 @@ static void selinux_release_secctx(char *secdata, u32 
seclen)
 static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
                             unsigned long flags)
 {
-       struct task_security_struct *tsec = tsk->security;
+       struct cred_security_struct *csec;
        struct key_security_struct *ksec;
 
        ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
        if (!ksec)
                return -ENOMEM;
 
+       rcu_read_lock();
+       csec = task_cred(tsk)->security;
        ksec->obj = k;
-       if (tsec->keycreate_sid)
-               ksec->sid = tsec->keycreate_sid;
+       if (csec->keycreate_sid)
+               ksec->sid = csec->keycreate_sid;
        else
-               ksec->sid = tsec->sid;
+               ksec->sid = csec->action_sid;
+       rcu_read_unlock();
        k->security = ksec;
 
        return 0;
@@ -4697,17 +4787,13 @@ 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)
+                                 struct task_struct *ctx,
+                                 key_perm_t perm)
 {
        struct key *key;
-       struct task_security_struct *tsec;
+       struct cred_security_struct *csec;
        struct key_security_struct *ksec;
-
-       key = key_ref_to_ptr(key_ref);
-
-       tsec = ctx->security;
-       ksec = key->security;
+       u32 action_sid;
 
        /* if no specific permissions are requested, we skip the
           permission check. No serious, additional covert channels
@@ -4715,7 +4801,16 @@ static int selinux_key_permission(key_ref_t key_ref,
        if (perm == 0)
                return 0;
 
-       return avc_has_perm(tsec->sid, ksec->sid,
+       key = key_ref_to_ptr(key_ref);
+
+       rcu_read_lock();
+       csec = task_cred(ctx)->security;
+       action_sid = csec->action_sid;
+       rcu_read_unlock();
+
+       ksec = key->security;
+
+       return avc_has_perm(action_sid, ksec->sid,
                            SECCLASS_KEY, perm, NULL);
 }
 
@@ -4790,6 +4885,9 @@ static struct security_operations selinux_ops = {
        .file_send_sigiotask =          selinux_file_send_sigiotask,
        .file_receive =                 selinux_file_receive,
 
+       .cred_dup =                     selinux_cred_dup,
+       .cred_destroy =                 selinux_cred_destroy,
+
        .task_create =                  selinux_task_create,
        .task_alloc_security =          selinux_task_alloc_security,
        .task_free_security =           selinux_task_free_security,
@@ -4898,6 +4996,17 @@ static struct security_operations selinux_ops = {
 #endif
 };
 
+/*
+ * initial security credentials
+ * - attached to init_cred which is never released
+ */
+static struct cred_security_struct init_cred_sec = {
+       .action_sid     = SECINITSID_KERNEL,
+       .create_sid     = SECINITSID_UNLABELED,
+       .keycreate_sid  = SECINITSID_UNLABELED,
+       .sockcreate_sid = SECINITSID_UNLABELED,
+};
+
 static __init int selinux_init(void)
 {
        struct task_security_struct *tsec;
@@ -4909,11 +5018,15 @@ static __init int selinux_init(void)
 
        printk(KERN_INFO "SELinux:  Initializing.\n");
 
+       /* Set the security state for the initial credentials */
+       init_cred.security = &init_cred_sec;
+       BUG_ON(current->cred != &init_cred);
+
        /* 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;
+       tsec->osid = tsec->victim_sid = SECINITSID_KERNEL;
 
        sel_inode_cache = kmem_cache_create("selinux_inode_security",
                                            sizeof(struct 
inode_security_struct),
diff --git a/security/selinux/include/objsec.h 
b/security/selinux/include/objsec.h
index 91b88f0..a1dbc1c 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -27,14 +27,22 @@
 #include "flask.h"
 #include "avc.h"
 
+/*
+ * the security parameters associated with the credentials record structure
+ * (struct cred::security)
+ */
+struct cred_security_struct {
+       u32     action_sid;     /* perform action as SID */
+       u32     create_sid;     /* filesystem object creation as SID */
+       u32     keycreate_sid;  /* key creation as SID */
+       u32     sockcreate_sid; /* socket creation as SID */
+};
+
 struct task_security_struct {
        struct task_struct *task;      /* back pointer to task object */
        u32 osid;            /* SID prior to last execve */
-       u32 sid;             /* current SID */
+       u32 victim_sid;      /* current SID affecting victimisation of this 
task */
        u32 exec_sid;        /* exec SID */
-       u32 create_sid;      /* fscreate SID */
-       u32 keycreate_sid;   /* keycreate SID */
-       u32 sockcreate_sid;  /* fscreate SID */
        u32 ptrace_sid;      /* SID of ptrace parent */
 };
 
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index c9e92da..9c6737f 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -77,13 +77,13 @@ extern void selnl_notify_setenforce(int val);
 static int task_has_security(struct task_struct *tsk,
                             u32 perms)
 {
-       struct task_security_struct *tsec;
+       struct cred_security_struct *csec;
 
-       tsec = tsk->security;
-       if (!tsec)
+       csec = tsk->cred->security;
+       if (!csec)
                return -EACCES;
 
-       return avc_has_perm(tsec->sid, SECINITSID_SECURITY,
+       return avc_has_perm(csec->action_sid, SECINITSID_SECURITY,
                            SECCLASS_SECURITY, perms, NULL);
 }
 
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index ba715f4..902d302 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -240,7 +240,7 @@ static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx 
**ctxp,
        /*
         * Does the subject have permission to set security context?
         */
-       rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
+       rc = avc_has_perm(tsec->action_sid, ctx->ctx_sid,
                          SECCLASS_ASSOCIATION,
                          ASSOCIATION__SETCONTEXT, NULL);
        if (rc)
@@ -341,7 +341,7 @@ int selinux_xfrm_policy_delete(struct xfrm_policy *xp)
        int rc = 0;
 
        if (ctx)
-               rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
+               rc = avc_has_perm(tsec->action_sid, ctx->ctx_sid,
                                  SECCLASS_ASSOCIATION,
                                  ASSOCIATION__SETCONTEXT, NULL);
 
@@ -383,7 +383,7 @@ int selinux_xfrm_state_delete(struct xfrm_state *x)
        int rc = 0;
 
        if (ctx)
-               rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
+               rc = avc_has_perm(tsec->action_sid, ctx->ctx_sid,
                                  SECCLASS_ASSOCIATION,
                                  ASSOCIATION__SETCONTEXT, NULL);
 

-
To unsubscribe from this list: send the line "unsubscribe 
linux-security-module" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to