From 8b6a5a37f87a414ef8636e36ec75accb27bb7508 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Wed, 29 Oct 2008 17:06:46 -0400 Subject: SELinux: check open perms in dentry_open not inode_permission Some operations, like searching a directory path or connecting a unix domain socket, make explicit calls into inode_permission. Our choices are to either try to come up with a signature for all of the explicit calls to inode_permission and do not check open on those, or to move the open checks to dentry_open where we know this is always an open operation. This patch moves the checks to dentry_open. Signed-off-by: Eric Paris Acked-by: Stephen Smalley Signed-off-by: James Morris --- security/selinux/hooks.c | 59 ++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 29 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index c679ba653e1..03ff7db2a2c 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1686,15 +1686,39 @@ static inline u32 file_mask_to_av(int mode, int mask) return av; } +/* Convert a Linux file to an access vector. */ +static inline u32 file_to_av(struct file *file) +{ + u32 av = 0; + + if (file->f_mode & FMODE_READ) + av |= FILE__READ; + if (file->f_mode & FMODE_WRITE) { + if (file->f_flags & O_APPEND) + av |= FILE__APPEND; + else + av |= FILE__WRITE; + } + if (!av) { + /* + * Special file opened with flags 3 for ioctl-only use. + */ + av = FILE__IOCTL; + } + + return av; +} + /* - * Convert a file mask to an access vector and include the correct open + * Convert a file to an access vector and include the correct open * open permission. */ -static inline u32 open_file_mask_to_av(int mode, int mask) +static inline u32 open_file_to_av(struct file *file) { - u32 av = file_mask_to_av(mode, mask); + u32 av = file_to_av(file); if (selinux_policycap_openperm) { + mode_t mode = file->f_path.dentry->d_inode->i_mode; /* * lnk files and socks do not really have an 'open' */ @@ -1710,34 +1734,11 @@ static inline u32 open_file_mask_to_av(int mode, int mask) av |= DIR__OPEN; else printk(KERN_ERR "SELinux: WARNING: inside %s with " - "unknown mode:%x\n", __func__, mode); + "unknown mode:%o\n", __func__, mode); } return av; } -/* Convert a Linux file to an access vector. */ -static inline u32 file_to_av(struct file *file) -{ - u32 av = 0; - - if (file->f_mode & FMODE_READ) - av |= FILE__READ; - if (file->f_mode & FMODE_WRITE) { - if (file->f_flags & O_APPEND) - av |= FILE__APPEND; - else - av |= FILE__WRITE; - } - if (!av) { - /* - * Special file opened with flags 3 for ioctl-only use. - */ - av = FILE__IOCTL; - } - - return av; -} - /* Hook functions begin here. */ static int selinux_ptrace_may_access(struct task_struct *child, @@ -2654,7 +2655,7 @@ static int selinux_inode_permission(struct inode *inode, int mask) } return inode_has_perm(current, inode, - open_file_mask_to_av(inode->i_mode, mask), NULL); + file_mask_to_av(inode->i_mode, mask), NULL); } static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) @@ -3170,7 +3171,7 @@ static int selinux_dentry_open(struct file *file) * new inode label or new policy. * This check is not redundant - do not remove. */ - return inode_has_perm(current, inode, file_to_av(file), NULL); + return inode_has_perm(current, inode, open_file_to_av(file), NULL); } /* task security operations */ -- cgit v1.2.3-18-g5258 From 41d9f9c524a53477467b7e0111ff3d644198f191 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Tue, 4 Nov 2008 15:18:26 -0500 Subject: SELinux: hold tasklist_lock and siglock while waking wait_chldexit SELinux has long been calling wake_up_interruptible() on current->parent->signal->wait_chldexit without holding any locks. It appears that this operation should hold the tasklist_lock to dereference current->parent and we should hold the siglock when waking up the signal->wait_chldexit. Signed-off-by: Eric Paris Signed-off-by: James Morris --- security/selinux/hooks.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 03ff7db2a2c..5f21a514f58 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2268,7 +2268,9 @@ static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm) struct rlimit *rlim, *initrlim; struct itimerval itimer; struct bprm_security_struct *bsec; + struct sighand_struct *psig; int rc, i; + unsigned long flags; tsec = current->security; bsec = bprm->security; @@ -2335,7 +2337,12 @@ static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm) /* Wake up the parent if it is waiting so that it can recheck wait permission to the new task SID. */ + read_lock_irq(&tasklist_lock); + psig = current->parent->sighand; + spin_lock_irqsave(&psig->siglock, flags); wake_up_interruptible(¤t->parent->signal->wait_chldexit); + spin_unlock_irqrestore(&psig->siglock, flags); + read_unlock_irq(&tasklist_lock); } /* superblock security operations */ -- cgit v1.2.3-18-g5258 From 39c9aede2b4a252bd296c0a86be832c3d3d0a273 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Wed, 5 Nov 2008 09:34:42 -0500 Subject: SELinux: Use unknown perm handling to handle unknown netlink msg types Currently when SELinux has not been updated to handle a netlink message type the operation is denied with EINVAL. This patch will leave the audit/warning message so things get fixed but if policy chose to allow unknowns this will allow the netlink operation. Signed-off-by: Eric Paris Acked-by: Stephen Smalley Signed-off-by: James Morris --- security/selinux/hooks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index f71de5a64d0..7fd4de46b2a 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4395,7 +4395,7 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) "SELinux: unrecognized netlink message" " type=%hu for sclass=%hu\n", nlh->nlmsg_type, isec->sclass); - if (!selinux_enforcing) + if (!selinux_enforcing || security_get_allow_unknown()) err = 0; } -- cgit v1.2.3-18-g5258 From 06112163f5fd9e491a7f810443d81efa9d88e247 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Tue, 11 Nov 2008 22:02:50 +1100 Subject: Add a new capable interface that will be used by systems that use audit to make an A or B type decision instead of a security decision. Currently this is the case at least for filesystems when deciding if a process can use the reserved 'root' blocks and for the case of things like the oom algorithm determining if processes are root processes and should be less likely to be killed. These types of security system requests should not be audited or logged since they are not really security decisions. It would be possible to solve this problem like the vm_enough_memory security check did by creating a new LSM interface and moving all of the policy into that interface but proves the needlessly bloat the LSM and provide complex indirection. This merely allows those decisions to be made where they belong and to not flood logs or printk with denials for thing that are not security decisions. Signed-off-by: Eric Paris Acked-by: Stephen Smalley Signed-off-by: James Morris --- security/selinux/hooks.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 7fd4de46b2a..88a3ee33068 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1365,12 +1365,14 @@ static int task_has_perm(struct task_struct *tsk1, /* Check whether a task is allowed to use a capability. */ static int task_has_capability(struct task_struct *tsk, - int cap) + int cap, int audit) { struct task_security_struct *tsec; struct avc_audit_data ad; + struct av_decision avd; u16 sclass; u32 av = CAP_TO_MASK(cap); + int rc; tsec = tsk->security; @@ -1390,7 +1392,11 @@ static int task_has_capability(struct task_struct *tsk, "SELinux: out of range capability %d\n", cap); BUG(); } - return avc_has_perm(tsec->sid, tsec->sid, sclass, av, &ad); + + rc = avc_has_perm_noaudit(tsec->sid, tsec->sid, sclass, av, 0, &avd); + if (audit == SECURITY_CAP_AUDIT) + avc_audit(tsec->sid, tsec->sid, sclass, av, &avd, rc, &ad); + return rc; } /* Check whether a task is allowed to use a system operation. */ @@ -1802,15 +1808,15 @@ static void selinux_capset_set(struct task_struct *target, kernel_cap_t *effecti secondary_ops->capset_set(target, effective, inheritable, permitted); } -static int selinux_capable(struct task_struct *tsk, int cap) +static int selinux_capable(struct task_struct *tsk, int cap, int audit) { int rc; - rc = secondary_ops->capable(tsk, cap); + rc = secondary_ops->capable(tsk, cap, audit); if (rc) return rc; - return task_has_capability(tsk, cap); + return task_has_capability(tsk, cap, audit); } static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid) @@ -1975,7 +1981,7 @@ 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; - rc = secondary_ops->capable(current, CAP_SYS_ADMIN); + rc = secondary_ops->capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT); if (rc == 0) rc = avc_has_perm_noaudit(tsec->sid, tsec->sid, SECCLASS_CAPABILITY, @@ -2829,7 +2835,7 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name * and lack of permission just means that we fall back to the * in-core context value, not a denial. */ - error = secondary_ops->capable(current, CAP_MAC_ADMIN); + error = secondary_ops->capable(current, CAP_MAC_ADMIN, SECURITY_CAP_NOAUDIT); if (!error) error = avc_has_perm_noaudit(tsec->sid, tsec->sid, SECCLASS_CAPABILITY2, -- cgit v1.2.3-18-g5258 From 066746796bd2f0a1ba210c0dded3b6ee4032692a Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Tue, 11 Nov 2008 22:02:57 +1100 Subject: Currently SELinux jumps through some ugly hoops to not audit a capbility check when determining if a process has additional powers to override memory limits or when trying to read/write illegal file labels. Use the new noaudit call instead. Signed-off-by: Eric Paris Acked-by: Stephen Smalley Signed-off-by: James Morris --- security/selinux/hooks.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 88a3ee33068..378dc53c08e 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1979,16 +1979,8 @@ 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; - - rc = secondary_ops->capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT); - if (rc == 0) - rc = avc_has_perm_noaudit(tsec->sid, tsec->sid, - SECCLASS_CAPABILITY, - CAP_TO_MASK(CAP_SYS_ADMIN), - 0, - NULL); + rc = selinux_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT); if (rc == 0) cap_sys_admin = 1; @@ -2820,7 +2812,6 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name u32 size; int error; char *context = NULL; - struct task_security_struct *tsec = current->security; struct inode_security_struct *isec = inode->i_security; if (strcmp(name, XATTR_SELINUX_SUFFIX)) @@ -2835,13 +2826,7 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name * and lack of permission just means that we fall back to the * in-core context value, not a denial. */ - error = secondary_ops->capable(current, CAP_MAC_ADMIN, SECURITY_CAP_NOAUDIT); - if (!error) - error = avc_has_perm_noaudit(tsec->sid, tsec->sid, - SECCLASS_CAPABILITY2, - CAPABILITY2__MAC_ADMIN, - 0, - NULL); + error = selinux_capable(current, CAP_MAC_ADMIN, SECURITY_CAP_NOAUDIT); if (!error) error = security_sid_to_context_force(isec->sid, &context, &size); -- cgit v1.2.3-18-g5258 From 1cdcbec1a3372c0c49c59d292e708fd07b509f18 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 14 Nov 2008 10:39:14 +1100 Subject: CRED: Neuter sys_capset() Take away the ability for sys_capset() to affect processes other than current. This means that current will not need to lock its own credentials when reading them against interference by other processes. This has effectively been the case for a while anyway, since: (1) Without LSM enabled, sys_capset() is disallowed. (2) With file-based capabilities, sys_capset() is neutered. Signed-off-by: David Howells Acked-by: Serge Hallyn Acked-by: Andrew G. Morgan Acked-by: James Morris Signed-off-by: James Morris --- security/selinux/hooks.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 378dc53c08e..df9986940e9 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1790,22 +1790,22 @@ static int selinux_capget(struct task_struct *target, kernel_cap_t *effective, return secondary_ops->capget(target, effective, inheritable, permitted); } -static int selinux_capset_check(struct task_struct *target, kernel_cap_t *effective, +static int selinux_capset_check(kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted) { int error; - error = secondary_ops->capset_check(target, effective, inheritable, permitted); + error = secondary_ops->capset_check(effective, inheritable, permitted); if (error) return error; - return task_has_perm(current, target, PROCESS__SETCAP); + return task_has_perm(current, current, PROCESS__SETCAP); } -static void selinux_capset_set(struct task_struct *target, kernel_cap_t *effective, +static void selinux_capset_set(kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted) { - secondary_ops->capset_set(target, effective, inheritable, permitted); + secondary_ops->capset_set(effective, inheritable, permitted); } static int selinux_capable(struct task_struct *tsk, int cap, int audit) -- cgit v1.2.3-18-g5258 From 15a2460ed0af7538ca8e6c610fe607a2cd9da142 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 14 Nov 2008 10:39:15 +1100 Subject: CRED: Constify the kernel_cap_t arguments to the capset LSM hooks Constify the kernel_cap_t arguments to the capset LSM hooks. Signed-off-by: David Howells Acked-by: Serge Hallyn Acked-by: James Morris Signed-off-by: James Morris --- security/selinux/hooks.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index df9986940e9..9f6da154cc8 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1790,8 +1790,9 @@ static int selinux_capget(struct task_struct *target, kernel_cap_t *effective, return secondary_ops->capget(target, effective, inheritable, permitted); } -static int selinux_capset_check(kernel_cap_t *effective, - kernel_cap_t *inheritable, kernel_cap_t *permitted) +static int selinux_capset_check(const kernel_cap_t *effective, + const kernel_cap_t *inheritable, + const kernel_cap_t *permitted) { int error; @@ -1802,8 +1803,9 @@ static int selinux_capset_check(kernel_cap_t *effective, return task_has_perm(current, current, PROCESS__SETCAP); } -static void selinux_capset_set(kernel_cap_t *effective, - kernel_cap_t *inheritable, kernel_cap_t *permitted) +static void selinux_capset_set(const kernel_cap_t *effective, + const kernel_cap_t *inheritable, + const kernel_cap_t *permitted) { secondary_ops->capset_set(effective, inheritable, permitted); } -- cgit v1.2.3-18-g5258 From b6dff3ec5e116e3af6f537d4caedcad6b9e5082a Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 14 Nov 2008 10:39:16 +1100 Subject: CRED: Separate task security context from task_struct Separate the task security context from task_struct. At this point, the security data is temporarily embedded in the task_struct with two pointers pointing to it. Note that the Alpha arch is altered as it refers to (E)UID and (E)GID in entry.S via asm-offsets. With comment fixes Signed-off-by: Marc Dionne Signed-off-by: David Howells Acked-by: James Morris Acked-by: Serge Hallyn Signed-off-by: James Morris --- security/selinux/hooks.c | 116 ++++++++++++++++++++++++----------------------- 1 file changed, 59 insertions(+), 57 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 9f6da154cc8..328308f2882 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -167,21 +167,21 @@ static int task_alloc_security(struct task_struct *task) return -ENOMEM; tsec->osid = tsec->sid = SECINITSID_UNLABELED; - task->security = tsec; + task->cred->security = tsec; return 0; } static void task_free_security(struct task_struct *task) { - struct task_security_struct *tsec = task->security; - task->security = NULL; + struct task_security_struct *tsec = task->cred->security; + task->cred->security = NULL; kfree(tsec); } static int inode_alloc_security(struct inode *inode) { - struct task_security_struct *tsec = current->security; + struct task_security_struct *tsec = current->cred->security; struct inode_security_struct *isec; isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS); @@ -215,7 +215,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 task_security_struct *tsec = current->cred->security; struct file_security_struct *fsec; fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL); @@ -554,7 +554,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *opts) { int rc = 0, i; - struct task_security_struct *tsec = current->security; + struct task_security_struct *tsec = current->cred->security; struct superblock_security_struct *sbsec = sb->s_security; const char *name = sb->s_type->name; struct inode *inode = sbsec->sb->s_root->d_inode; @@ -1353,8 +1353,8 @@ static int task_has_perm(struct task_struct *tsk1, { struct task_security_struct *tsec1, *tsec2; - tsec1 = tsk1->security; - tsec2 = tsk2->security; + tsec1 = tsk1->cred->security; + tsec2 = tsk2->cred->security; return avc_has_perm(tsec1->sid, tsec2->sid, SECCLASS_PROCESS, perms, NULL); } @@ -1374,7 +1374,7 @@ static int task_has_capability(struct task_struct *tsk, u32 av = CAP_TO_MASK(cap); int rc; - tsec = tsk->security; + tsec = tsk->cred->security; AVC_AUDIT_DATA_INIT(&ad, CAP); ad.tsk = tsk; @@ -1405,7 +1405,7 @@ static int task_has_system(struct task_struct *tsk, { struct task_security_struct *tsec; - tsec = tsk->security; + tsec = tsk->cred->security; return avc_has_perm(tsec->sid, SECINITSID_KERNEL, SECCLASS_SYSTEM, perms, NULL); @@ -1426,7 +1426,7 @@ static int inode_has_perm(struct task_struct *tsk, if (unlikely(IS_PRIVATE(inode))) return 0; - tsec = tsk->security; + tsec = tsk->cred->security; isec = inode->i_security; if (!adp) { @@ -1466,7 +1466,7 @@ static int file_has_perm(struct task_struct *tsk, struct file *file, u32 av) { - struct task_security_struct *tsec = tsk->security; + struct task_security_struct *tsec = tsk->cred->security; struct file_security_struct *fsec = file->f_security; struct inode *inode = file->f_path.dentry->d_inode; struct avc_audit_data ad; @@ -1503,7 +1503,7 @@ static int may_create(struct inode *dir, struct avc_audit_data ad; int rc; - tsec = current->security; + tsec = current->cred->security; dsec = dir->i_security; sbsec = dir->i_sb->s_security; @@ -1540,7 +1540,7 @@ static int may_create_key(u32 ksid, { struct task_security_struct *tsec; - tsec = ctx->security; + tsec = ctx->cred->security; return avc_has_perm(tsec->sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL); } @@ -1561,7 +1561,7 @@ static int may_link(struct inode *dir, u32 av; int rc; - tsec = current->security; + tsec = current->cred->security; dsec = dir->i_security; isec = dentry->d_inode->i_security; @@ -1606,7 +1606,7 @@ static inline int may_rename(struct inode *old_dir, int old_is_dir, new_is_dir; int rc; - tsec = current->security; + tsec = 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); @@ -1659,7 +1659,7 @@ static int superblock_has_perm(struct task_struct *tsk, struct task_security_struct *tsec; struct superblock_security_struct *sbsec; - tsec = tsk->security; + tsec = tsk->cred->security; sbsec = sb->s_security; return avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad); @@ -1758,8 +1758,8 @@ static int selinux_ptrace_may_access(struct task_struct *child, return rc; if (mode == PTRACE_MODE_READ) { - struct task_security_struct *tsec = current->security; - struct task_security_struct *csec = child->security; + struct task_security_struct *tsec = current->cred->security; + struct task_security_struct *csec = child->cred->security; return avc_has_perm(tsec->sid, csec->sid, SECCLASS_FILE, FILE__READ, NULL); } @@ -1874,7 +1874,7 @@ static int selinux_sysctl(ctl_table *table, int op) if (rc) return rc; - tsec = current->security; + tsec = current->cred->security; rc = selinux_sysctl_get_sid(table, (op == 0001) ? SECCLASS_DIR : SECCLASS_FILE, &tsid); @@ -2025,7 +2025,7 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm) if (bsec->set) return 0; - tsec = current->security; + tsec = current->cred->security; isec = inode->i_security; /* Default to the current task SID. */ @@ -2090,7 +2090,7 @@ static int selinux_bprm_check_security(struct linux_binprm *bprm) static int selinux_bprm_secureexec(struct linux_binprm *bprm) { - struct task_security_struct *tsec = current->security; + struct task_security_struct *tsec = current->cred->security; int atsecure = 0; if (tsec->osid != tsec->sid) { @@ -2214,7 +2214,7 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) secondary_ops->bprm_apply_creds(bprm, unsafe); - tsec = current->security; + tsec = current->cred->security; bsec = bprm->security; sid = bsec->sid; @@ -2243,7 +2243,7 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) rcu_read_lock(); tracer = tracehook_tracer_task(current); if (likely(tracer != NULL)) { - sec = tracer->security; + sec = tracer->cred->security; ptsid = sec->sid; } rcu_read_unlock(); @@ -2274,7 +2274,7 @@ static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm) int rc, i; unsigned long flags; - tsec = current->security; + tsec = current->cred->security; bsec = bprm->security; if (bsec->unsafe) { @@ -2521,7 +2521,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, int rc; char *namep = NULL, *context; - tsec = current->security; + tsec = current->cred->security; dsec = dir->i_security; sbsec = dir->i_sb->s_security; @@ -2706,7 +2706,7 @@ static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name) static int selinux_inode_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - struct task_security_struct *tsec = current->security; + struct task_security_struct *tsec = current->cred->security; struct inode *inode = dentry->d_inode; struct inode_security_struct *isec = inode->i_security; struct superblock_security_struct *sbsec; @@ -2918,7 +2918,7 @@ static int selinux_revalidate_file_permission(struct file *file, int mask) static int selinux_file_permission(struct file *file, int mask) { struct inode *inode = file->f_path.dentry->d_inode; - struct task_security_struct *tsec = current->security; + struct task_security_struct *tsec = current->cred->security; struct file_security_struct *fsec = file->f_security; struct inode_security_struct *isec = inode->i_security; @@ -2995,7 +2995,8 @@ static int selinux_file_mmap(struct file *file, unsigned long reqprot, unsigned long addr, unsigned long addr_only) { int rc = 0; - u32 sid = ((struct task_security_struct *)(current->security))->sid; + u32 sid = ((struct task_security_struct *) + (current->cred->security))->sid; if (addr < mmap_min_addr) rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT, @@ -3107,7 +3108,7 @@ static int selinux_file_set_fowner(struct file *file) struct task_security_struct *tsec; struct file_security_struct *fsec; - tsec = current->security; + tsec = current->cred->security; fsec = file->f_security; fsec->fown_sid = tsec->sid; @@ -3125,7 +3126,7 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk, /* struct fown_struct is never outside the context of a struct file */ file = container_of(fown, struct file, f_owner); - tsec = tsk->security; + tsec = tsk->cred->security; fsec = file->f_security; if (!signum) @@ -3188,12 +3189,12 @@ static int selinux_task_alloc_security(struct task_struct *tsk) struct task_security_struct *tsec1, *tsec2; int rc; - tsec1 = current->security; + tsec1 = current->cred->security; rc = task_alloc_security(tsk); if (rc) return rc; - tsec2 = tsk->security; + tsec2 = tsk->cred->security; tsec2->osid = tsec1->osid; tsec2->sid = tsec1->sid; @@ -3251,7 +3252,7 @@ static int selinux_task_getsid(struct task_struct *p) static void selinux_task_getsecid(struct task_struct *p, u32 *secid) { - struct task_security_struct *tsec = p->security; + struct task_security_struct *tsec = p->cred->security; *secid = tsec->sid; } @@ -3343,7 +3344,7 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info, perm = PROCESS__SIGNULL; /* null signal; existence test */ else perm = signal_to_av(sig); - tsec = p->security; + tsec = p->cred->security; if (secid) rc = avc_has_perm(secid, tsec->sid, SECCLASS_PROCESS, perm, NULL); else @@ -3375,7 +3376,7 @@ static void selinux_task_reparent_to_init(struct task_struct *p) secondary_ops->task_reparent_to_init(p); - tsec = p->security; + tsec = p->cred->security; tsec->osid = tsec->sid; tsec->sid = SECINITSID_KERNEL; return; @@ -3384,7 +3385,7 @@ static void selinux_task_reparent_to_init(struct task_struct *p) static void selinux_task_to_inode(struct task_struct *p, struct inode *inode) { - struct task_security_struct *tsec = p->security; + struct task_security_struct *tsec = p->cred->security; struct inode_security_struct *isec = inode->i_security; isec->sid = tsec->sid; @@ -3632,7 +3633,7 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock, struct avc_audit_data ad; int err = 0; - tsec = task->security; + tsec = task->cred->security; isec = SOCK_INODE(sock)->i_security; if (isec->sid == SECINITSID_KERNEL) @@ -3656,7 +3657,7 @@ static int selinux_socket_create(int family, int type, if (kern) goto out; - tsec = current->security; + tsec = current->cred->security; newsid = tsec->sockcreate_sid ? : tsec->sid; err = avc_has_perm(tsec->sid, newsid, socket_type_to_security_class(family, type, @@ -3677,7 +3678,7 @@ static int selinux_socket_post_create(struct socket *sock, int family, isec = SOCK_INODE(sock)->i_security; - tsec = current->security; + tsec = current->cred->security; newsid = tsec->sockcreate_sid ? : tsec->sid; isec->sclass = socket_type_to_security_class(family, type, protocol); isec->sid = kern ? SECINITSID_KERNEL : newsid; @@ -3723,7 +3724,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in struct sock *sk = sock->sk; u32 sid, node_perm; - tsec = current->security; + tsec = current->cred->security; isec = SOCK_INODE(sock)->i_security; if (family == PF_INET) { @@ -4764,7 +4765,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 task_security_struct *tsec = task->cred->security; struct ipc_security_struct *isec; isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL); @@ -4814,7 +4815,7 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms, struct ipc_security_struct *isec; struct avc_audit_data ad; - tsec = current->security; + tsec = current->cred->security; isec = ipc_perms->security; AVC_AUDIT_DATA_INIT(&ad, IPC); @@ -4845,7 +4846,7 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq) if (rc) return rc; - tsec = current->security; + tsec = current->cred->security; isec = msq->q_perm.security; AVC_AUDIT_DATA_INIT(&ad, IPC); @@ -4871,7 +4872,7 @@ static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg) struct ipc_security_struct *isec; struct avc_audit_data ad; - tsec = current->security; + tsec = current->cred->security; isec = msq->q_perm.security; AVC_AUDIT_DATA_INIT(&ad, IPC); @@ -4917,7 +4918,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, struct avc_audit_data ad; int rc; - tsec = current->security; + tsec = current->cred->security; isec = msq->q_perm.security; msec = msg->security; @@ -4965,7 +4966,7 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg, struct avc_audit_data ad; int rc; - tsec = target->security; + tsec = target->cred->security; isec = msq->q_perm.security; msec = msg->security; @@ -4992,7 +4993,7 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp) if (rc) return rc; - tsec = current->security; + tsec = current->cred->security; isec = shp->shm_perm.security; AVC_AUDIT_DATA_INIT(&ad, IPC); @@ -5018,7 +5019,7 @@ static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg) struct ipc_security_struct *isec; struct avc_audit_data ad; - tsec = current->security; + tsec = current->cred->security; isec = shp->shm_perm.security; AVC_AUDIT_DATA_INIT(&ad, IPC); @@ -5091,7 +5092,7 @@ static int selinux_sem_alloc_security(struct sem_array *sma) if (rc) return rc; - tsec = current->security; + tsec = current->cred->security; isec = sma->sem_perm.security; AVC_AUDIT_DATA_INIT(&ad, IPC); @@ -5117,7 +5118,7 @@ static int selinux_sem_associate(struct sem_array *sma, int semflg) struct ipc_security_struct *isec; struct avc_audit_data ad; - tsec = current->security; + tsec = current->cred->security; isec = sma->sem_perm.security; AVC_AUDIT_DATA_INIT(&ad, IPC); @@ -5224,7 +5225,7 @@ static int selinux_getprocattr(struct task_struct *p, return error; } - tsec = p->security; + tsec = p->cred->security; if (!strcmp(name, "current")) sid = tsec->sid; @@ -5308,7 +5309,7 @@ static int selinux_setprocattr(struct task_struct *p, operation. See selinux_bprm_set_security for the execve checks and may_create for the file creation checks. The operation will then fail if the context is not permitted. */ - tsec = p->security; + tsec = p->cred->security; if (!strcmp(name, "exec")) tsec->exec_sid = sid; else if (!strcmp(name, "fscreate")) @@ -5361,7 +5362,8 @@ boundary_ok: rcu_read_lock(); tracer = tracehook_tracer_task(p); if (tracer != NULL) { - struct task_security_struct *ptsec = tracer->security; + struct task_security_struct *ptsec = + tracer->cred->security; u32 ptsid = ptsec->sid; rcu_read_unlock(); error = avc_has_perm_noaudit(ptsid, sid, @@ -5405,7 +5407,7 @@ 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 task_security_struct *tsec = tsk->cred->security; struct key_security_struct *ksec; ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL); @@ -5439,7 +5441,7 @@ static int selinux_key_permission(key_ref_t key_ref, key = key_ref_to_ptr(key_ref); - tsec = ctx->security; + tsec = ctx->cred->security; ksec = key->security; /* if no specific permissions are requested, we skip the @@ -5683,7 +5685,7 @@ static __init int selinux_init(void) /* 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 = current->cred->security; tsec->osid = tsec->sid = SECINITSID_KERNEL; sel_inode_cache = kmem_cache_create("selinux_inode_security", -- cgit v1.2.3-18-g5258 From f1752eec6145c97163dbce62d17cf5d928e28a27 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 14 Nov 2008 10:39:17 +1100 Subject: CRED: Detach the credentials from task_struct Detach the credentials from task_struct, duplicating them in copy_process() and releasing them in __put_task_struct(). Signed-off-by: David Howells Acked-by: James Morris Acked-by: Serge Hallyn Signed-off-by: James Morris --- security/selinux/hooks.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 328308f2882..658435dce37 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -158,7 +158,7 @@ static int selinux_secmark_enabled(void) /* Allocate and free functions for each kind of security blob. */ -static int task_alloc_security(struct task_struct *task) +static int cred_alloc_security(struct cred *cred) { struct task_security_struct *tsec; @@ -167,18 +167,11 @@ static int task_alloc_security(struct task_struct *task) return -ENOMEM; tsec->osid = tsec->sid = SECINITSID_UNLABELED; - task->cred->security = tsec; + cred->security = tsec; return 0; } -static void task_free_security(struct task_struct *task) -{ - struct task_security_struct *tsec = task->cred->security; - task->cred->security = NULL; - kfree(tsec); -} - static int inode_alloc_security(struct inode *inode) { struct task_security_struct *tsec = current->cred->security; @@ -3184,17 +3177,17 @@ static int selinux_task_create(unsigned long clone_flags) return task_has_perm(current, current, PROCESS__FORK); } -static int selinux_task_alloc_security(struct task_struct *tsk) +static int selinux_cred_alloc_security(struct cred *cred) { struct task_security_struct *tsec1, *tsec2; int rc; tsec1 = current->cred->security; - rc = task_alloc_security(tsk); + rc = cred_alloc_security(cred); if (rc) return rc; - tsec2 = tsk->cred->security; + tsec2 = cred->security; tsec2->osid = tsec1->osid; tsec2->sid = tsec1->sid; @@ -3208,9 +3201,14 @@ static int selinux_task_alloc_security(struct task_struct *tsk) return 0; } -static void selinux_task_free_security(struct task_struct *tsk) +/* + * detach and free the LSM part of a set of credentials + */ +static void selinux_cred_free(struct cred *cred) { - task_free_security(tsk); + struct task_security_struct *tsec = cred->security; + cred->security = NULL; + kfree(tsec); } static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) @@ -5552,8 +5550,8 @@ static struct security_operations selinux_ops = { .dentry_open = selinux_dentry_open, .task_create = selinux_task_create, - .task_alloc_security = selinux_task_alloc_security, - .task_free_security = selinux_task_free_security, + .cred_alloc_security = selinux_cred_alloc_security, + .cred_free = selinux_cred_free, .task_setuid = selinux_task_setuid, .task_post_setuid = selinux_task_post_setuid, .task_setgid = selinux_task_setgid, @@ -5683,7 +5681,7 @@ static __init int selinux_init(void) printk(KERN_INFO "SELinux: Initializing.\n"); /* Set the security state for the initial task. */ - if (task_alloc_security(current)) + if (cred_alloc_security(current->cred)) panic("SELinux: Failed to initialize initial task.\n"); tsec = current->cred->security; tsec->osid = tsec->sid = SECINITSID_KERNEL; -- cgit v1.2.3-18-g5258 From 275bb41e9d058fbb327e7642f077e1beaeac162e Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 14 Nov 2008 10:39:19 +1100 Subject: CRED: Wrap access to SELinux's task SID Wrap access to SELinux's task SID, using task_sid() and current_sid() as appropriate. Signed-off-by: David Howells Acked-by: James Morris Signed-off-by: James Morris --- security/selinux/hooks.c | 412 +++++++++++++++++++++++++---------------------- 1 file changed, 218 insertions(+), 194 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 658435dce37..3f3de565c24 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -172,10 +172,35 @@ static int cred_alloc_security(struct cred *cred) return 0; } +/* + * get the security ID of a task + */ +static inline u32 task_sid(const struct task_struct *task) +{ + const struct task_security_struct *tsec; + u32 sid; + + rcu_read_lock(); + tsec = __task_cred(task)->security; + sid = tsec->sid; + rcu_read_unlock(); + return sid; +} + +/* + * get the security ID of the current task + */ +static inline u32 current_sid(void) +{ + const struct task_security_struct *tsec = current_cred()->security; + + return tsec->sid; +} + static int inode_alloc_security(struct inode *inode) { - struct task_security_struct *tsec = current->cred->security; struct inode_security_struct *isec; + u32 sid = current_sid(); isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS); if (!isec) @@ -186,7 +211,7 @@ static int inode_alloc_security(struct inode *inode) isec->inode = inode; isec->sid = SECINITSID_UNLABELED; isec->sclass = SECCLASS_FILE; - isec->task_sid = tsec->sid; + isec->task_sid = sid; inode->i_security = isec; return 0; @@ -208,15 +233,15 @@ static void inode_free_security(struct inode *inode) static int file_alloc_security(struct file *file) { - struct task_security_struct *tsec = current->cred->security; struct file_security_struct *fsec; + u32 sid = current_sid(); fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL); if (!fsec) return -ENOMEM; - fsec->sid = tsec->sid; - fsec->fown_sid = tsec->sid; + fsec->sid = sid; + fsec->fown_sid = sid; file->f_security = fsec; return 0; @@ -331,8 +356,9 @@ static const match_table_t tokens = { static int may_context_mount_sb_relabel(u32 sid, struct superblock_security_struct *sbsec, - struct task_security_struct *tsec) + const struct cred *cred) { + const struct task_security_struct *tsec = cred->security; int rc; rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, @@ -347,8 +373,9 @@ static int may_context_mount_sb_relabel(u32 sid, static int may_context_mount_inode_relabel(u32 sid, struct superblock_security_struct *sbsec, - struct task_security_struct *tsec) + const struct cred *cred) { + const struct task_security_struct *tsec = cred->security; int rc; rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, FILESYSTEM__RELABELFROM, NULL); @@ -546,8 +573,8 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag, static int selinux_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *opts) { + const struct cred *cred = current_cred(); int rc = 0, i; - struct task_security_struct *tsec = current->cred->security; struct superblock_security_struct *sbsec = sb->s_security; const char *name = sb->s_type->name; struct inode *inode = sbsec->sb->s_root->d_inode; @@ -673,8 +700,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, /* sets the context of the superblock for the fs being mounted. */ if (fscontext_sid) { - - rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, tsec); + rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred); if (rc) goto out; @@ -688,12 +714,14 @@ static int selinux_set_mnt_opts(struct super_block *sb, */ if (context_sid) { if (!fscontext_sid) { - rc = may_context_mount_sb_relabel(context_sid, sbsec, tsec); + rc = may_context_mount_sb_relabel(context_sid, sbsec, + cred); if (rc) goto out; sbsec->sid = context_sid; } else { - rc = may_context_mount_inode_relabel(context_sid, sbsec, tsec); + rc = may_context_mount_inode_relabel(context_sid, sbsec, + cred); if (rc) goto out; } @@ -705,7 +733,8 @@ static int selinux_set_mnt_opts(struct super_block *sb, } if (rootcontext_sid) { - rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec, tsec); + rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec, + cred); if (rc) goto out; @@ -723,7 +752,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, if (defcontext_sid != sbsec->def_sid) { rc = may_context_mount_inode_relabel(defcontext_sid, - sbsec, tsec); + sbsec, cred); if (rc) goto out; } @@ -1338,18 +1367,23 @@ static inline u32 signal_to_av(int sig) return perm; } -/* Check permission betweeen a pair of tasks, e.g. signal checks, - fork check, ptrace check, etc. */ -static int task_has_perm(struct task_struct *tsk1, - struct task_struct *tsk2, +/* + * Check permission betweeen a pair of tasks, e.g. signal checks, + * fork check, ptrace check, etc. + * tsk1 is the actor and tsk2 is the target + */ +static int task_has_perm(const struct task_struct *tsk1, + const struct task_struct *tsk2, u32 perms) { - struct task_security_struct *tsec1, *tsec2; + const struct task_security_struct *__tsec1, *__tsec2; + u32 sid1, sid2; - tsec1 = tsk1->cred->security; - tsec2 = tsk2->cred->security; - return avc_has_perm(tsec1->sid, tsec2->sid, - SECCLASS_PROCESS, perms, NULL); + rcu_read_lock(); + __tsec1 = __task_cred(tsk1)->security; sid1 = __tsec1->sid; + __tsec2 = __task_cred(tsk2)->security; sid2 = __tsec2->sid; + rcu_read_unlock(); + return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL); } #if CAP_LAST_CAP > 63 @@ -1360,15 +1394,13 @@ static int task_has_perm(struct task_struct *tsk1, static int task_has_capability(struct task_struct *tsk, int cap, int audit) { - struct task_security_struct *tsec; struct avc_audit_data ad; struct av_decision avd; u16 sclass; + u32 sid = task_sid(tsk); u32 av = CAP_TO_MASK(cap); int rc; - tsec = tsk->cred->security; - AVC_AUDIT_DATA_INIT(&ad, CAP); ad.tsk = tsk; ad.u.cap = cap; @@ -1386,9 +1418,9 @@ static int task_has_capability(struct task_struct *tsk, BUG(); } - rc = avc_has_perm_noaudit(tsec->sid, tsec->sid, sclass, av, 0, &avd); + rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd); if (audit == SECURITY_CAP_AUDIT) - avc_audit(tsec->sid, tsec->sid, sclass, av, &avd, rc, &ad); + avc_audit(sid, sid, sclass, av, &avd, rc, &ad); return rc; } @@ -1396,11 +1428,9 @@ static int task_has_capability(struct task_struct *tsk, static int task_has_system(struct task_struct *tsk, u32 perms) { - struct task_security_struct *tsec; - - tsec = tsk->cred->security; + u32 sid = task_sid(tsk); - return avc_has_perm(tsec->sid, SECINITSID_KERNEL, + return avc_has_perm(sid, SECINITSID_KERNEL, SECCLASS_SYSTEM, perms, NULL); } @@ -1412,14 +1442,14 @@ static int inode_has_perm(struct task_struct *tsk, u32 perms, struct avc_audit_data *adp) { - struct task_security_struct *tsec; struct inode_security_struct *isec; struct avc_audit_data ad; + u32 sid; if (unlikely(IS_PRIVATE(inode))) return 0; - tsec = tsk->cred->security; + sid = task_sid(tsk); isec = inode->i_security; if (!adp) { @@ -1428,7 +1458,7 @@ static int inode_has_perm(struct task_struct *tsk, ad.u.fs.inode = inode; } - return avc_has_perm(tsec->sid, isec->sid, isec->sclass, perms, adp); + return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp); } /* Same as inode_has_perm, but pass explicit audit data containing @@ -1459,17 +1489,17 @@ static int file_has_perm(struct task_struct *tsk, struct file *file, u32 av) { - struct task_security_struct *tsec = tsk->cred->security; struct file_security_struct *fsec = file->f_security; struct inode *inode = file->f_path.dentry->d_inode; struct avc_audit_data ad; + u32 sid = task_sid(tsk); int rc; AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path = file->f_path; - if (tsec->sid != fsec->sid) { - rc = avc_has_perm(tsec->sid, fsec->sid, + if (sid != fsec->sid) { + rc = avc_has_perm(sid, fsec->sid, SECCLASS_FD, FD__USE, &ad); @@ -1489,36 +1519,36 @@ static int may_create(struct inode *dir, struct dentry *dentry, u16 tclass) { - struct task_security_struct *tsec; + const struct cred *cred = current_cred(); + const struct task_security_struct *tsec = cred->security; struct inode_security_struct *dsec; struct superblock_security_struct *sbsec; - u32 newsid; + u32 sid, newsid; struct avc_audit_data ad; int rc; - tsec = current->cred->security; dsec = dir->i_security; sbsec = dir->i_sb->s_security; + sid = tsec->sid; + newsid = tsec->create_sid; + AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = dentry; - rc = avc_has_perm(tsec->sid, dsec->sid, SECCLASS_DIR, + rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, DIR__ADD_NAME | DIR__SEARCH, &ad); if (rc) return rc; - if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) { - newsid = tsec->create_sid; - } else { - rc = security_transition_sid(tsec->sid, dsec->sid, tclass, - &newsid); + if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) { + rc = security_transition_sid(sid, dsec->sid, tclass, &newsid); if (rc) return rc; } - rc = avc_has_perm(tsec->sid, newsid, tclass, FILE__CREATE, &ad); + rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad); if (rc) return rc; @@ -1531,11 +1561,9 @@ static int may_create(struct inode *dir, static int may_create_key(u32 ksid, struct task_struct *ctx) { - struct task_security_struct *tsec; - - tsec = ctx->cred->security; + u32 sid = task_sid(ctx); - return avc_has_perm(tsec->sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL); + return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL); } #define MAY_LINK 0 @@ -1548,13 +1576,12 @@ static int may_link(struct inode *dir, int kind) { - struct task_security_struct *tsec; struct inode_security_struct *dsec, *isec; struct avc_audit_data ad; + u32 sid = current_sid(); u32 av; int rc; - tsec = current->cred->security; dsec = dir->i_security; isec = dentry->d_inode->i_security; @@ -1563,7 +1590,7 @@ static int may_link(struct inode *dir, av = DIR__SEARCH; av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME); - rc = avc_has_perm(tsec->sid, dsec->sid, SECCLASS_DIR, av, &ad); + rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad); if (rc) return rc; @@ -1583,7 +1610,7 @@ static int may_link(struct inode *dir, return 0; } - rc = avc_has_perm(tsec->sid, isec->sid, isec->sclass, av, &ad); + rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad); return rc; } @@ -1592,14 +1619,13 @@ static inline int may_rename(struct inode *old_dir, struct inode *new_dir, struct dentry *new_dentry) { - struct task_security_struct *tsec; struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec; struct avc_audit_data ad; + u32 sid = current_sid(); u32 av; int old_is_dir, new_is_dir; int rc; - tsec = current->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); @@ -1608,16 +1634,16 @@ static inline int may_rename(struct inode *old_dir, AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = old_dentry; - rc = avc_has_perm(tsec->sid, old_dsec->sid, SECCLASS_DIR, + rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, DIR__REMOVE_NAME | DIR__SEARCH, &ad); if (rc) return rc; - rc = avc_has_perm(tsec->sid, old_isec->sid, + rc = avc_has_perm(sid, old_isec->sid, old_isec->sclass, FILE__RENAME, &ad); if (rc) return rc; if (old_is_dir && new_dir != old_dir) { - rc = avc_has_perm(tsec->sid, old_isec->sid, + rc = avc_has_perm(sid, old_isec->sid, old_isec->sclass, DIR__REPARENT, &ad); if (rc) return rc; @@ -1627,13 +1653,13 @@ static inline int may_rename(struct inode *old_dir, av = DIR__ADD_NAME | DIR__SEARCH; if (new_dentry->d_inode) av |= DIR__REMOVE_NAME; - rc = avc_has_perm(tsec->sid, new_dsec->sid, SECCLASS_DIR, av, &ad); + rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad); if (rc) return rc; if (new_dentry->d_inode) { new_isec = new_dentry->d_inode->i_security; new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode); - rc = avc_has_perm(tsec->sid, new_isec->sid, + rc = avc_has_perm(sid, new_isec->sid, new_isec->sclass, (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad); if (rc) @@ -1649,13 +1675,11 @@ static int superblock_has_perm(struct task_struct *tsk, u32 perms, struct avc_audit_data *ad) { - struct task_security_struct *tsec; struct superblock_security_struct *sbsec; + u32 sid = task_sid(tsk); - tsec = tsk->cred->security; sbsec = sb->s_security; - return avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, - perms, ad); + return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad); } /* Convert a Linux mode and permission mask to an access vector. */ @@ -1751,10 +1775,9 @@ static int selinux_ptrace_may_access(struct task_struct *child, return rc; if (mode == PTRACE_MODE_READ) { - struct task_security_struct *tsec = current->cred->security; - struct task_security_struct *csec = child->cred->security; - return avc_has_perm(tsec->sid, csec->sid, - SECCLASS_FILE, FILE__READ, NULL); + u32 sid = current_sid(); + u32 csid = task_sid(child); + return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL); } return task_has_perm(current, child, PROCESS__PTRACE); @@ -1859,15 +1882,14 @@ static int selinux_sysctl(ctl_table *table, int op) { int error = 0; u32 av; - struct task_security_struct *tsec; - u32 tsid; + u32 tsid, sid; int rc; rc = secondary_ops->sysctl(table, op); if (rc) return rc; - tsec = current->cred->security; + sid = current_sid(); rc = selinux_sysctl_get_sid(table, (op == 0001) ? SECCLASS_DIR : SECCLASS_FILE, &tsid); @@ -1879,7 +1901,7 @@ static int selinux_sysctl(ctl_table *table, int op) /* The op values are "defined" in sysctl.c, thereby creating * a bad coupling between this module and sysctl.c */ if (op == 001) { - error = avc_has_perm(tsec->sid, tsid, + error = avc_has_perm(sid, tsid, SECCLASS_DIR, DIR__SEARCH, NULL); } else { av = 0; @@ -1888,7 +1910,7 @@ static int selinux_sysctl(ctl_table *table, int op) if (op & 002) av |= FILE__WRITE; if (av) - error = avc_has_perm(tsec->sid, tsid, + error = avc_has_perm(sid, tsid, SECCLASS_FILE, av, NULL); } @@ -2018,7 +2040,7 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm) if (bsec->set) return 0; - tsec = current->cred->security; + tsec = current_security(); isec = inode->i_security; /* Default to the current task SID. */ @@ -2083,14 +2105,19 @@ static int selinux_bprm_check_security(struct linux_binprm *bprm) static int selinux_bprm_secureexec(struct linux_binprm *bprm) { - struct task_security_struct *tsec = current->cred->security; + const struct cred *cred = current_cred(); + const struct task_security_struct *tsec = cred->security; + u32 sid, osid; int atsecure = 0; - if (tsec->osid != tsec->sid) { + sid = tsec->sid; + osid = tsec->osid; + + if (osid != sid) { /* Enable secure mode for SIDs transitions unless the noatsecure permission is granted between the two SIDs, i.e. ahp returns 0. */ - atsecure = avc_has_perm(tsec->osid, tsec->sid, + atsecure = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__NOATSECURE, NULL); } @@ -2207,7 +2234,7 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) secondary_ops->bprm_apply_creds(bprm, unsafe); - tsec = current->cred->security; + tsec = current_security(); bsec = bprm->security; sid = bsec->sid; @@ -2236,7 +2263,7 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) rcu_read_lock(); tracer = tracehook_tracer_task(current); if (likely(tracer != NULL)) { - sec = tracer->cred->security; + sec = __task_cred(tracer)->security; ptsid = sec->sid; } rcu_read_unlock(); @@ -2267,7 +2294,7 @@ static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm) int rc, i; unsigned long flags; - tsec = current->cred->security; + tsec = current_security(); bsec = bprm->security; if (bsec->unsafe) { @@ -2507,21 +2534,22 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, char **name, void **value, size_t *len) { - struct task_security_struct *tsec; + const struct cred *cred = current_cred(); + const struct task_security_struct *tsec = cred->security; struct inode_security_struct *dsec; struct superblock_security_struct *sbsec; - u32 newsid, clen; + u32 sid, newsid, clen; int rc; char *namep = NULL, *context; - tsec = current->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; - } else { - rc = security_transition_sid(tsec->sid, dsec->sid, + sid = tsec->sid; + newsid = tsec->create_sid; + + if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) { + rc = security_transition_sid(sid, dsec->sid, inode_mode_to_security_class(inode->i_mode), &newsid); if (rc) { @@ -2699,12 +2727,11 @@ static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name) static int selinux_inode_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - struct task_security_struct *tsec = current->cred->security; struct inode *inode = dentry->d_inode; struct inode_security_struct *isec = inode->i_security; struct superblock_security_struct *sbsec; struct avc_audit_data ad; - u32 newsid; + u32 newsid, sid = current_sid(); int rc = 0; if (strcmp(name, XATTR_NAME_SELINUX)) @@ -2720,7 +2747,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = dentry; - rc = avc_has_perm(tsec->sid, isec->sid, isec->sclass, + rc = avc_has_perm(sid, isec->sid, isec->sclass, FILE__RELABELFROM, &ad); if (rc) return rc; @@ -2734,12 +2761,12 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, if (rc) return rc; - rc = avc_has_perm(tsec->sid, newsid, isec->sclass, + rc = avc_has_perm(sid, newsid, isec->sclass, FILE__RELABELTO, &ad); if (rc) return rc; - rc = security_validate_transition(isec->sid, newsid, tsec->sid, + rc = security_validate_transition(isec->sid, newsid, sid, isec->sclass); if (rc) return rc; @@ -2911,16 +2938,16 @@ static int selinux_revalidate_file_permission(struct file *file, int mask) static int selinux_file_permission(struct file *file, int mask) { struct inode *inode = file->f_path.dentry->d_inode; - struct task_security_struct *tsec = current->cred->security; struct file_security_struct *fsec = file->f_security; struct inode_security_struct *isec = inode->i_security; + u32 sid = current_sid(); if (!mask) { /* No permission to check. Existence test. */ return 0; } - if (tsec->sid == fsec->sid && fsec->isid == isec->sid + if (sid == fsec->sid && fsec->isid == isec->sid && fsec->pseqno == avc_policy_seqno()) return selinux_netlbl_inode_permission(inode, mask); @@ -2988,8 +3015,7 @@ static int selinux_file_mmap(struct file *file, unsigned long reqprot, unsigned long addr, unsigned long addr_only) { int rc = 0; - u32 sid = ((struct task_security_struct *) - (current->cred->security))->sid; + u32 sid = current_sid(); if (addr < mmap_min_addr) rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT, @@ -3098,12 +3124,10 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd, static int selinux_file_set_fowner(struct file *file) { - struct task_security_struct *tsec; struct file_security_struct *fsec; - tsec = current->cred->security; fsec = file->f_security; - fsec->fown_sid = tsec->sid; + fsec->fown_sid = current_sid(); return 0; } @@ -3112,14 +3136,13 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk, struct fown_struct *fown, int signum) { struct file *file; + u32 sid = current_sid(); u32 perm; - struct task_security_struct *tsec; struct file_security_struct *fsec; /* struct fown_struct is never outside the context of a struct file */ file = container_of(fown, struct file, f_owner); - tsec = tsk->cred->security; fsec = file->f_security; if (!signum) @@ -3127,7 +3150,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, sid, SECCLASS_PROCESS, perm, NULL); } @@ -3182,7 +3205,7 @@ static int selinux_cred_alloc_security(struct cred *cred) struct task_security_struct *tsec1, *tsec2; int rc; - tsec1 = current->cred->security; + tsec1 = current_security(); rc = cred_alloc_security(cred); if (rc) @@ -3250,8 +3273,7 @@ static int selinux_task_getsid(struct task_struct *p) static void selinux_task_getsecid(struct task_struct *p, u32 *secid) { - struct task_security_struct *tsec = p->cred->security; - *secid = tsec->sid; + *secid = task_sid(p); } static int selinux_task_setgroups(struct group_info *group_info) @@ -3332,7 +3354,6 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info, { u32 perm; int rc; - struct task_security_struct *tsec; rc = secondary_ops->task_kill(p, info, sig, secid); if (rc) @@ -3342,9 +3363,9 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info, perm = PROCESS__SIGNULL; /* null signal; existence test */ else perm = signal_to_av(sig); - tsec = p->cred->security; if (secid) - rc = avc_has_perm(secid, tsec->sid, SECCLASS_PROCESS, perm, NULL); + rc = avc_has_perm(secid, task_sid(p), + SECCLASS_PROCESS, perm, NULL); else rc = task_has_perm(current, p, perm); return rc; @@ -3383,12 +3404,11 @@ static void selinux_task_reparent_to_init(struct task_struct *p) static void selinux_task_to_inode(struct task_struct *p, struct inode *inode) { - struct task_security_struct *tsec = p->cred->security; struct inode_security_struct *isec = inode->i_security; + u32 sid = task_sid(p); - isec->sid = tsec->sid; + isec->sid = sid; isec->initialized = 1; - return; } /* Returns error only if unable to parse addresses */ @@ -3627,19 +3647,19 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock, u32 perms) { struct inode_security_struct *isec; - struct task_security_struct *tsec; struct avc_audit_data ad; + u32 sid; int err = 0; - tsec = task->cred->security; isec = SOCK_INODE(sock)->i_security; if (isec->sid == SECINITSID_KERNEL) goto out; + sid = task_sid(task); AVC_AUDIT_DATA_INIT(&ad, NET); ad.u.net.sk = sock->sk; - err = avc_has_perm(tsec->sid, isec->sid, isec->sclass, perms, &ad); + err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad); out: return err; @@ -3648,18 +3668,20 @@ out: static int selinux_socket_create(int family, int type, int protocol, int kern) { + const struct cred *cred = current_cred(); + const struct task_security_struct *tsec = cred->security; + u32 sid, newsid; + u16 secclass; int err = 0; - struct task_security_struct *tsec; - u32 newsid; if (kern) goto out; - tsec = current->cred->security; - newsid = tsec->sockcreate_sid ? : tsec->sid; - err = avc_has_perm(tsec->sid, newsid, - socket_type_to_security_class(family, type, - protocol), SOCKET__CREATE, NULL); + sid = tsec->sid; + newsid = tsec->sockcreate_sid ?: sid; + + secclass = socket_type_to_security_class(family, type, protocol); + err = avc_has_perm(sid, newsid, secclass, SOCKET__CREATE, NULL); out: return err; @@ -3668,18 +3690,26 @@ out: static int selinux_socket_post_create(struct socket *sock, int family, int type, int protocol, int kern) { - int err = 0; + const struct cred *cred = current_cred(); + const struct task_security_struct *tsec = cred->security; struct inode_security_struct *isec; - struct task_security_struct *tsec; struct sk_security_struct *sksec; - u32 newsid; + u32 sid, newsid; + int err = 0; + + sid = tsec->sid; + newsid = tsec->sockcreate_sid; isec = SOCK_INODE(sock)->i_security; - tsec = current->cred->security; - newsid = tsec->sockcreate_sid ? : tsec->sid; + if (kern) + isec->sid = SECINITSID_KERNEL; + else if (newsid) + isec->sid = newsid; + else + isec->sid = sid; + isec->sclass = socket_type_to_security_class(family, type, protocol); - isec->sid = kern ? SECINITSID_KERNEL : newsid; isec->initialized = 1; if (sock->sk) { @@ -3714,7 +3744,6 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in if (family == PF_INET || family == PF_INET6) { char *addrp; struct inode_security_struct *isec; - struct task_security_struct *tsec; struct avc_audit_data ad; struct sockaddr_in *addr4 = NULL; struct sockaddr_in6 *addr6 = NULL; @@ -3722,7 +3751,6 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in struct sock *sk = sock->sk; u32 sid, node_perm; - tsec = current->cred->security; isec = SOCK_INODE(sock)->i_security; if (family == PF_INET) { @@ -4763,15 +4791,16 @@ static int ipc_alloc_security(struct task_struct *task, struct kern_ipc_perm *perm, u16 sclass) { - struct task_security_struct *tsec = task->cred->security; struct ipc_security_struct *isec; + u32 sid; isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL); if (!isec) return -ENOMEM; + sid = task_sid(task); isec->sclass = sclass; - isec->sid = tsec->sid; + isec->sid = sid; perm->security = isec; return 0; @@ -4809,17 +4838,16 @@ static void msg_msg_free_security(struct msg_msg *msg) static int ipc_has_perm(struct kern_ipc_perm *ipc_perms, u32 perms) { - struct task_security_struct *tsec; struct ipc_security_struct *isec; struct avc_audit_data ad; + u32 sid = current_sid(); - tsec = current->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(sid, isec->sid, isec->sclass, perms, &ad); } static int selinux_msg_msg_alloc_security(struct msg_msg *msg) @@ -4835,22 +4863,21 @@ static void selinux_msg_msg_free_security(struct msg_msg *msg) /* message queue security operations */ static int selinux_msg_queue_alloc_security(struct msg_queue *msq) { - struct task_security