aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/hooks.c
diff options
context:
space:
mode:
authorAlexey Kodanev <alexey.kodanev@oracle.com>2018-05-11 13:15:11 -0400
committerPaul Moore <paul@paul-moore.com>2018-05-14 15:17:02 -0400
commit0f8db8cc73df60b3de9a5eebd8f117b56eff5b03 (patch)
treec890791d42e34d4dcb9bad3307143246a13adb81 /security/selinux/hooks.c
parent6b6bc6205d98796361962ee282a063f18ba8dc57 (diff)
selinux: add AF_UNSPEC and INADDR_ANY checks to selinux_socket_bind()
Commit d452930fd3b9 ("selinux: Add SCTP support") breaks compatibility with the old programs that can pass sockaddr_in structure with AF_UNSPEC and INADDR_ANY to bind(). As a result, bind() returns EAFNOSUPPORT error. This was found with LTP/asapi_01 test. Similar to commit 29c486df6a20 ("net: ipv4: relax AF_INET check in bind()"), which relaxed AF_INET check for compatibility, add AF_UNSPEC case to AF_INET and make sure that the address is INADDR_ANY. Fixes: d452930fd3b9 ("selinux: Add SCTP support") Signed-off-by: Alexey Kodanev <alexey.kodanev@oracle.com> Signed-off-by: Paul Moore <paul@paul-moore.com>
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r--security/selinux/hooks.c29
1 files changed, 19 insertions, 10 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 21b377aef69a..16df6cca9a1b 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4568,6 +4568,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
4568static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) 4568static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
4569{ 4569{
4570 struct sock *sk = sock->sk; 4570 struct sock *sk = sock->sk;
4571 struct sk_security_struct *sksec = sk->sk_security;
4571 u16 family; 4572 u16 family;
4572 int err; 4573 int err;
4573 4574
@@ -4579,11 +4580,11 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
4579 family = sk->sk_family; 4580 family = sk->sk_family;
4580 if (family == PF_INET || family == PF_INET6) { 4581 if (family == PF_INET || family == PF_INET6) {
4581 char *addrp; 4582 char *addrp;
4582 struct sk_security_struct *sksec = sk->sk_security;
4583 struct common_audit_data ad; 4583 struct common_audit_data ad;
4584 struct lsm_network_audit net = {0,}; 4584 struct lsm_network_audit net = {0,};
4585 struct sockaddr_in *addr4 = NULL; 4585 struct sockaddr_in *addr4 = NULL;
4586 struct sockaddr_in6 *addr6 = NULL; 4586 struct sockaddr_in6 *addr6 = NULL;
4587 u16 family_sa = address->sa_family;
4587 unsigned short snum; 4588 unsigned short snum;
4588 u32 sid, node_perm; 4589 u32 sid, node_perm;
4589 4590
@@ -4593,11 +4594,20 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
4593 * need to check address->sa_family as it is possible to have 4594 * need to check address->sa_family as it is possible to have
4594 * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET. 4595 * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET.
4595 */ 4596 */
4596 switch (address->sa_family) { 4597 switch (family_sa) {
4598 case AF_UNSPEC:
4597 case AF_INET: 4599 case AF_INET:
4598 if (addrlen < sizeof(struct sockaddr_in)) 4600 if (addrlen < sizeof(struct sockaddr_in))
4599 return -EINVAL; 4601 return -EINVAL;
4600 addr4 = (struct sockaddr_in *)address; 4602 addr4 = (struct sockaddr_in *)address;
4603 if (family_sa == AF_UNSPEC) {
4604 /* see __inet_bind(), we only want to allow
4605 * AF_UNSPEC if the address is INADDR_ANY
4606 */
4607 if (addr4->sin_addr.s_addr != htonl(INADDR_ANY))
4608 goto err_af;
4609 family_sa = AF_INET;
4610 }
4601 snum = ntohs(addr4->sin_port); 4611 snum = ntohs(addr4->sin_port);
4602 addrp = (char *)&addr4->sin_addr.s_addr; 4612 addrp = (char *)&addr4->sin_addr.s_addr;
4603 break; 4613 break;
@@ -4609,13 +4619,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
4609 addrp = (char *)&addr6->sin6_addr.s6_addr; 4619 addrp = (char *)&addr6->sin6_addr.s6_addr;
4610 break; 4620 break;
4611 default: 4621 default:
4612 /* Note that SCTP services expect -EINVAL, whereas 4622 goto err_af;
4613 * others expect -EAFNOSUPPORT.
4614 */
4615 if (sksec->sclass == SECCLASS_SCTP_SOCKET)
4616 return -EINVAL;
4617 else
4618 return -EAFNOSUPPORT;
4619 } 4623 }
4620 4624
4621 if (snum) { 4625 if (snum) {
@@ -4673,7 +4677,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
4673 ad.u.net->sport = htons(snum); 4677 ad.u.net->sport = htons(snum);
4674 ad.u.net->family = family; 4678 ad.u.net->family = family;
4675 4679
4676 if (address->sa_family == AF_INET) 4680 if (family_sa == AF_INET)
4677 ad.u.net->v4info.saddr = addr4->sin_addr.s_addr; 4681 ad.u.net->v4info.saddr = addr4->sin_addr.s_addr;
4678 else 4682 else
4679 ad.u.net->v6info.saddr = addr6->sin6_addr; 4683 ad.u.net->v6info.saddr = addr6->sin6_addr;
@@ -4686,6 +4690,11 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
4686 } 4690 }
4687out: 4691out:
4688 return err; 4692 return err;
4693err_af:
4694 /* Note that SCTP services expect -EINVAL, others -EAFNOSUPPORT. */
4695 if (sksec->sclass == SECCLASS_SCTP_SOCKET)
4696 return -EINVAL;
4697 return -EAFNOSUPPORT;
4689} 4698}
4690 4699
4691/* This supports connect(2) and SCTP connect services such as sctp_connectx(3) 4700/* This supports connect(2) and SCTP connect services such as sctp_connectx(3)