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 | } |