diff options
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r-- | security/selinux/hooks.c | 70 |
1 files changed, 44 insertions, 26 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index b02315183b2f..99c4675952f7 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -1567,8 +1567,15 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
1567 | /* Called from d_instantiate or d_splice_alias. */ | 1567 | /* Called from d_instantiate or d_splice_alias. */ |
1568 | dentry = dget(opt_dentry); | 1568 | dentry = dget(opt_dentry); |
1569 | } else { | 1569 | } else { |
1570 | /* Called from selinux_complete_init, try to find a dentry. */ | 1570 | /* |
1571 | * Called from selinux_complete_init, try to find a dentry. | ||
1572 | * Some filesystems really want a connected one, so try | ||
1573 | * that first. We could split SECURITY_FS_USE_XATTR in | ||
1574 | * two, depending upon that... | ||
1575 | */ | ||
1571 | dentry = d_find_alias(inode); | 1576 | dentry = d_find_alias(inode); |
1577 | if (!dentry) | ||
1578 | dentry = d_find_any_alias(inode); | ||
1572 | } | 1579 | } |
1573 | if (!dentry) { | 1580 | if (!dentry) { |
1574 | /* | 1581 | /* |
@@ -1673,14 +1680,19 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
1673 | if ((sbsec->flags & SE_SBGENFS) && !S_ISLNK(inode->i_mode)) { | 1680 | if ((sbsec->flags & SE_SBGENFS) && !S_ISLNK(inode->i_mode)) { |
1674 | /* We must have a dentry to determine the label on | 1681 | /* We must have a dentry to determine the label on |
1675 | * procfs inodes */ | 1682 | * procfs inodes */ |
1676 | if (opt_dentry) | 1683 | if (opt_dentry) { |
1677 | /* Called from d_instantiate or | 1684 | /* Called from d_instantiate or |
1678 | * d_splice_alias. */ | 1685 | * d_splice_alias. */ |
1679 | dentry = dget(opt_dentry); | 1686 | dentry = dget(opt_dentry); |
1680 | else | 1687 | } else { |
1681 | /* Called from selinux_complete_init, try to | 1688 | /* Called from selinux_complete_init, try to |
1682 | * find a dentry. */ | 1689 | * find a dentry. Some filesystems really want |
1690 | * a connected one, so try that first. | ||
1691 | */ | ||
1683 | dentry = d_find_alias(inode); | 1692 | dentry = d_find_alias(inode); |
1693 | if (!dentry) | ||
1694 | dentry = d_find_any_alias(inode); | ||
1695 | } | ||
1684 | /* | 1696 | /* |
1685 | * This can be hit on boot when a file is accessed | 1697 | * This can be hit on boot when a file is accessed |
1686 | * before the policy is loaded. When we load policy we | 1698 | * before the policy is loaded. When we load policy we |
@@ -4575,6 +4587,7 @@ static int selinux_socket_post_create(struct socket *sock, int family, | |||
4575 | static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) | 4587 | static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) |
4576 | { | 4588 | { |
4577 | struct sock *sk = sock->sk; | 4589 | struct sock *sk = sock->sk; |
4590 | struct sk_security_struct *sksec = sk->sk_security; | ||
4578 | u16 family; | 4591 | u16 family; |
4579 | int err; | 4592 | int err; |
4580 | 4593 | ||
@@ -4586,11 +4599,11 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
4586 | family = sk->sk_family; | 4599 | family = sk->sk_family; |
4587 | if (family == PF_INET || family == PF_INET6) { | 4600 | if (family == PF_INET || family == PF_INET6) { |
4588 | char *addrp; | 4601 | char *addrp; |
4589 | struct sk_security_struct *sksec = sk->sk_security; | ||
4590 | struct common_audit_data ad; | 4602 | struct common_audit_data ad; |
4591 | struct lsm_network_audit net = {0,}; | 4603 | struct lsm_network_audit net = {0,}; |
4592 | struct sockaddr_in *addr4 = NULL; | 4604 | struct sockaddr_in *addr4 = NULL; |
4593 | struct sockaddr_in6 *addr6 = NULL; | 4605 | struct sockaddr_in6 *addr6 = NULL; |
4606 | u16 family_sa = address->sa_family; | ||
4594 | unsigned short snum; | 4607 | unsigned short snum; |
4595 | u32 sid, node_perm; | 4608 | u32 sid, node_perm; |
4596 | 4609 | ||
@@ -4600,11 +4613,20 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
4600 | * need to check address->sa_family as it is possible to have | 4613 | * need to check address->sa_family as it is possible to have |
4601 | * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET. | 4614 | * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET. |
4602 | */ | 4615 | */ |
4603 | switch (address->sa_family) { | 4616 | switch (family_sa) { |
4617 | case AF_UNSPEC: | ||
4604 | case AF_INET: | 4618 | case AF_INET: |
4605 | if (addrlen < sizeof(struct sockaddr_in)) | 4619 | if (addrlen < sizeof(struct sockaddr_in)) |
4606 | return -EINVAL; | 4620 | return -EINVAL; |
4607 | addr4 = (struct sockaddr_in *)address; | 4621 | addr4 = (struct sockaddr_in *)address; |
4622 | if (family_sa == AF_UNSPEC) { | ||
4623 | /* see __inet_bind(), we only want to allow | ||
4624 | * AF_UNSPEC if the address is INADDR_ANY | ||
4625 | */ | ||
4626 | if (addr4->sin_addr.s_addr != htonl(INADDR_ANY)) | ||
4627 | goto err_af; | ||
4628 | family_sa = AF_INET; | ||
4629 | } | ||
4608 | snum = ntohs(addr4->sin_port); | 4630 | snum = ntohs(addr4->sin_port); |
4609 | addrp = (char *)&addr4->sin_addr.s_addr; | 4631 | addrp = (char *)&addr4->sin_addr.s_addr; |
4610 | break; | 4632 | break; |
@@ -4616,15 +4638,14 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
4616 | addrp = (char *)&addr6->sin6_addr.s6_addr; | 4638 | addrp = (char *)&addr6->sin6_addr.s6_addr; |
4617 | break; | 4639 | break; |
4618 | default: | 4640 | default: |
4619 | /* Note that SCTP services expect -EINVAL, whereas | 4641 | goto err_af; |
4620 | * others expect -EAFNOSUPPORT. | ||
4621 | */ | ||
4622 | if (sksec->sclass == SECCLASS_SCTP_SOCKET) | ||
4623 | return -EINVAL; | ||
4624 | else | ||
4625 | return -EAFNOSUPPORT; | ||
4626 | } | 4642 | } |
4627 | 4643 | ||
4644 | ad.type = LSM_AUDIT_DATA_NET; | ||
4645 | ad.u.net = &net; | ||
4646 | ad.u.net->sport = htons(snum); | ||
4647 | ad.u.net->family = family_sa; | ||
4648 | |||
4628 | if (snum) { | 4649 | if (snum) { |
4629 | int low, high; | 4650 | int low, high; |
4630 | 4651 | ||
@@ -4636,10 +4657,6 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
4636 | snum, &sid); | 4657 | snum, &sid); |
4637 | if (err) | 4658 | if (err) |
4638 | goto out; | 4659 | goto out; |
4639 | ad.type = LSM_AUDIT_DATA_NET; | ||
4640 | ad.u.net = &net; | ||
4641 | ad.u.net->sport = htons(snum); | ||
4642 | ad.u.net->family = family; | ||
4643 | err = avc_has_perm(&selinux_state, | 4660 | err = avc_has_perm(&selinux_state, |
4644 | sksec->sid, sid, | 4661 | sksec->sid, sid, |
4645 | sksec->sclass, | 4662 | sksec->sclass, |
@@ -4671,16 +4688,11 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
4671 | break; | 4688 | break; |
4672 | } | 4689 | } |
4673 | 4690 | ||
4674 | err = sel_netnode_sid(addrp, family, &sid); | 4691 | err = sel_netnode_sid(addrp, family_sa, &sid); |
4675 | if (err) | 4692 | if (err) |
4676 | goto out; | 4693 | goto out; |
4677 | 4694 | ||
4678 | ad.type = LSM_AUDIT_DATA_NET; | 4695 | if (family_sa == AF_INET) |
4679 | ad.u.net = &net; | ||
4680 | ad.u.net->sport = htons(snum); | ||
4681 | ad.u.net->family = family; | ||
4682 | |||
4683 | if (address->sa_family == AF_INET) | ||
4684 | ad.u.net->v4info.saddr = addr4->sin_addr.s_addr; | 4696 | ad.u.net->v4info.saddr = addr4->sin_addr.s_addr; |
4685 | else | 4697 | else |
4686 | ad.u.net->v6info.saddr = addr6->sin6_addr; | 4698 | ad.u.net->v6info.saddr = addr6->sin6_addr; |
@@ -4693,6 +4705,11 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
4693 | } | 4705 | } |
4694 | out: | 4706 | out: |
4695 | return err; | 4707 | return err; |
4708 | err_af: | ||
4709 | /* Note that SCTP services expect -EINVAL, others -EAFNOSUPPORT. */ | ||
4710 | if (sksec->sclass == SECCLASS_SCTP_SOCKET) | ||
4711 | return -EINVAL; | ||
4712 | return -EAFNOSUPPORT; | ||
4696 | } | 4713 | } |
4697 | 4714 | ||
4698 | /* This supports connect(2) and SCTP connect services such as sctp_connectx(3) | 4715 | /* This supports connect(2) and SCTP connect services such as sctp_connectx(3) |
@@ -4770,7 +4787,7 @@ static int selinux_socket_connect_helper(struct socket *sock, | |||
4770 | ad.type = LSM_AUDIT_DATA_NET; | 4787 | ad.type = LSM_AUDIT_DATA_NET; |
4771 | ad.u.net = &net; | 4788 | ad.u.net = &net; |
4772 | ad.u.net->dport = htons(snum); | 4789 | ad.u.net->dport = htons(snum); |
4773 | ad.u.net->family = sk->sk_family; | 4790 | ad.u.net->family = address->sa_family; |
4774 | err = avc_has_perm(&selinux_state, | 4791 | err = avc_has_perm(&selinux_state, |
4775 | sksec->sid, sid, sksec->sclass, perm, &ad); | 4792 | sksec->sid, sid, sksec->sclass, perm, &ad); |
4776 | if (err) | 4793 | if (err) |
@@ -5271,6 +5288,7 @@ static int selinux_sctp_bind_connect(struct sock *sk, int optname, | |||
5271 | while (walk_size < addrlen) { | 5288 | while (walk_size < addrlen) { |
5272 | addr = addr_buf; | 5289 | addr = addr_buf; |
5273 | switch (addr->sa_family) { | 5290 | switch (addr->sa_family) { |
5291 | case AF_UNSPEC: | ||
5274 | case AF_INET: | 5292 | case AF_INET: |
5275 | len = sizeof(struct sockaddr_in); | 5293 | len = sizeof(struct sockaddr_in); |
5276 | break; | 5294 | break; |
@@ -5278,7 +5296,7 @@ static int selinux_sctp_bind_connect(struct sock *sk, int optname, | |||
5278 | len = sizeof(struct sockaddr_in6); | 5296 | len = sizeof(struct sockaddr_in6); |
5279 | break; | 5297 | break; |
5280 | default: | 5298 | default: |
5281 | return -EAFNOSUPPORT; | 5299 | return -EINVAL; |
5282 | } | 5300 | } |
5283 | 5301 | ||
5284 | err = -EINVAL; | 5302 | err = -EINVAL; |