Quoting David Howells ([email protected]):
> 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.
My concern is with this victim_sid. Whether the concern is valid
depends on exactly how the other credentials can be used, which isn't
yet entirely clear to me.
So my concern is that while a task is acting with alternate creds,
another task can act upon it based upon victim_sid. So does this
open up the possibility for an unprivileged task to ptrace or kill
a task in the middle of a privileged operation? Is that somehow
safe in the way this is used here?
I guess I need to look more at the actual nfs patches etc.
thanks,
-serge
> (*) 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 | 34 +++
> 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, 380 insertions(+), 206 deletions(-)
>
> diff --git a/include/linux/cred.h b/include/linux/cred.h
> index 22ae610..6c6feec 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..e5ed2ea 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -504,6 +504,18 @@ 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 +1269,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 +1879,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 +2571,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 e96dafe..6a9dda2 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 3694662..6fc41da 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;
> @@ -333,26 +334,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;
> @@ -369,7 +370,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)
> @@ -501,7 +502,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;
>
> @@ -523,12 +524,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;
> }
> @@ -548,7 +549,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;
>
> @@ -568,7 +569,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;
>
> @@ -1023,15 +1024,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);
> }
>
> @@ -1039,16 +1047,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);
> }
>
> @@ -1056,11 +1064,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);
> }
>
> @@ -1072,14 +1080,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) {
> @@ -1088,7 +1096,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
> @@ -1119,7 +1128,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;
> @@ -1131,8 +1140,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);
> @@ -1152,36 +1161,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;
>
> @@ -1194,11 +1203,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
> @@ -1211,13 +1221,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;
>
> @@ -1226,7 +1236,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;
>
> @@ -1245,7 +1255,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;
> }
>
> @@ -1254,14 +1264,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);
> @@ -1270,16 +1280,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;
> @@ -1289,15 +1299,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;
> }
> @@ -1311,12 +1323,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);
> }
>
> @@ -1369,7 +1381,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;
>
> @@ -1379,8 +1391,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;
> }
>
> @@ -1470,7 +1486,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;
>
> @@ -1478,7 +1494,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);
> @@ -1490,7 +1506,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;
> @@ -1499,7 +1515,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);
> }
>
> @@ -1587,11 +1603,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,
> @@ -1624,6 +1640,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;
> @@ -1641,15 +1658,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;
> @@ -1657,7 +1675,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;
> @@ -1668,16 +1686,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;
> @@ -1709,11 +1727,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);
> }
> @@ -1823,6 +1841,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;
> @@ -1830,17 +1849,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;
> @@ -1859,7 +1878,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;
> }
> }
>
> @@ -1881,7 +1902,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. */
> @@ -1893,7 +1914,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);
> @@ -1920,7 +1941,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++) {
> @@ -2122,21 +2143,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) {
> @@ -2295,7 +2316,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;
> @@ -2327,7 +2348,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;
> @@ -2336,12 +2357,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;
> @@ -2575,8 +2596,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,
> @@ -2690,7 +2712,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;
> }
> @@ -2714,7 +2736,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);
> }
>
> @@ -2723,6 +2745,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)
> @@ -2749,13 +2796,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
> @@ -2893,7 +2937,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;
> @@ -2927,8 +2972,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;
> }
>
> @@ -2938,7 +2983,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;
> }
> @@ -3163,11 +3208,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)
> @@ -3175,7 +3220,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;
> @@ -3185,15 +3231,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);
>
> @@ -3206,14 +3252,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;
> @@ -4027,7 +4073,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);
> @@ -4036,7 +4082,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;
> @@ -4075,17 +4121,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)
> @@ -4101,7 +4148,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;
> @@ -4110,13 +4157,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);
> @@ -4132,17 +4179,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);
> }
>
> @@ -4176,13 +4223,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;
>
> @@ -4194,7 +4241,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);
> @@ -4206,11 +4253,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? */
> @@ -4237,10 +4284,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;
> }
> @@ -4248,7 +4295,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;
> @@ -4257,13 +4304,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);
> @@ -4279,17 +4326,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);
> }
>
> @@ -4347,7 +4394,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;
> @@ -4356,13 +4403,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);
> @@ -4378,17 +4425,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);
> }
>
> @@ -4504,6 +4551,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;
> @@ -4515,22 +4563,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;
>
> @@ -4538,13 +4589,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;
>
> @@ -4560,17 +4618,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;
>
> @@ -4592,20 +4652,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;
>
> @@ -4624,11 +4701,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);
> @@ -4636,20 +4718,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;
> }
> @@ -4669,18 +4756,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;
> @@ -4695,17 +4785,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
> @@ -4713,7 +4799,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);
> }
>
> @@ -4788,6 +4883,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,
> @@ -4896,6 +4994,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;
> @@ -4907,11 +5016,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
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]