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.c50
1 files changed, 28 insertions, 22 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 4cafe6a19167..be5817df0a9d 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4576,6 +4576,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
4576static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) 4576static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
4577{ 4577{
4578 struct sock *sk = sock->sk; 4578 struct sock *sk = sock->sk;
4579 struct sk_security_struct *sksec = sk->sk_security;
4579 u16 family; 4580 u16 family;
4580 int err; 4581 int err;
4581 4582
@@ -4587,11 +4588,11 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
4587 family = sk->sk_family; 4588 family = sk->sk_family;
4588 if (family == PF_INET || family == PF_INET6) { 4589 if (family == PF_INET || family == PF_INET6) {
4589 char *addrp; 4590 char *addrp;
4590 struct sk_security_struct *sksec = sk->sk_security;
4591 struct common_audit_data ad; 4591 struct common_audit_data ad;
4592 struct lsm_network_audit net = {0,}; 4592 struct lsm_network_audit net = {0,};
4593 struct sockaddr_in *addr4 = NULL; 4593 struct sockaddr_in *addr4 = NULL;
4594 struct sockaddr_in6 *addr6 = NULL; 4594 struct sockaddr_in6 *addr6 = NULL;
4595 u16 family_sa = address->sa_family;
4595 unsigned short snum; 4596 unsigned short snum;
4596 u32 sid, node_perm; 4597 u32 sid, node_perm;
4597 4598
@@ -4601,11 +4602,20 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
4601 * need to check address->sa_family as it is possible to have 4602 * need to check address->sa_family as it is possible to have
4602 * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET. 4603 * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET.
4603 */ 4604 */
4604 switch (address->sa_family) { 4605 switch (family_sa) {
4606 case AF_UNSPEC:
4605 case AF_INET: 4607 case AF_INET:
4606 if (addrlen < sizeof(struct sockaddr_in)) 4608 if (addrlen < sizeof(struct sockaddr_in))
4607 return -EINVAL; 4609 return -EINVAL;
4608 addr4 = (struct sockaddr_in *)address; 4610 addr4 = (struct sockaddr_in *)address;
4611 if (family_sa == AF_UNSPEC) {
4612 /* see __inet_bind(), we only want to allow
4613 * AF_UNSPEC if the address is INADDR_ANY
4614 */
4615 if (addr4->sin_addr.s_addr != htonl(INADDR_ANY))
4616 goto err_af;
4617 family_sa = AF_INET;
4618 }
4609 snum = ntohs(addr4->sin_port); 4619 snum = ntohs(addr4->sin_port);
4610 addrp = (char *)&addr4->sin_addr.s_addr; 4620 addrp = (char *)&addr4->sin_addr.s_addr;
4611 break; 4621 break;
@@ -4617,15 +4627,14 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
4617 addrp = (char *)&addr6->sin6_addr.s6_addr; 4627 addrp = (char *)&addr6->sin6_addr.s6_addr;
4618 break; 4628 break;
4619 default: 4629 default:
4620 /* Note that SCTP services expect -EINVAL, whereas 4630 goto err_af;
4621 * others expect -EAFNOSUPPORT.
4622 */
4623 if (sksec->sclass == SECCLASS_SCTP_SOCKET)
4624 return -EINVAL;
4625 else
4626 return -EAFNOSUPPORT;
4627 } 4631 }
4628 4632
4633 ad.type = LSM_AUDIT_DATA_NET;
4634 ad.u.net = &net;
4635 ad.u.net->sport = htons(snum);
4636 ad.u.net->family = family_sa;
4637
4629 if (snum) { 4638 if (snum) {
4630 int low, high; 4639 int low, high;
4631 4640
@@ -4637,10 +4646,6 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
4637 snum, &sid); 4646 snum, &sid);
4638 if (err) 4647 if (err)
4639 goto out; 4648 goto out;
4640 ad.type = LSM_AUDIT_DATA_NET;
4641 ad.u.net = &net;
4642 ad.u.net->sport = htons(snum);
4643 ad.u.net->family = family;
4644 err = avc_has_perm(&selinux_state, 4649 err = avc_has_perm(&selinux_state,
4645 sksec->sid, sid, 4650 sksec->sid, sid,
4646 sksec->sclass, 4651 sksec->sclass,
@@ -4672,16 +4677,11 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
4672 break; 4677 break;
4673 } 4678 }
4674 4679
4675 err = sel_netnode_sid(addrp, family, &sid); 4680 err = sel_netnode_sid(addrp, family_sa, &sid);
4676 if (err) 4681 if (err)
4677 goto out; 4682 goto out;
4678 4683
4679 ad.type = LSM_AUDIT_DATA_NET; 4684 if (family_sa == AF_INET)
4680 ad.u.net = &net;
4681 ad.u.net->sport = htons(snum);
4682 ad.u.net->family = family;
4683
4684 if (address->sa_family == AF_INET)
4685 ad.u.net->v4info.saddr = addr4->sin_addr.s_addr; 4685 ad.u.net->v4info.saddr = addr4->sin_addr.s_addr;
4686 else 4686 else
4687 ad.u.net->v6info.saddr = addr6->sin6_addr; 4687 ad.u.net->v6info.saddr = addr6->sin6_addr;
@@ -4694,6 +4694,11 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
4694 } 4694 }
4695out: 4695out:
4696 return err; 4696 return err;
4697err_af:
4698 /* Note that SCTP services expect -EINVAL, others -EAFNOSUPPORT. */
4699 if (sksec->sclass == SECCLASS_SCTP_SOCKET)
4700 return -EINVAL;
4701 return -EAFNOSUPPORT;
4697} 4702}
4698 4703
4699/* This supports connect(2) and SCTP connect services such as sctp_connectx(3) 4704/* This supports connect(2) and SCTP connect services such as sctp_connectx(3)
@@ -4771,7 +4776,7 @@ static int selinux_socket_connect_helper(struct socket *sock,
4771 ad.type = LSM_AUDIT_DATA_NET; 4776 ad.type = LSM_AUDIT_DATA_NET;
4772 ad.u.net = &net; 4777 ad.u.net = &net;
4773 ad.u.net->dport = htons(snum); 4778 ad.u.net->dport = htons(snum);
4774 ad.u.net->family = sk->sk_family; 4779 ad.u.net->family = address->sa_family;
4775 err = avc_has_perm(&selinux_state, 4780 err = avc_has_perm(&selinux_state,
4776 sksec->sid, sid, sksec->sclass, perm, &ad); 4781 sksec->sid, sid, sksec->sclass, perm, &ad);
4777 if (err) 4782 if (err)
@@ -5272,6 +5277,7 @@ static int selinux_sctp_bind_connect(struct sock *sk, int optname,
5272 while (walk_size < addrlen) { 5277 while (walk_size < addrlen) {
5273 addr = addr_buf; 5278 addr = addr_buf;
5274 switch (addr->sa_family) { 5279 switch (addr->sa_family) {
5280 case AF_UNSPEC:
5275 case AF_INET: 5281 case AF_INET:
5276 len = sizeof(struct sockaddr_in); 5282 len = sizeof(struct sockaddr_in);
5277 break; 5283 break;
@@ -5279,7 +5285,7 @@ static int selinux_sctp_bind_connect(struct sock *sk, int optname,
5279 len = sizeof(struct sockaddr_in6); 5285 len = sizeof(struct sockaddr_in6);
5280 break; 5286 break;
5281 default: 5287 default:
5282 return -EAFNOSUPPORT; 5288 return -EINVAL;
5283 } 5289 }
5284 5290
5285 err = -EINVAL; 5291 err = -EINVAL;