diff options
| author | Richard Haines <richard_c_haines@btinternet.com> | 2018-02-13 15:57:18 -0500 |
|---|---|---|
| committer | Paul Moore <paul@paul-moore.com> | 2018-02-26 17:45:25 -0500 |
| commit | d452930fd3b9031e59abfeddb2fa383f1403d61a (patch) | |
| tree | bb3c24ac8fdf0065ec09f6c4b7e70488a2a5ab58 | |
| parent | 2277c7cd75e39783eeb7512a6c35f8b4abbe1039 (diff) | |
selinux: Add SCTP support
The SELinux SCTP implementation is explained in:
Documentation/security/SELinux-sctp.rst
Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
| -rw-r--r-- | Documentation/security/SELinux-sctp.rst | 157 | ||||
| -rw-r--r-- | security/selinux/hooks.c | 280 | ||||
| -rw-r--r-- | security/selinux/include/classmap.h | 2 | ||||
| -rw-r--r-- | security/selinux/include/netlabel.h | 21 | ||||
| -rw-r--r-- | security/selinux/include/objsec.h | 4 | ||||
| -rw-r--r-- | security/selinux/netlabel.c | 133 |
6 files changed, 565 insertions, 32 deletions
diff --git a/Documentation/security/SELinux-sctp.rst b/Documentation/security/SELinux-sctp.rst new file mode 100644 index 000000000000..2f66bf30658a --- /dev/null +++ b/Documentation/security/SELinux-sctp.rst | |||
| @@ -0,0 +1,157 @@ | |||
| 1 | SCTP SELinux Support | ||
| 2 | ===================== | ||
| 3 | |||
| 4 | Security Hooks | ||
| 5 | =============== | ||
| 6 | |||
| 7 | ``Documentation/security/LSM-sctp.rst`` describes the following SCTP security | ||
| 8 | hooks with the SELinux specifics expanded below:: | ||
| 9 | |||
| 10 | security_sctp_assoc_request() | ||
| 11 | security_sctp_bind_connect() | ||
| 12 | security_sctp_sk_clone() | ||
| 13 | security_inet_conn_established() | ||
| 14 | |||
| 15 | |||
| 16 | security_sctp_assoc_request() | ||
| 17 | ----------------------------- | ||
| 18 | Passes the ``@ep`` and ``@chunk->skb`` of the association INIT packet to the | ||
| 19 | security module. Returns 0 on success, error on failure. | ||
| 20 | :: | ||
| 21 | |||
| 22 | @ep - pointer to sctp endpoint structure. | ||
| 23 | @skb - pointer to skbuff of association packet. | ||
| 24 | |||
| 25 | The security module performs the following operations: | ||
| 26 | IF this is the first association on ``@ep->base.sk``, then set the peer | ||
| 27 | sid to that in ``@skb``. This will ensure there is only one peer sid | ||
| 28 | assigned to ``@ep->base.sk`` that may support multiple associations. | ||
| 29 | |||
| 30 | ELSE validate the ``@ep->base.sk peer_sid`` against the ``@skb peer sid`` | ||
| 31 | to determine whether the association should be allowed or denied. | ||
| 32 | |||
| 33 | Set the sctp ``@ep sid`` to socket's sid (from ``ep->base.sk``) with | ||
| 34 | MLS portion taken from ``@skb peer sid``. This will be used by SCTP | ||
| 35 | TCP style sockets and peeled off connections as they cause a new socket | ||
| 36 | to be generated. | ||
| 37 | |||
| 38 | If IP security options are configured (CIPSO/CALIPSO), then the ip | ||
| 39 | options are set on the socket. | ||
| 40 | |||
| 41 | |||
| 42 | security_sctp_bind_connect() | ||
| 43 | ----------------------------- | ||
| 44 | Checks permissions required for ipv4/ipv6 addresses based on the ``@optname`` | ||
| 45 | as follows:: | ||
| 46 | |||
| 47 | ------------------------------------------------------------------ | ||
| 48 | | BIND Permission Checks | | ||
| 49 | | @optname | @address contains | | ||
| 50 | |----------------------------|-----------------------------------| | ||
| 51 | | SCTP_SOCKOPT_BINDX_ADD | One or more ipv4 / ipv6 addresses | | ||
| 52 | | SCTP_PRIMARY_ADDR | Single ipv4 or ipv6 address | | ||
| 53 | | SCTP_SET_PEER_PRIMARY_ADDR | Single ipv4 or ipv6 address | | ||
| 54 | ------------------------------------------------------------------ | ||
| 55 | |||
| 56 | ------------------------------------------------------------------ | ||
| 57 | | CONNECT Permission Checks | | ||
| 58 | | @optname | @address contains | | ||
| 59 | |----------------------------|-----------------------------------| | ||
| 60 | | SCTP_SOCKOPT_CONNECTX | One or more ipv4 / ipv6 addresses | | ||
| 61 | | SCTP_PARAM_ADD_IP | One or more ipv4 / ipv6 addresses | | ||
| 62 | | SCTP_SENDMSG_CONNECT | Single ipv4 or ipv6 address | | ||
| 63 | | SCTP_PARAM_SET_PRIMARY | Single ipv4 or ipv6 address | | ||
| 64 | ------------------------------------------------------------------ | ||
| 65 | |||
| 66 | |||
| 67 | ``Documentation/security/LSM-sctp.rst`` gives a summary of the ``@optname`` | ||
| 68 | entries and also describes ASCONF chunk processing when Dynamic Address | ||
| 69 | Reconfiguration is enabled. | ||
| 70 | |||
| 71 | |||
| 72 | security_sctp_sk_clone() | ||
| 73 | ------------------------- | ||
| 74 | Called whenever a new socket is created by **accept**\(2) (i.e. a TCP style | ||
| 75 | socket) or when a socket is 'peeled off' e.g userspace calls | ||
| 76 | **sctp_peeloff**\(3). ``security_sctp_sk_clone()`` will set the new | ||
| 77 | sockets sid and peer sid to that contained in the ``@ep sid`` and | ||
| 78 | ``@ep peer sid`` respectively. | ||
| 79 | :: | ||
| 80 | |||
| 81 | @ep - pointer to current sctp endpoint structure. | ||
| 82 | @sk - pointer to current sock structure. | ||
| 83 | @sk - pointer to new sock structure. | ||
| 84 | |||
| 85 | |||
| 86 | security_inet_conn_established() | ||
| 87 | --------------------------------- | ||
| 88 | Called when a COOKIE ACK is received where it sets the connection's peer sid | ||
| 89 | to that in ``@skb``:: | ||
| 90 | |||
| 91 | @sk - pointer to sock structure. | ||
| 92 | @skb - pointer to skbuff of the COOKIE ACK packet. | ||
| 93 | |||
| 94 | |||
| 95 | Policy Statements | ||
| 96 | ================== | ||
| 97 | The following class and permissions to support SCTP are available within the | ||
| 98 | kernel:: | ||
| 99 | |||
| 100 | class sctp_socket inherits socket { node_bind } | ||
| 101 | |||
| 102 | whenever the following policy capability is enabled:: | ||
| 103 | |||
| 104 | policycap extended_socket_class; | ||
| 105 | |||
| 106 | SELinux SCTP support adds the ``name_connect`` permission for connecting | ||
| 107 | to a specific port type and the ``association`` permission that is explained | ||
| 108 | in the section below. | ||
| 109 | |||
| 110 | If userspace tools have been updated, SCTP will support the ``portcon`` | ||
| 111 | statement as shown in the following example:: | ||
| 112 | |||
| 113 | portcon sctp 1024-1036 system_u:object_r:sctp_ports_t:s0 | ||
| 114 | |||
| 115 | |||
| 116 | SCTP Peer Labeling | ||
| 117 | =================== | ||
| 118 | An SCTP socket will only have one peer label assigned to it. This will be | ||
| 119 | assigned during the establishment of the first association. Once the peer | ||
| 120 | label has been assigned, any new associations will have the ``association`` | ||
| 121 | permission validated by checking the socket peer sid against the received | ||
| 122 | packets peer sid to determine whether the association should be allowed or | ||
| 123 | denied. | ||
| 124 | |||
| 125 | NOTES: | ||
| 126 | 1) If peer labeling is not enabled, then the peer context will always be | ||
| 127 | ``SECINITSID_UNLABELED`` (``unlabeled_t`` in Reference Policy). | ||
| 128 | |||
| 129 | 2) As SCTP can support more than one transport address per endpoint | ||
| 130 | (multi-homing) on a single socket, it is possible to configure policy | ||
| 131 | and NetLabel to provide different peer labels for each of these. As the | ||
| 132 | socket peer label is determined by the first associations transport | ||
| 133 | address, it is recommended that all peer labels are consistent. | ||
| 134 | |||
| 135 | 3) **getpeercon**\(3) may be used by userspace to retrieve the sockets peer | ||
| 136 | context. | ||
| 137 | |||
| 138 | 4) While not SCTP specific, be aware when using NetLabel that if a label | ||
| 139 | is assigned to a specific interface, and that interface 'goes down', | ||
| 140 | then the NetLabel service will remove the entry. Therefore ensure that | ||
| 141 | the network startup scripts call **netlabelctl**\(8) to set the required | ||
| 142 | label (see **netlabel-config**\(8) helper script for details). | ||
| 143 | |||
| 144 | 5) The NetLabel SCTP peer labeling rules apply as discussed in the following | ||
| 145 | set of posts tagged "netlabel" at: http://www.paul-moore.com/blog/t. | ||
| 146 | |||
| 147 | 6) CIPSO is only supported for IPv4 addressing: ``socket(AF_INET, ...)`` | ||
| 148 | CALIPSO is only supported for IPv6 addressing: ``socket(AF_INET6, ...)`` | ||
| 149 | |||
| 150 | Note the following when testing CIPSO/CALIPSO: | ||
| 151 | a) CIPSO will send an ICMP packet if an SCTP packet cannot be | ||
| 152 | delivered because of an invalid label. | ||
| 153 | b) CALIPSO does not send an ICMP packet, just silently discards it. | ||
| 154 | |||
| 155 | 7) IPSEC is not supported as RFC 3554 - sctp/ipsec support has not been | ||
| 156 | implemented in userspace (**racoon**\(8) or **ipsec_pluto**\(8)), | ||
| 157 | although the kernel supports SCTP/IPSEC. | ||
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 8644d864e3c1..28a5c4ee0705 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -67,6 +67,8 @@ | |||
| 67 | #include <linux/tcp.h> | 67 | #include <linux/tcp.h> |
| 68 | #include <linux/udp.h> | 68 | #include <linux/udp.h> |
| 69 | #include <linux/dccp.h> | 69 | #include <linux/dccp.h> |
| 70 | #include <linux/sctp.h> | ||
| 71 | #include <net/sctp/structs.h> | ||
| 70 | #include <linux/quota.h> | 72 | #include <linux/quota.h> |
| 71 | #include <linux/un.h> /* for Unix socket types */ | 73 | #include <linux/un.h> /* for Unix socket types */ |
| 72 | #include <net/af_unix.h> /* for Unix socket types */ | 74 | #include <net/af_unix.h> /* for Unix socket types */ |
| @@ -4134,6 +4136,23 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb, | |||
| 4134 | break; | 4136 | break; |
| 4135 | } | 4137 | } |
| 4136 | 4138 | ||
| 4139 | #if IS_ENABLED(CONFIG_IP_SCTP) | ||
| 4140 | case IPPROTO_SCTP: { | ||
| 4141 | struct sctphdr _sctph, *sh; | ||
| 4142 | |||
| 4143 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
| 4144 | break; | ||
| 4145 | |||
| 4146 | offset += ihlen; | ||
| 4147 | sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph); | ||
| 4148 | if (sh == NULL) | ||
| 4149 | break; | ||
| 4150 | |||
| 4151 | ad->u.net->sport = sh->source; | ||
| 4152 | ad->u.net->dport = sh->dest; | ||
| 4153 | break; | ||
| 4154 | } | ||
| 4155 | #endif | ||
| 4137 | default: | 4156 | default: |
| 4138 | break; | 4157 | break; |
| 4139 | } | 4158 | } |
| @@ -4207,6 +4226,19 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb, | |||
| 4207 | break; | 4226 | break; |
| 4208 | } | 4227 | } |
| 4209 | 4228 | ||
| 4229 | #if IS_ENABLED(CONFIG_IP_SCTP) | ||
| 4230 | case IPPROTO_SCTP: { | ||
| 4231 | struct sctphdr _sctph, *sh; | ||
| 4232 | |||
| 4233 | sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph); | ||
| 4234 | if (sh == NULL) | ||
| 4235 | break; | ||
| 4236 | |||
| 4237 | ad->u.net->sport = sh->source; | ||
| 4238 | ad->u.net->dport = sh->dest; | ||
| 4239 | break; | ||
| 4240 | } | ||
| 4241 | #endif | ||
| 4210 | /* includes fragments */ | 4242 | /* includes fragments */ |
| 4211 | default: | 4243 | default: |
| 4212 | break; | 4244 | break; |
| @@ -4396,6 +4428,10 @@ static int selinux_socket_post_create(struct socket *sock, int family, | |||
| 4396 | sksec = sock->sk->sk_security; | 4428 | sksec = sock->sk->sk_security; |
| 4397 | sksec->sclass = sclass; | 4429 | sksec->sclass = sclass; |
| 4398 | sksec->sid = sid; | 4430 | sksec->sid = sid; |
| 4431 | /* Allows detection of the first association on this socket */ | ||
| 4432 | if (sksec->sclass == SECCLASS_SCTP_SOCKET) | ||
| 4433 | sksec->sctp_assoc_state = SCTP_ASSOC_UNSET; | ||
| 4434 | |||
| 4399 | err = selinux_netlbl_socket_post_create(sock->sk, family); | 4435 | err = selinux_netlbl_socket_post_create(sock->sk, family); |
| 4400 | } | 4436 | } |
| 4401 | 4437 | ||
| @@ -4416,11 +4452,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
| 4416 | if (err) | 4452 | if (err) |
| 4417 | goto out; | 4453 | goto out; |
| 4418 | 4454 | ||
| 4419 | /* | 4455 | /* If PF_INET or PF_INET6, check name_bind permission for the port. */ |
| 4420 | * If PF_INET or PF_INET6, check name_bind permission for the port. | ||
| 4421 | * Multiple address binding for SCTP is not supported yet: we just | ||
| 4422 | * check the first address now. | ||
| 4423 | */ | ||
| 4424 | family = sk->sk_family; | 4456 | family = sk->sk_family; |
| 4425 | if (family == PF_INET || family == PF_INET6) { | 4457 | if (family == PF_INET || family == PF_INET6) { |
| 4426 | char *addrp; | 4458 | char *addrp; |
| @@ -4432,7 +4464,13 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
| 4432 | unsigned short snum; | 4464 | unsigned short snum; |
| 4433 | u32 sid, node_perm; | 4465 | u32 sid, node_perm; |
| 4434 | 4466 | ||
| 4435 | if (family == PF_INET) { | 4467 | /* |
| 4468 | * sctp_bindx(3) calls via selinux_sctp_bind_connect() | ||
| 4469 | * that validates multiple binding addresses. Because of this | ||
| 4470 | * need to check address->sa_family as it is possible to have | ||
| 4471 | * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET. | ||
| 4472 | */ | ||
| 4473 | if (address->sa_family == AF_INET) { | ||
| 4436 | if (addrlen < sizeof(struct sockaddr_in)) { | 4474 | if (addrlen < sizeof(struct sockaddr_in)) { |
| 4437 | err = -EINVAL; | 4475 | err = -EINVAL; |
| 4438 | goto out; | 4476 | goto out; |
| @@ -4486,6 +4524,10 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
| 4486 | node_perm = DCCP_SOCKET__NODE_BIND; | 4524 | node_perm = DCCP_SOCKET__NODE_BIND; |
| 4487 | break; | 4525 | break; |
| 4488 | 4526 | ||
| 4527 | case SECCLASS_SCTP_SOCKET: | ||
| 4528 | node_perm = SCTP_SOCKET__NODE_BIND; | ||
| 4529 | break; | ||
| 4530 | |||
| 4489 | default: | 4531 | default: |
| 4490 | node_perm = RAWIP_SOCKET__NODE_BIND; | 4532 | node_perm = RAWIP_SOCKET__NODE_BIND; |
| 4491 | break; | 4533 | break; |
| @@ -4500,7 +4542,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
| 4500 | ad.u.net->sport = htons(snum); | 4542 | ad.u.net->sport = htons(snum); |
| 4501 | ad.u.net->family = family; | 4543 | ad.u.net->family = family; |
| 4502 | 4544 | ||
| 4503 | if (family == PF_INET) | 4545 | if (address->sa_family == AF_INET) |
| 4504 | ad.u.net->v4info.saddr = addr4->sin_addr.s_addr; | 4546 | ad.u.net->v4info.saddr = addr4->sin_addr.s_addr; |
| 4505 | else | 4547 | else |
| 4506 | ad.u.net->v6info.saddr = addr6->sin6_addr; | 4548 | ad.u.net->v6info.saddr = addr6->sin6_addr; |
| @@ -4514,7 +4556,11 @@ out: | |||
| 4514 | return err; | 4556 | return err; |
| 4515 | } | 4557 | } |
| 4516 | 4558 | ||
| 4517 | static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) | 4559 | /* This supports connect(2) and SCTP connect services such as sctp_connectx(3) |
| 4560 | * and sctp_sendmsg(3) as described in Documentation/security/LSM-sctp.txt | ||
| 4561 | */ | ||
| 4562 | static int selinux_socket_connect_helper(struct socket *sock, | ||
| 4563 | struct sockaddr *address, int addrlen) | ||
| 4518 | { | 4564 | { |
| 4519 | struct sock *sk = sock->sk; | 4565 | struct sock *sk = sock->sk; |
| 4520 | struct sk_security_struct *sksec = sk->sk_security; | 4566 | struct sk_security_struct *sksec = sk->sk_security; |
| @@ -4525,10 +4571,12 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
| 4525 | return err; | 4571 | return err; |
| 4526 | 4572 | ||
| 4527 | /* | 4573 | /* |
| 4528 | * If a TCP or DCCP socket, check name_connect permission for the port. | 4574 | * If a TCP, DCCP or SCTP socket, check name_connect permission |
| 4575 | * for the port. | ||
| 4529 | */ | 4576 | */ |
| 4530 | if (sksec->sclass == SECCLASS_TCP_SOCKET || | 4577 | if (sksec->sclass == SECCLASS_TCP_SOCKET || |
| 4531 | sksec->sclass == SECCLASS_DCCP_SOCKET) { | 4578 | sksec->sclass == SECCLASS_DCCP_SOCKET || |
| 4579 | sksec->sclass == SECCLASS_SCTP_SOCKET) { | ||
| 4532 | struct common_audit_data ad; | 4580 | struct common_audit_data ad; |
| 4533 | struct lsm_network_audit net = {0,}; | 4581 | struct lsm_network_audit net = {0,}; |
| 4534 | struct sockaddr_in *addr4 = NULL; | 4582 | struct sockaddr_in *addr4 = NULL; |
| @@ -4536,7 +4584,12 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
| 4536 | unsigned short snum; | 4584 | unsigned short snum; |
| 4537 | u32 sid, perm; | 4585 | u32 sid, perm; |
| 4538 | 4586 | ||
| 4539 | if (sk->sk_family == PF_INET) { | 4587 | /* sctp_connectx(3) calls via selinux_sctp_bind_connect() |
| 4588 | * that validates multiple connect addresses. Because of this | ||
| 4589 | * need to check address->sa_family as it is possible to have | ||
| 4590 | * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET. | ||
| 4591 | */ | ||
| 4592 | if (address->sa_family == AF_INET) { | ||
| 4540 | addr4 = (struct sockaddr_in *)address; | 4593 | addr4 = (struct sockaddr_in *)address; |
| 4541 | if (addrlen < sizeof(struct sockaddr_in)) | 4594 | if (addrlen < sizeof(struct sockaddr_in)) |
| 4542 | return -EINVAL; | 4595 | return -EINVAL; |
| @@ -4550,10 +4603,19 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
| 4550 | 4603 | ||
| 4551 | err = sel_netport_sid(sk->sk_protocol, snum, &sid); | 4604 | err = sel_netport_sid(sk->sk_protocol, snum, &sid); |
| 4552 | if (err) | 4605 | if (err) |
| 4553 | goto out; | 4606 | return err; |
| 4554 | 4607 | ||
| 4555 | perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ? | 4608 | switch (sksec->sclass) { |
| 4556 | TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT; | 4609 | case SECCLASS_TCP_SOCKET: |
| 4610 | perm = TCP_SOCKET__NAME_CONNECT; | ||
| 4611 | break; | ||
| 4612 | case SECCLASS_DCCP_SOCKET: | ||
| 4613 | perm = DCCP_SOCKET__NAME_CONNECT; | ||
| 4614 | break; | ||
| 4615 | case SECCLASS_SCTP_SOCKET: | ||
| 4616 | perm = SCTP_SOCKET__NAME_CONNECT; | ||
| 4617 | break; | ||
| 4618 | } | ||
| 4557 | 4619 | ||
| 4558 | ad.type = LSM_AUDIT_DATA_NET; | 4620 | ad.type = LSM_AUDIT_DATA_NET; |
| 4559 | ad.u.net = &net; | 4621 | ad.u.net = &net; |
| @@ -4561,13 +4623,24 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
| 4561 | ad.u.net->family = sk->sk_family; | 4623 | ad.u.net->family = sk->sk_family; |
| 4562 | err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad); | 4624 | err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad); |
| 4563 | if (err) | 4625 | if (err) |
| 4564 | goto out; | 4626 | return err; |
| 4565 | } | 4627 | } |
| 4566 | 4628 | ||
| 4567 | err = selinux_netlbl_socket_connect(sk, address); | 4629 | return 0; |
| 4630 | } | ||
| 4568 | 4631 | ||
| 4569 | out: | 4632 | /* Supports connect(2), see comments in selinux_socket_connect_helper() */ |
| 4570 | return err; | 4633 | static int selinux_socket_connect(struct socket *sock, |
| 4634 | struct sockaddr *address, int addrlen) | ||
| 4635 | { | ||
| 4636 | int err; | ||
| 4637 | struct sock *sk = sock->sk; | ||
| 4638 | |||
| 4639 | err = selinux_socket_connect_helper(sock, address, addrlen); | ||
| 4640 | if (err) | ||
| 4641 | return err; | ||
| 4642 | |||
| 4643 | return selinux_netlbl_socket_connect(sk, address); | ||
| 4571 | } | 4644 | } |
| 4572 | 4645 | ||
| 4573 | static int selinux_socket_listen(struct socket *sock, int backlog) | 4646 | static int selinux_socket_listen(struct socket *sock, int backlog) |
| @@ -4830,7 +4903,8 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op | |||
| 4830 | u32 peer_sid = SECSID_NULL; | 4903 | u32 peer_sid = SECSID_NULL; |
| 4831 | 4904 | ||
| 4832 | if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET || | 4905 | if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET || |
| 4833 | sksec->sclass == SECCLASS_TCP_SOCKET) | 4906 | sksec->sclass == SECCLASS_TCP_SOCKET || |
| 4907 | sksec->sclass == SECCLASS_SCTP_SOCKET) | ||
| 4834 | peer_sid = sksec->peer_sid; | 4908 | peer_sid = sksec->peer_sid; |
| 4835 | if (peer_sid == SECSID_NULL) | 4909 | if (peer_sid == SECSID_NULL) |
| 4836 | return -ENOPROTOOPT; | 4910 | return -ENOPROTOOPT; |
| @@ -4943,6 +5017,171 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent) | |||
| 4943 | sksec->sclass = isec->sclass; | 5017 | sksec->sclass = isec->sclass; |
| 4944 | } | 5018 | } |
| 4945 | 5019 | ||
| 5020 | /* Called whenever SCTP receives an INIT chunk. This happens when an incoming | ||
| 5021 | * connect(2), sctp_connectx(3) or sctp_sendmsg(3) (with no association | ||
| 5022 | * already present). | ||
| 5023 | */ | ||
| 5024 | static int selinux_sctp_assoc_request(struct sctp_endpoint *ep, | ||
| 5025 | struct sk_buff *skb) | ||
| 5026 | { | ||
| 5027 | struct sk_security_struct *sksec = ep->base.sk->sk_security; | ||
| 5028 | struct common_audit_data ad; | ||
| 5029 | struct lsm_network_audit net = {0,}; | ||
| 5030 | u8 peerlbl_active; | ||
| 5031 | u32 peer_sid = SECINITSID_UNLABELED; | ||
| 5032 | u32 conn_sid; | ||
| 5033 | int err = 0; | ||
| 5034 | |||
| 5035 | if (!selinux_policycap_extsockclass) | ||
| 5036 | return 0; | ||
| 5037 | |||
| 5038 | peerlbl_active = selinux_peerlbl_enabled(); | ||
| 5039 | |||
| 5040 | if (peerlbl_active) { | ||
| 5041 | /* This will return peer_sid = SECSID_NULL if there are | ||
| 5042 | * no peer labels, see security_net_peersid_resolve(). | ||
| 5043 | */ | ||
| 5044 | err = selinux_skb_peerlbl_sid(skb, ep->base.sk->sk_family, | ||
| 5045 | &peer_sid); | ||
| 5046 | if (err) | ||
| 5047 | return err; | ||
| 5048 | |||
| 5049 | if (peer_sid == SECSID_NULL) | ||
| 5050 | peer_sid = SECINITSID_UNLABELED; | ||
| 5051 | } | ||
| 5052 | |||
| 5053 | if (sksec->sctp_assoc_state == SCTP_ASSOC_UNSET) { | ||
| 5054 | sksec->sctp_assoc_state = SCTP_ASSOC_SET; | ||
| 5055 | |||
| 5056 | /* Here as first association on socket. As the peer SID | ||
| 5057 | * was allowed by peer recv (and the netif/node checks), | ||
| 5058 | * then it is approved by policy and used as the primary | ||
| 5059 | * peer SID for getpeercon(3). | ||
| 5060 | */ | ||
| 5061 | sksec->peer_sid = peer_sid; | ||
| 5062 | } else if (sksec->peer_sid != peer_sid) { | ||
| 5063 | /* Other association peer SIDs are checked to enforce | ||
| 5064 | * consistency among the peer SIDs. | ||
| 5065 | */ | ||
| 5066 | ad.type = LSM_AUDIT_DATA_NET; | ||
| 5067 | ad.u.net = &net; | ||
| 5068 | ad.u.net->sk = ep->base.sk; | ||
| 5069 | err = avc_has_perm(sksec->peer_sid, peer_sid, sksec->sclass, | ||
| 5070 | SCTP_SOCKET__ASSOCIATION, &ad); | ||
| 5071 | if (err) | ||
| 5072 | return err; | ||
| 5073 | } | ||
| 5074 | |||
| 5075 | /* Compute the MLS component for the connection and store | ||
| 5076 | * the information in ep. This will be used by SCTP TCP type | ||
| 5077 | * sockets and peeled off connections as they cause a new | ||
| 5078 | * socket to be generated. selinux_sctp_sk_clone() will then | ||
| 5079 | * plug this into the new socket. | ||
| 5080 | */ | ||
| 5081 | err = selinux_conn_sid(sksec->sid, peer_sid, &conn_sid); | ||
| 5082 | if (err) | ||
| 5083 | return err; | ||
| 5084 | |||
| 5085 | ep->secid = conn_sid; | ||
| 5086 | ep->peer_secid = peer_sid; | ||
| 5087 | |||
| 5088 | /* Set any NetLabel labels including CIPSO/CALIPSO options. */ | ||
| 5089 | return selinux_netlbl_sctp_assoc_request(ep, skb); | ||
| 5090 | } | ||
| 5091 | |||
| 5092 | /* Check if sctp IPv4/IPv6 addresses are valid for binding or connecting | ||
| 5093 | * based on their @optname. | ||
| 5094 | */ | ||
| 5095 | static int selinux_sctp_bind_connect(struct sock *sk, int optname, | ||
| 5096 | struct sockaddr *address, | ||
| 5097 | int addrlen) | ||
| 5098 | { | ||
| 5099 | int len, err = 0, walk_size = 0; | ||
| 5100 | void *addr_buf; | ||
| 5101 | struct sockaddr *addr; | ||
| 5102 | struct socket *sock; | ||
| 5103 | |||
| 5104 | if (!selinux_policycap_extsockclass) | ||
| 5105 | return 0; | ||
| 5106 | |||
| 5107 | /* Process one or more addresses that may be IPv4 or IPv6 */ | ||
| 5108 | sock = sk->sk_socket; | ||
| 5109 | addr_buf = address; | ||
| 5110 | |||
| 5111 | while (walk_size < addrlen) { | ||
| 5112 | addr = addr_buf; | ||
| 5113 | switch (addr->sa_family) { | ||
| 5114 | case AF_INET: | ||
| 5115 | len = sizeof(struct sockaddr_in); | ||
| 5116 | break; | ||
| 5117 | case AF_INET6: | ||
| 5118 | len = sizeof(struct sockaddr_in6); | ||
| 5119 | break; | ||
| 5120 | default: | ||
| 5121 | return -EAFNOSUPPORT; | ||
| 5122 | } | ||
| 5123 | |||
| 5124 | err = -EINVAL; | ||
| 5125 | switch (optname) { | ||
| 5126 | /* Bind checks */ | ||
| 5127 | case SCTP_PRIMARY_ADDR: | ||
| 5128 | case SCTP_SET_PEER_PRIMARY_ADDR: | ||
| 5129 | case SCTP_SOCKOPT_BINDX_ADD: | ||
| 5130 | err = selinux_socket_bind(sock, addr, len); | ||
| 5131 | break; | ||
| 5132 | /* Connect checks */ | ||
| 5133 | case SCTP_SOCKOPT_CONNECTX: | ||
| 5134 | case SCTP_PARAM_SET_PRIMARY: | ||
| 5135 | case SCTP_PARAM_ADD_IP: | ||
| 5136 | case SCTP_SENDMSG_CONNECT: | ||
| 5137 | err = selinux_socket_connect_helper(sock, addr, len); | ||
| 5138 | if (err) | ||
| 5139 | return err; | ||
| 5140 | |||
| 5141 | /* As selinux_sctp_bind_connect() is called by the | ||
| 5142 | * SCTP protocol layer, the socket is already locked, | ||
| 5143 | * therefore selinux_netlbl_socket_connect_locked() is | ||
| 5144 | * is called here. The situations handled are: | ||
| 5145 | * sctp_connectx(3), sctp_sendmsg(3), sendmsg(2), | ||
| 5146 | * whenever a new IP address is added or when a new | ||
| 5147 | * primary address is selected. | ||
| 5148 | * Note that an SCTP connect(2) call happens before | ||
| 5149 | * the SCTP protocol layer and is handled via | ||
| 5150 | * selinux_socket_connect(). | ||
| 5151 | */ | ||
| 5152 | err = selinux_netlbl_socket_connect_locked(sk, addr); | ||
| 5153 | break; | ||
| 5154 | } | ||
| 5155 | |||
| 5156 | if (err) | ||
| 5157 | return err; | ||
| 5158 | |||
| 5159 | addr_buf += len; | ||
| 5160 | walk_size += len; | ||
| 5161 | } | ||
| 5162 | |||
| 5163 | return 0; | ||
| 5164 | } | ||
| 5165 | |||
| 5166 | /* Called whenever a new socket is created by accept(2) or sctp_peeloff(3). */ | ||
| 5167 | static void selinux_sctp_sk_clone(struct sctp_endpoint *ep, struct sock *sk, | ||
| 5168 | struct sock *newsk) | ||
| 5169 | { | ||
| 5170 | struct sk_security_struct *sksec = sk->sk_security; | ||
| 5171 | struct sk_security_struct *newsksec = newsk->sk_security; | ||
| 5172 | |||
| 5173 | /* If policy does not support SECCLASS_SCTP_SOCKET then call | ||
| 5174 | * the non-sctp clone version. | ||
| 5175 | */ | ||
| 5176 | if (!selinux_policycap_extsockclass) | ||
| 5177 | return selinux_sk_clone_security(sk, newsk); | ||
| 5178 | |||
| 5179 | newsksec->sid = ep->secid; | ||
| 5180 | newsksec->peer_sid = ep->peer_secid; | ||
| 5181 | newsksec->sclass = sksec->sclass; | ||
| 5182 | selinux_netlbl_sctp_sk_clone(sk, newsk); | ||
| 5183 | } | ||
| 5184 | |||
| 4946 | static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | 5185 | static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, |
| 4947 | struct request_sock *req) | 5186 | struct request_sock *req) |
| 4948 | { | 5187 | { |
| @@ -6563,6 +6802,9 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { | |||
| 6563 | LSM_HOOK_INIT(sk_clone_security, selinux_sk_clone_security), | 6802 | LSM_HOOK_INIT(sk_clone_security, selinux_sk_clone_security), |
| 6564 | LSM_HOOK_INIT(sk_getsecid, selinux_sk_getsecid), | 6803 | LSM_HOOK_INIT(sk_getsecid, selinux_sk_getsecid), |
| 6565 | LSM_HOOK_INIT(sock_graft, selinux_sock_graft), | 6804 | LSM_HOOK_INIT(sock_graft, selinux_sock_graft), |
| 6805 | LSM_HOOK_INIT(sctp_assoc_request, selinux_sctp_assoc_request), | ||
| 6806 | LSM_HOOK_INIT(sctp_sk_clone, selinux_sctp_sk_clone), | ||
| 6807 | LSM_HOOK_INIT(sctp_bind_connect, selinux_sctp_bind_connect), | ||
| 6566 | LSM_HOOK_INIT(inet_conn_request, selinux_inet_conn_request), | 6808 | LSM_HOOK_INIT(inet_conn_request, selinux_inet_conn_request), |
| 6567 | LSM_HOOK_INIT(inet_csk_clone, selinux_inet_csk_clone), | 6809 | LSM_HOOK_INIT(inet_csk_clone, selinux_inet_csk_clone), |
| 6568 | LSM_HOOK_INIT(inet_conn_established, selinux_inet_conn_established), | 6810 | LSM_HOOK_INIT(inet_conn_established, selinux_inet_conn_established), |
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index acdee7795297..7f0372426494 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h | |||
| @@ -176,7 +176,7 @@ struct security_class_mapping secclass_map[] = { | |||
| 176 | { COMMON_CAP2_PERMS, NULL } }, | 176 | { COMMON_CAP2_PERMS, NULL } }, |
| 177 | { "sctp_socket", | 177 | { "sctp_socket", |
| 178 | { COMMON_SOCK_PERMS, | 178 | { COMMON_SOCK_PERMS, |
| 179 | "node_bind", NULL } }, | 179 | "node_bind", "name_connect", "association", NULL } }, |
| 180 | { "icmp_socket", | 180 | { "icmp_socket", |
| 181 | { COMMON_SOCK_PERMS, | 181 | { COMMON_SOCK_PERMS, |
| 182 | "node_bind", NULL } }, | 182 | "node_bind", NULL } }, |
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h index e77a5e307955..6ef4953431dc 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #include <linux/skbuff.h> | 32 | #include <linux/skbuff.h> |
| 33 | #include <net/sock.h> | 33 | #include <net/sock.h> |
| 34 | #include <net/request_sock.h> | 34 | #include <net/request_sock.h> |
| 35 | #include <net/sctp/structs.h> | ||
| 35 | 36 | ||
| 36 | #include "avc.h" | 37 | #include "avc.h" |
| 37 | #include "objsec.h" | 38 | #include "objsec.h" |
| @@ -52,9 +53,11 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | |||
| 52 | int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | 53 | int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, |
| 53 | u16 family, | 54 | u16 family, |
| 54 | u32 sid); | 55 | u32 sid); |
| 55 | 56 | int selinux_netlbl_sctp_assoc_request(struct sctp_endpoint *ep, | |
| 57 | struct sk_buff *skb); | ||
| 56 | int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family); | 58 | int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family); |
| 57 | void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family); | 59 | void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family); |
| 60 | void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk); | ||
| 58 | int selinux_netlbl_socket_post_create(struct sock *sk, u16 family); | 61 | int selinux_netlbl_socket_post_create(struct sock *sk, u16 family); |
| 59 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | 62 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, |
| 60 | struct sk_buff *skb, | 63 | struct sk_buff *skb, |
| @@ -64,6 +67,8 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, | |||
| 64 | int level, | 67 | int level, |
| 65 | int optname); | 68 | int optname); |
| 66 | int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr); | 69 | int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr); |
| 70 | int selinux_netlbl_socket_connect_locked(struct sock *sk, | ||
| 71 | struct sockaddr *addr); | ||
| 67 | 72 | ||
| 68 | #else | 73 | #else |
| 69 | static inline void selinux_netlbl_cache_invalidate(void) | 74 | static inline void selinux_netlbl_cache_invalidate(void) |
| @@ -113,6 +118,11 @@ static inline int selinux_netlbl_conn_setsid(struct sock *sk, | |||
| 113 | return 0; | 118 | return 0; |
| 114 | } | 119 | } |
| 115 | 120 | ||
| 121 | static inline int selinux_netlbl_sctp_assoc_request(struct sctp_endpoint *ep, | ||
| 122 | struct sk_buff *skb) | ||
| 123 | { | ||
| 124 | return 0; | ||
| 125 | } | ||
| 116 | static inline int selinux_netlbl_inet_conn_request(struct request_sock *req, | 126 | static inline int selinux_netlbl_inet_conn_request(struct request_sock *req, |
| 117 | u16 family) | 127 | u16 family) |
| 118 | { | 128 | { |
| @@ -122,6 +132,10 @@ static inline void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family) | |||
| 122 | { | 132 | { |
| 123 | return; | 133 | return; |
| 124 | } | 134 | } |
| 135 | static inline void selinux_netlbl_sctp_sk_clone(struct sock *sk, sock *newsk) | ||
| 136 | { | ||
| 137 | return; | ||
| 138 | } | ||
| 125 | static inline int selinux_netlbl_socket_post_create(struct sock *sk, | 139 | static inline int selinux_netlbl_socket_post_create(struct sock *sk, |
| 126 | u16 family) | 140 | u16 family) |
| 127 | { | 141 | { |
| @@ -145,6 +159,11 @@ static inline int selinux_netlbl_socket_connect(struct sock *sk, | |||
| 145 | { | 159 | { |
| 146 | return 0; | 160 | return 0; |
| 147 | } | 161 | } |
| 162 | static inline int selinux_netlbl_socket_connect_locked(struct sock *sk, | ||
| 163 | struct sockaddr *addr) | ||
| 164 | { | ||
| 165 | return 0; | ||
| 166 | } | ||
| 148 | #endif /* CONFIG_NETLABEL */ | 167 | #endif /* CONFIG_NETLABEL */ |
| 149 | 168 | ||
| 150 | #endif | 169 | #endif |
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 3d54468ce334..dabf02888a95 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
| @@ -130,6 +130,10 @@ struct sk_security_struct { | |||
| 130 | u32 sid; /* SID of this object */ | 130 | u32 sid; /* SID of this object */ |
| 131 | u32 peer_sid; /* SID of peer */ | 131 | u32 peer_sid; /* SID of peer */ |
| 132 | u16 sclass; /* sock security class */ | 132 | u16 sclass; /* sock security class */ |
| 133 | enum { /* SCTP association state */ | ||
| 134 | SCTP_ASSOC_UNSET = 0, | ||
| 135 | SCTP_ASSOC_SET, | ||
| 136 | } sctp_assoc_state; | ||
| 133 | }; | 137 | }; |
| 134 | 138 | ||
| 135 | struct tun_security_struct { | 139 | struct tun_security_struct { |
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 2c297b995b16..8730be427390 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c | |||
| @@ -249,6 +249,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | |||
| 249 | sk = skb_to_full_sk(skb); | 249 | sk = skb_to_full_sk(skb); |
| 250 | if (sk != NULL) { | 250 | if (sk != NULL) { |
| 251 | struct sk_security_struct *sksec = sk->sk_security; | 251 | struct sk_security_struct *sksec = sk->sk_security; |
| 252 | |||
| 252 | if (sksec->nlbl_state != NLBL_REQSKB) | 253 | if (sksec->nlbl_state != NLBL_REQSKB) |
| 253 | return 0; | 254 | return 0; |
| 254 | secattr = selinux_netlbl_sock_getattr(sk, sid); | 255 | secattr = selinux_netlbl_sock_getattr(sk, sid); |
| @@ -270,6 +271,61 @@ skbuff_setsid_return: | |||
| 270 | } | 271 | } |
| 271 | 272 | ||
| 272 | /** | 273 | /** |
| 274 | * selinux_netlbl_sctp_assoc_request - Label an incoming sctp association. | ||
| 275 | * @ep: incoming association endpoint. | ||
| 276 | * @skb: the packet. | ||
| 277 | * | ||
| 278 | * Description: | ||
| 279 | * A new incoming connection is represented by @ep, ...... | ||
| 280 | * Returns zero on success, negative values on failure. | ||
| 281 | * | ||
| 282 | */ | ||
| 283 | int selinux_netlbl_sctp_assoc_request(struct sctp_endpoint *ep, | ||
| 284 | struct sk_buff *skb) | ||
| 285 | { | ||
| 286 | int rc; | ||
| 287 | struct netlbl_lsm_secattr secattr; | ||
| 288 | struct sk_security_struct *sksec = ep->base.sk->sk_security; | ||
| 289 | struct sockaddr *addr; | ||
| 290 | struct sockaddr_in addr4; | ||
| 291 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 292 | struct sockaddr_in6 addr6; | ||
| 293 | #endif | ||
| 294 | |||
| 295 | if (ep->base.sk->sk_family != PF_INET && | ||
| 296 | ep->base.sk->sk_family != PF_INET6) | ||
| 297 | return 0; | ||
| 298 | |||
| 299 | netlbl_secattr_init(&secattr); | ||
| 300 | rc = security_netlbl_sid_to_secattr(ep->secid, &secattr); | ||
| 301 | if (rc != 0) | ||
| 302 | goto assoc_request_return; | ||
| 303 | |||
| 304 | /* Move skb hdr address info to a struct sockaddr and then call | ||
| 305 | * netlbl_conn_setattr(). | ||
| 306 | */ | ||
| 307 | if (ip_hdr(skb)->version == 4) { | ||
| 308 | addr4.sin_family = AF_INET; | ||
| 309 | addr4.sin_addr.s_addr = ip_hdr(skb)->saddr; | ||
| 310 | addr = (struct sockaddr *)&addr4; | ||
| 311 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 312 | } else { | ||
| 313 | addr6.sin6_family = AF_INET6; | ||
| 314 | addr6.sin6_addr = ipv6_hdr(skb)->saddr; | ||
| 315 | addr = (struct sockaddr *)&addr6; | ||
| 316 | #endif | ||
| 317 | } | ||
| 318 | |||
| 319 | rc = netlbl_conn_setattr(ep->base.sk, addr, &secattr); | ||
| 320 | if (rc == 0) | ||
| 321 | sksec->nlbl_state = NLBL_LABELED; | ||
| 322 | |||
| 323 | assoc_request_return: | ||
| 324 | netlbl_secattr_destroy(&secattr); | ||
| 325 | return rc; | ||
| 326 | } | ||
| 327 | |||
| 328 | /** | ||
| 273 | * selinux_netlbl_inet_conn_request - Label an incoming stream connection | 329 | * selinux_netlbl_inet_conn_request - Label an incoming stream connection |
| 274 | * @req: incoming connection request socket | 330 | * @req: incoming connection request socket |
| 275 | * | 331 | * |
| @@ -319,6 +375,22 @@ void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family) | |||
| 319 | } | 375 | } |
| 320 | 376 | ||
| 321 | /** | 377 | /** |
| 378 | * selinux_netlbl_sctp_sk_clone - Copy state to the newly created sock | ||
| 379 | * @sk: current sock | ||
| 380 | * @newsk: the new sock | ||
| 381 | * | ||
| 382 | * Description: | ||
| 383 | * Called whenever a new socket is created by accept(2) or sctp_peeloff(3). | ||
| 384 | */ | ||
| 385 | void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk) | ||
| 386 | { | ||
| 387 | struct sk_security_struct *sksec = sk->sk_security; | ||
| 388 | struct sk_security_struct *newsksec = newsk->sk_security; | ||
| 389 | |||
| 390 | newsksec->nlbl_state = sksec->nlbl_state; | ||
| 391 | } | ||
| 392 | |||
| 393 | /** | ||
| 322 | * selinux_netlbl_socket_post_create - Label a socket using NetLabel | 394 | * selinux_netlbl_socket_post_create - Label a socket using NetLabel |
| 323 | * @sock: the socket to label | 395 | * @sock: the socket to label |
| 324 | * @family: protocol family | 396 | * @family: protocol family |
| @@ -469,7 +541,8 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, | |||
| 469 | } | 541 | } |
| 470 | 542 | ||
| 471 | /** | 543 | /** |
| 472 | * selinux_netlbl_socket_connect - Label a client-side socket on connect | 544 | * selinux_netlbl_socket_connect_helper - Help label a client-side socket on |
| 545 | * connect | ||
| 473 | * @sk: the socket to label | 546 | * @sk: the socket to label |
| 474 | * @addr: the destination address | 547 | * @addr: the destination address |
| 475 | * | 548 | * |
| @@ -478,18 +551,13 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, | |||
| 478 | * Returns zero values on success, negative values on failure. | 551 | * Returns zero values on success, negative values on failure. |
| 479 | * | 552 | * |
| 480 | */ | 553 | */ |
| 481 | int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) | 554 | static int selinux_netlbl_socket_connect_helper(struct sock *sk, |
| 555 | struct sockaddr *addr) | ||
| 482 | { | 556 | { |
| 483 | int rc; | 557 | int rc; |
| 484 | struct sk_security_struct *sksec = sk->sk_security; | 558 | struct sk_security_struct *sksec = sk->sk_security; |
| 485 | struct netlbl_lsm_secattr *secattr; | 559 | struct netlbl_lsm_secattr *secattr; |
| 486 | 560 | ||
| 487 | if (sksec->nlbl_state != NLBL_REQSKB && | ||
| 488 | sksec->nlbl_state != NLBL_CONNLABELED) | ||
| 489 | return 0; | ||
| 490 | |||
| 491 | lock_sock(sk); | ||
| 492 | |||
| 493 | /* connected sockets are allowed to disconnect when the address family | 561 | /* connected sockets are allowed to disconnect when the address family |
| 494 | * is set to AF_UNSPEC, if that is what is happening we want to reset | 562 | * is set to AF_UNSPEC, if that is what is happening we want to reset |
| 495 | * the socket */ | 563 | * the socket */ |
| @@ -497,18 +565,61 @@ int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) | |||
| 497 | netlbl_sock_delattr(sk); | 565 | netlbl_sock_delattr(sk); |
| 498 | sksec->nlbl_state = NLBL_REQSKB; | 566 | sksec->nlbl_state = NLBL_REQSKB; |
| 499 | rc = 0; | 567 | rc = 0; |
| 500 | goto socket_connect_return; | 568 | return rc; |
| 501 | } | 569 | } |
| 502 | secattr = selinux_netlbl_sock_genattr(sk); | 570 | secattr = selinux_netlbl_sock_genattr(sk); |
| 503 | if (secattr == NULL) { | 571 | if (secattr == NULL) { |
| 504 | rc = -ENOMEM; | 572 | rc = -ENOMEM; |
| 505 | goto socket_connect_return; | 573 | return rc; |
| 506 | } | 574 | } |
| 507 | rc = netlbl_conn_setattr(sk, addr, secattr); | 575 | rc = netlbl_conn_setattr(sk, addr, secattr); |
| 508 | if (rc == 0) | 576 | if (rc == 0) |
| 509 | sksec->nlbl_state = NLBL_CONNLABELED; | 577 | sksec->nlbl_state = NLBL_CONNLABELED; |
| 510 | 578 | ||
| 511 | socket_connect_return: | 579 | return rc; |
| 580 | } | ||
| 581 | |||
| 582 | /** | ||
| 583 | * selinux_netlbl_socket_connect_locked - Label a client-side socket on | ||
| 584 | * connect | ||
| 585 | * @sk: the socket to label | ||
| 586 | * @addr: the destination address | ||
| 587 | * | ||
| 588 | * Description: | ||
| 589 | * Attempt to label a connected socket that already has the socket locked | ||
| 590 | * with NetLabel using the given address. | ||
| 591 | * Returns zero values on success, negative values on failure. | ||
| 592 | * | ||
| 593 | */ | ||
| 594 | int selinux_netlbl_socket_connect_locked(struct sock *sk, | ||
| 595 | struct sockaddr *addr) | ||
| 596 | { | ||
| 597 | struct sk_security_struct *sksec = sk->sk_security; | ||
| 598 | |||
| 599 | if (sksec->nlbl_state != NLBL_REQSKB && | ||
| 600 | sksec->nlbl_state != NLBL_CONNLABELED) | ||
| 601 | return 0; | ||
| 602 | |||
| 603 | return selinux_netlbl_socket_connect_helper(sk, addr); | ||
| 604 | } | ||
| 605 | |||
| 606 | /** | ||
| 607 | * selinux_netlbl_socket_connect - Label a client-side socket on connect | ||
| 608 | * @sk: the socket to label | ||
| 609 | * @addr: the destination address | ||
| 610 | * | ||
| 611 | * Description: | ||
| 612 | * Attempt to label a connected socket with NetLabel using the given address. | ||
| 613 | * Returns zero values on success, negative values on failure. | ||
| 614 | * | ||
| 615 | */ | ||
| 616 | int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) | ||
| 617 | { | ||
| 618 | int rc; | ||
| 619 | |||
| 620 | lock_sock(sk); | ||
| 621 | rc = selinux_netlbl_socket_connect_locked(sk, addr); | ||
| 512 | release_sock(sk); | 622 | release_sock(sk); |
| 623 | |||
| 513 | return rc; | 624 | return rc; |
| 514 | } | 625 | } |
