aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/hooks.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r--security/selinux/hooks.c62
1 files changed, 39 insertions, 23 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 03fc6a81ae32..4a7374c12d9c 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -957,7 +957,8 @@ out_err:
957 return rc; 957 return rc;
958} 958}
959 959
960void selinux_write_opts(struct seq_file *m, struct security_mnt_opts *opts) 960static void selinux_write_opts(struct seq_file *m,
961 struct security_mnt_opts *opts)
961{ 962{
962 int i; 963 int i;
963 char *prefix; 964 char *prefix;
@@ -1290,7 +1291,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
1290 /* Default to the fs superblock SID. */ 1291 /* Default to the fs superblock SID. */
1291 isec->sid = sbsec->sid; 1292 isec->sid = sbsec->sid;
1292 1293
1293 if (sbsec->proc) { 1294 if (sbsec->proc && !S_ISLNK(inode->i_mode)) {
1294 struct proc_inode *proci = PROC_I(inode); 1295 struct proc_inode *proci = PROC_I(inode);
1295 if (proci->pde) { 1296 if (proci->pde) {
1296 isec->sclass = inode_mode_to_security_class(inode->i_mode); 1297 isec->sclass = inode_mode_to_security_class(inode->i_mode);
@@ -3548,38 +3549,44 @@ out:
3548#endif /* IPV6 */ 3549#endif /* IPV6 */
3549 3550
3550static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, 3551static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
3551 char **addrp, int src, u8 *proto) 3552 char **_addrp, int src, u8 *proto)
3552{ 3553{
3553 int ret = 0; 3554 char *addrp;
3555 int ret;
3554 3556
3555 switch (ad->u.net.family) { 3557 switch (ad->u.net.family) {
3556 case PF_INET: 3558 case PF_INET:
3557 ret = selinux_parse_skb_ipv4(skb, ad, proto); 3559 ret = selinux_parse_skb_ipv4(skb, ad, proto);
3558 if (ret || !addrp) 3560 if (ret)
3559 break; 3561 goto parse_error;
3560 *addrp = (char *)(src ? &ad->u.net.v4info.saddr : 3562 addrp = (char *)(src ? &ad->u.net.v4info.saddr :
3561 &ad->u.net.v4info.daddr); 3563 &ad->u.net.v4info.daddr);
3562 break; 3564 goto okay;
3563 3565
3564#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 3566#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3565 case PF_INET6: 3567 case PF_INET6:
3566 ret = selinux_parse_skb_ipv6(skb, ad, proto); 3568 ret = selinux_parse_skb_ipv6(skb, ad, proto);
3567 if (ret || !addrp) 3569 if (ret)
3568 break; 3570 goto parse_error;
3569 *addrp = (char *)(src ? &ad->u.net.v6info.saddr : 3571 addrp = (char *)(src ? &ad->u.net.v6info.saddr :
3570 &ad->u.net.v6info.daddr); 3572 &ad->u.net.v6info.daddr);
3571 break; 3573 goto okay;
3572#endif /* IPV6 */ 3574#endif /* IPV6 */
3573 default: 3575 default:
3574 break; 3576 addrp = NULL;
3577 goto okay;
3575 } 3578 }
3576 3579
3577 if (unlikely(ret)) 3580parse_error:
3578 printk(KERN_WARNING 3581 printk(KERN_WARNING
3579 "SELinux: failure in selinux_parse_skb()," 3582 "SELinux: failure in selinux_parse_skb(),"
3580 " unable to parse packet\n"); 3583 " unable to parse packet\n");
3581
3582 return ret; 3584 return ret;
3585
3586okay:
3587 if (_addrp)
3588 *_addrp = addrp;
3589 return 0;
3583} 3590}
3584 3591
3585/** 3592/**
@@ -5219,8 +5226,12 @@ static int selinux_setprocattr(struct task_struct *p,
5219 5226
5220 if (sid == 0) 5227 if (sid == 0)
5221 return -EINVAL; 5228 return -EINVAL;
5222 5229 /*
5223 /* Only allow single threaded processes to change context */ 5230 * SELinux allows to change context in the following case only.
5231 * - Single threaded processes.
5232 * - Multi threaded processes intend to change its context into
5233 * more restricted domain (defined by TYPEBOUNDS statement).
5234 */
5224 if (atomic_read(&p->mm->mm_users) != 1) { 5235 if (atomic_read(&p->mm->mm_users) != 1) {
5225 struct task_struct *g, *t; 5236 struct task_struct *g, *t;
5226 struct mm_struct *mm = p->mm; 5237 struct mm_struct *mm = p->mm;
@@ -5228,11 +5239,16 @@ static int selinux_setprocattr(struct task_struct *p,
5228 do_each_thread(g, t) { 5239 do_each_thread(g, t) {
5229 if (t->mm == mm && t != p) { 5240 if (t->mm == mm && t != p) {
5230 read_unlock(&tasklist_lock); 5241 read_unlock(&tasklist_lock);
5231 return -EPERM; 5242 error = security_bounded_transition(tsec->sid, sid);
5243 if (!error)
5244 goto boundary_ok;
5245
5246 return error;
5232 } 5247 }
5233 } while_each_thread(g, t); 5248 } while_each_thread(g, t);
5234 read_unlock(&tasklist_lock); 5249 read_unlock(&tasklist_lock);
5235 } 5250 }
5251boundary_ok:
5236 5252
5237 /* Check permissions for the transition. */ 5253 /* Check permissions for the transition. */
5238 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS, 5254 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,