aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Haines <richard_c_haines@btinternet.com>2018-02-13 15:57:18 -0500
committerPaul Moore <paul@paul-moore.com>2018-02-26 17:45:25 -0500
commitd452930fd3b9031e59abfeddb2fa383f1403d61a (patch)
treebb3c24ac8fdf0065ec09f6c4b7e70488a2a5ab58
parent2277c7cd75e39783eeb7512a6c35f8b4abbe1039 (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.rst157
-rw-r--r--security/selinux/hooks.c280
-rw-r--r--security/selinux/include/classmap.h2
-rw-r--r--security/selinux/include/netlabel.h21
-rw-r--r--security/selinux/include/objsec.h4
-rw-r--r--security/selinux/netlabel.c133
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 @@
1SCTP SELinux Support
2=====================
3
4Security Hooks
5===============
6
7``Documentation/security/LSM-sctp.rst`` describes the following SCTP security
8hooks 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
16security_sctp_assoc_request()
17-----------------------------
18Passes the ``@ep`` and ``@chunk->skb`` of the association INIT packet to the
19security 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
25The 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
42security_sctp_bind_connect()
43-----------------------------
44Checks permissions required for ipv4/ipv6 addresses based on the ``@optname``
45as 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``
68entries and also describes ASCONF chunk processing when Dynamic Address
69Reconfiguration is enabled.
70
71
72security_sctp_sk_clone()
73-------------------------
74Called whenever a new socket is created by **accept**\(2) (i.e. a TCP style
75socket) or when a socket is 'peeled off' e.g userspace calls
76**sctp_peeloff**\(3). ``security_sctp_sk_clone()`` will set the new
77sockets 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
86security_inet_conn_established()
87---------------------------------
88Called when a COOKIE ACK is received where it sets the connection's peer sid
89to that in ``@skb``::
90
91 @sk - pointer to sock structure.
92 @skb - pointer to skbuff of the COOKIE ACK packet.
93
94
95Policy Statements
96==================
97The following class and permissions to support SCTP are available within the
98kernel::
99
100 class sctp_socket inherits socket { node_bind }
101
102whenever the following policy capability is enabled::
103
104 policycap extended_socket_class;
105
106SELinux SCTP support adds the ``name_connect`` permission for connecting
107to a specific port type and the ``association`` permission that is explained
108in the section below.
109
110If userspace tools have been updated, SCTP will support the ``portcon``
111statement as shown in the following example::
112
113 portcon sctp 1024-1036 system_u:object_r:sctp_ports_t:s0
114
115
116SCTP Peer Labeling
117===================
118An SCTP socket will only have one peer label assigned to it. This will be
119assigned during the establishment of the first association. Once the peer
120label has been assigned, any new associations will have the ``association``
121permission validated by checking the socket peer sid against the received
122packets peer sid to determine whether the association should be allowed or
123denied.
124
125NOTES:
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
4517static 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 */
4562static 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
4569out: 4632/* Supports connect(2), see comments in selinux_socket_connect_helper() */
4570 return err; 4633static 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
4573static int selinux_socket_listen(struct socket *sock, int backlog) 4646static 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 */
5024static 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 */
5095static 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). */
5167static 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
4946static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, 5185static 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,
52int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, 53int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
53 u16 family, 54 u16 family,
54 u32 sid); 55 u32 sid);
55 56int selinux_netlbl_sctp_assoc_request(struct sctp_endpoint *ep,
57 struct sk_buff *skb);
56int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family); 58int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family);
57void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family); 59void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family);
60void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk);
58int selinux_netlbl_socket_post_create(struct sock *sk, u16 family); 61int selinux_netlbl_socket_post_create(struct sock *sk, u16 family);
59int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, 62int 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);
66int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr); 69int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr);
70int selinux_netlbl_socket_connect_locked(struct sock *sk,
71 struct sockaddr *addr);
67 72
68#else 73#else
69static inline void selinux_netlbl_cache_invalidate(void) 74static 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
121static inline int selinux_netlbl_sctp_assoc_request(struct sctp_endpoint *ep,
122 struct sk_buff *skb)
123{
124 return 0;
125}
116static inline int selinux_netlbl_inet_conn_request(struct request_sock *req, 126static 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}
135static inline void selinux_netlbl_sctp_sk_clone(struct sock *sk, sock *newsk)
136{
137 return;
138}
125static inline int selinux_netlbl_socket_post_create(struct sock *sk, 139static 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}
162static 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
135struct tun_security_struct { 139struct 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 */
283int 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
323assoc_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 */
385void 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 */
481int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) 554static 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
511socket_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 */
594int 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 */
616int 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}