Add an act-as SID to task_security_struct that is equivalent to fsuid/fsgid in task_struct. This permits a task to perform operations as if it is the overriding SID, without changing its own SID as that might be needed to control access to the process by ptrace, signals, /proc, etc. This is useful for CacheFiles in that it allows CacheFiles to access the cache files and directories using the cache's security context rather than the security context of the process on whose behalf it is working, and in the context of which it is running. Signed-Off-By: David Howells <dhowells@xxxxxxxxxx> --- include/linux/security.h | 32 +++++++ security/dummy.c | 12 +++ security/selinux/exports.c | 2 security/selinux/hooks.c | 160 +++++++++++++++++++++++-------------- security/selinux/include/objsec.h | 1 security/selinux/selinuxfs.c | 2 security/selinux/xfrm.c | 6 + 7 files changed, 148 insertions(+), 67 deletions(-) diff --git a/include/linux/security.h b/include/linux/security.h index 92d3da0..422015d 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1154,6 +1154,16 @@ struct request_sock; * Set the current FS security ID. * @secid contains the security ID to set. * + * @act_as_secid: + * Set the security ID as which to act, returning the security ID as which + * the process was previously acting. + * @secid contains the security ID to act as. + * + * @act_as_self: + * Reset the security ID as which to act to be the same as the process's + * owning security ID, and return the security ID as which the process was + * previously acting. + * * This is the main security structure. */ struct security_operations { @@ -1339,6 +1349,8 @@ struct security_operations { void (*release_secctx)(char *secdata, u32 seclen); u32 (*get_fscreate_secid)(void); u32 (*set_fscreate_secid)(u32 secid); + u32 (*act_as_secid)(u32 secid); + u32 (*act_as_self)(void); #ifdef CONFIG_SECURITY_NETWORK int (*unix_stream_connect) (struct socket * sock, @@ -2146,6 +2158,16 @@ static inline u32 security_set_fscreate_secid(u32 secid) return security_ops->set_fscreate_secid(secid); } +static inline u32 security_act_as_secid(u32 secid) +{ + return security_ops->act_as_secid(secid); +} + +static inline u32 security_act_as_self(void) +{ + return security_ops->act_as_self(); +} + /* prototypes */ extern int security_init (void); extern int register_security (struct security_operations *ops); @@ -2838,6 +2860,16 @@ static inline u32 security_set_fscreate_secid(u32 secid) return 0; } +static inline u32 security_act_as_secid(u32 secid) +{ + return 0; +} + +static inline u32 security_act_as_self(void) +{ + return 0; +} + #endif /* CONFIG_SECURITY */ #ifdef CONFIG_SECURITY_NETWORK diff --git a/security/dummy.c b/security/dummy.c index d463e6f..77ec75d 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -940,6 +940,16 @@ static u32 dummy_set_fscreate_secid(u32 secid) return 0; } +static u32 dummy_act_as_secid(u32 secid) +{ + return 0; +} + +static u32 dummy_act_as_self(void) +{ + return 0; +} + #ifdef CONFIG_KEYS static inline int dummy_key_alloc(struct key *key, struct task_struct *ctx, unsigned long flags) @@ -1096,6 +1106,8 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, release_secctx); set_to_dummy_if_null(ops, get_fscreate_secid); set_to_dummy_if_null(ops, set_fscreate_secid); + set_to_dummy_if_null(ops, act_as_secid); + set_to_dummy_if_null(ops, act_as_self); #ifdef CONFIG_SECURITY_NETWORK set_to_dummy_if_null(ops, unix_stream_connect); set_to_dummy_if_null(ops, unix_may_send); diff --git a/security/selinux/exports.c b/security/selinux/exports.c index b6f9694..b559699 100644 --- a/security/selinux/exports.c +++ b/security/selinux/exports.c @@ -79,7 +79,7 @@ int selinux_relabel_packet_permission(u32 sid) if (selinux_enabled) { struct task_security_struct *tsec = current->security; - return avc_has_perm(tsec->sid, sid, SECCLASS_PACKET, + return avc_has_perm(tsec->actor_sid, sid, SECCLASS_PACKET, PACKET__RELABELTO, NULL); } return 0; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index d23ac76..453eef2 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->actor_sid = tsec->sid = tsec->ptrace_sid = + SECINITSID_UNLABELED; task->security = tsec; return 0; @@ -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 = tsec->actor_sid; inode->i_security = isec; return 0; @@ -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 = tsec->actor_sid; + fsec->fown_sid = tsec->actor_sid; file->f_security = fsec; return 0; @@ -337,12 +338,12 @@ static int may_context_mount_sb_relabel(u32 sid, { int rc; - rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, + rc = avc_has_perm(tsec->actor_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(tsec->actor_sid, sid, SECCLASS_FILESYSTEM, FILESYSTEM__RELABELTO, NULL); return rc; } @@ -352,7 +353,7 @@ static int may_context_mount_inode_relabel(u32 sid, struct task_security_struct *tsec) { int rc; - rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, + rc = avc_has_perm(tsec->actor_sid, sbsec->sid, SECCLASS_FILESYSTEM, FILESYSTEM__RELABELFROM, NULL); if (rc) return rc; @@ -1031,7 +1032,7 @@ static int task_has_perm(struct task_struct *tsk1, tsec1 = tsk1->security; tsec2 = tsk2->security; - return avc_has_perm(tsec1->sid, tsec2->sid, + return avc_has_perm(tsec1->actor_sid, tsec2->sid, SECCLASS_PROCESS, perms, NULL); } @@ -1048,7 +1049,7 @@ static int task_has_capability(struct task_struct *tsk, ad.tsk = tsk; ad.u.cap = cap; - return avc_has_perm(tsec->sid, tsec->sid, + return avc_has_perm(tsec->actor_sid, tsec->actor_sid, SECCLASS_CAPABILITY, CAP_TO_MASK(cap), &ad); } @@ -1060,7 +1061,7 @@ static int task_has_system(struct task_struct *tsk, tsec = tsk->security; - return avc_has_perm(tsec->sid, SECINITSID_KERNEL, + return avc_has_perm(tsec->actor_sid, SECINITSID_KERNEL, SECCLASS_SYSTEM, perms, NULL); } @@ -1088,7 +1089,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(tsec->actor_sid, isec->sid, isec->sclass, perms, + adp); } /* Same as inode_has_perm, but pass explicit audit data containing @@ -1131,8 +1133,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 (tsec->actor_sid != fsec->sid) { + rc = avc_has_perm(tsec->actor_sid, fsec->sid, SECCLASS_FD, FD__USE, &ad); @@ -1166,7 +1168,7 @@ static int may_create(struct inode *dir, 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(tsec->actor_sid, dsec->sid, SECCLASS_DIR, DIR__ADD_NAME | DIR__SEARCH, &ad); if (rc) @@ -1175,13 +1177,13 @@ static int may_create(struct inode *dir, if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) { newsid = tsec->create_sid; } else { - rc = security_transition_sid(tsec->sid, dsec->sid, tclass, - &newsid); + rc = security_transition_sid(tsec->actor_sid, dsec->sid, + tclass, &newsid); if (rc) return rc; } - rc = avc_has_perm(tsec->sid, newsid, tclass, FILE__CREATE, &ad); + rc = avc_has_perm(tsec->actor_sid, newsid, tclass, FILE__CREATE, &ad); if (rc) return rc; @@ -1198,7 +1200,8 @@ static int may_create_key(u32 ksid, tsec = ctx->security; - return avc_has_perm(tsec->sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL); + return avc_has_perm(tsec->actor_sid, ksid, SECCLASS_KEY, KEY__CREATE, + NULL); } #define MAY_LINK 0 @@ -1226,7 +1229,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(tsec->actor_sid, dsec->sid, SECCLASS_DIR, av, &ad); if (rc) return rc; @@ -1245,7 +1248,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(tsec->actor_sid, isec->sid, isec->sclass, av, &ad); return rc; } @@ -1270,16 +1273,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(tsec->actor_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(tsec->actor_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(tsec->actor_sid, old_isec->sid, old_isec->sclass, DIR__REPARENT, &ad); if (rc) return rc; @@ -1289,15 +1292,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(tsec->actor_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(tsec->actor_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; } @@ -1316,7 +1321,7 @@ static int superblock_has_perm(struct task_struct *tsk, tsec = tsk->security; sbsec = sb->s_security; - return avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, + return avc_has_perm(tsec->actor_sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad); } @@ -1380,7 +1385,7 @@ 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; + csec->ptrace_sid = psec->actor_sid; return rc; } @@ -1490,7 +1495,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(tsec->actor_sid, tsid, SECCLASS_DIR, DIR__SEARCH, NULL); } else { av = 0; @@ -1499,7 +1504,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(tsec->actor_sid, tsid, SECCLASS_FILE, av, NULL); } @@ -1591,7 +1596,7 @@ static int selinux_vm_enough_memory(long pages) 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(tsec->actor_sid, tsec->actor_sid, SECCLASS_CAPABILITY, CAP_TO_MASK(CAP_SYS_ADMIN), 0, @@ -1644,7 +1649,7 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm) isec = inode->i_security; /* Default to the current task SID. */ - bsec->sid = tsec->sid; + bsec->sid = tsec->actor_sid; /* Reset fs, key, and sock SIDs on execve. */ tsec->create_sid = 0; @@ -1657,7 +1662,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(tsec->actor_sid, isec->sid, SECCLASS_PROCESS, &newsid); if (rc) return rc; @@ -1668,16 +1673,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 = tsec->actor_sid; - if (tsec->sid == newsid) { - rc = avc_has_perm(tsec->sid, isec->sid, + if (tsec->actor_sid == newsid) { + rc = avc_has_perm(tsec->actor_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(tsec->actor_sid, newsid, SECCLASS_PROCESS, PROCESS__TRANSITION, &ad); if (rc) return rc; @@ -1859,6 +1864,8 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) return; } } + if (tsec->actor_sid == tsec->sid) + tsec->actor_sid = sid; tsec->sid = sid; } } @@ -2133,7 +2140,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) { newsid = tsec->create_sid; } else { - rc = security_transition_sid(tsec->sid, dsec->sid, + rc = security_transition_sid(tsec->actor_sid, dsec->sid, inode_mode_to_security_class(inode->i_mode), &newsid); if (rc) { @@ -2324,7 +2331,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(tsec->actor_sid, isec->sid, isec->sclass, FILE__RELABELFROM, &ad); if (rc) return rc; @@ -2333,12 +2340,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(tsec->actor_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, tsec->actor_sid, isec->sclass); if (rc) return rc; @@ -2746,7 +2753,7 @@ static int selinux_task_alloc_security(struct task_struct *tsk) tsec2 = tsk->security; tsec2->osid = tsec1->osid; - tsec2->sid = tsec1->sid; + tsec2->actor_sid = tsec2->sid = tsec1->sid; /* Retain the exec, fs, key, and sock SIDs across fork */ tsec2->exec_sid = tsec1->exec_sid; @@ -2925,6 +2932,8 @@ static void selinux_task_reparent_to_init(struct task_struct *p) tsec = p->security; tsec->osid = tsec->sid; + if (tsec->actor_sid == tsec->sid) + tsec->actor_sid = SECINITSID_KERNEL; tsec->sid = SECINITSID_KERNEL; return; } @@ -3172,7 +3181,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(tsec->actor_sid, isec->sid, isec->sclass, perms, + &ad); out: return err; @@ -3189,8 +3199,8 @@ static int selinux_socket_create(int family, int type, goto out; tsec = current->security; - newsid = tsec->sockcreate_sid ? : tsec->sid; - err = avc_has_perm(tsec->sid, newsid, + newsid = tsec->sockcreate_sid ? : tsec->actor_sid; + err = avc_has_perm(tsec->actor_sid, newsid, socket_type_to_security_class(family, type, protocol), SOCKET__CREATE, NULL); @@ -3210,7 +3220,7 @@ static int selinux_socket_post_create(struct socket *sock, int family, isec = SOCK_INODE(sock)->i_security; tsec = current->security; - newsid = tsec->sockcreate_sid ? : tsec->sid; + newsid = tsec->sockcreate_sid ? : tsec->actor_sid; isec->sclass = socket_type_to_security_class(family, type, protocol); isec->sid = kern ? SECINITSID_KERNEL : newsid; isec->initialized = 1; @@ -4033,7 +4043,7 @@ static int ipc_alloc_security(struct task_struct *task, isec->sclass = sclass; isec->ipc_perm = perm; - isec->sid = tsec->sid; + isec->sid = tsec->actor_sid; perm->security = isec; return 0; @@ -4082,7 +4092,8 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms, 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(tsec->actor_sid, isec->sid, isec->sclass, perms, + &ad); } static int selinux_msg_msg_alloc_security(struct msg_msg *msg) @@ -4113,7 +4124,7 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq) 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(tsec->actor_sid, isec->sid, SECCLASS_MSGQ, MSGQ__CREATE, &ad); if (rc) { ipc_free_security(&msq->q_perm); @@ -4139,7 +4150,7 @@ static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg) 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(tsec->actor_sid, isec->sid, SECCLASS_MSGQ, MSGQ__ASSOCIATE, &ad); } @@ -4191,7 +4202,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(tsec->actor_sid, isec->sid, SECCLASS_MSG, &msec->sid); @@ -4203,11 +4214,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(tsec->actor_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(tsec->actor_sid, msec->sid, SECCLASS_MSG, MSG__SEND, &ad); if (!rc) /* Can the message be put in the queue? */ @@ -4234,10 +4245,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->actor_sid, isec->sid, SECCLASS_MSGQ, MSGQ__READ, &ad); if (!rc) - rc = avc_has_perm(tsec->sid, msec->sid, + rc = avc_has_perm(tsec->actor_sid, msec->sid, SECCLASS_MSG, MSG__RECEIVE, &ad); return rc; } @@ -4260,7 +4271,7 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp) 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(tsec->actor_sid, isec->sid, SECCLASS_SHM, SHM__CREATE, &ad); if (rc) { ipc_free_security(&shp->shm_perm); @@ -4286,7 +4297,7 @@ static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg) 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(tsec->actor_sid, isec->sid, SECCLASS_SHM, SHM__ASSOCIATE, &ad); } @@ -4359,7 +4370,7 @@ static int selinux_sem_alloc_security(struct sem_array *sma) 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(tsec->actor_sid, isec->sid, SECCLASS_SEM, SEM__CREATE, &ad); if (rc) { ipc_free_security(&sma->sem_perm); @@ -4385,7 +4396,7 @@ static int selinux_sem_associate(struct sem_array *sma, int semflg) 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(tsec->actor_sid, isec->sid, SECCLASS_SEM, SEM__ASSOCIATE, &ad); } @@ -4633,14 +4644,19 @@ 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) + if (!error) { + if (tsec->actor_sid == tsec->sid) + tsec->actor_sid = sid; tsec->sid = sid; + } task_unlock(p); avc_audit(tsec->ptrace_sid, sid, SECCLASS_PROCESS, PROCESS__PTRACE, &avd, error, NULL); if (error) return error; } else { + if (tsec->actor_sid == tsec->sid) + tsec->actor_sid = sid; tsec->sid = sid; task_unlock(p); } @@ -4678,6 +4694,24 @@ static u32 selinux_set_fscreate_secid(u32 secid) return oldsid; } +static u32 selinux_act_as_secid(u32 secid) +{ + struct task_security_struct *tsec = current->security; + u32 oldactor_sid = tsec->actor_sid; + + tsec->actor_sid = secid; + return oldactor_sid; +} + +static u32 selinux_act_as_self(void) +{ + struct task_security_struct *tsec = current->security; + u32 oldactor_sid = tsec->actor_sid; + + tsec->actor_sid = tsec->sid; + return oldactor_sid; +} + #ifdef CONFIG_KEYS static int selinux_key_alloc(struct key *k, struct task_struct *tsk, @@ -4727,7 +4761,7 @@ static int selinux_key_permission(key_ref_t key_ref, if (perm == 0) return 0; - return avc_has_perm(tsec->sid, ksec->sid, + return avc_has_perm(tsec->actor_sid, ksec->sid, SECCLASS_KEY, perm, NULL); } @@ -4862,6 +4896,8 @@ static struct security_operations selinux_ops = { .release_secctx = selinux_release_secctx, .get_fscreate_secid = selinux_get_fscreate_secid, .set_fscreate_secid = selinux_set_fscreate_secid, + .act_as_secid = selinux_act_as_secid, + .act_as_self = selinux_act_as_self, .unix_stream_connect = selinux_socket_unix_stream_connect, .unix_may_send = selinux_socket_unix_may_send, @@ -4927,7 +4963,7 @@ static __init int selinux_init(void) 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->actor_sid = tsec->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..884df98 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -31,6 +31,7 @@ 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 actor_sid; /* act-as SID (normally == sid) */ u32 exec_sid; /* exec SID */ u32 create_sid; /* fscreate SID */ u32 keycreate_sid; /* keycreate SID */ diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index c9e92da..8df8e6a 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -83,7 +83,7 @@ static int task_has_security(struct task_struct *tsk, if (!tsec) return -EACCES; - return avc_has_perm(tsec->sid, SECINITSID_SECURITY, + return avc_has_perm(tsec->actor_sid, SECINITSID_SECURITY, SECCLASS_SECURITY, perms, NULL); } diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index ba715f4..873b6ba 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->actor_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->actor_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->actor_sid, ctx->ctx_sid, SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, NULL); - To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html