aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/netlabel.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/selinux/netlabel.c')
-rw-r--r--security/selinux/netlabel.c147
1 files changed, 119 insertions, 28 deletions
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index 090404d6e512..b22b7dafa0e3 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -29,10 +29,12 @@
29 29
30#include <linux/spinlock.h> 30#include <linux/spinlock.h>
31#include <linux/rcupdate.h> 31#include <linux/rcupdate.h>
32#include <linux/ip.h>
33#include <linux/ipv6.h>
32#include <net/sock.h> 34#include <net/sock.h>
33#include <net/netlabel.h> 35#include <net/netlabel.h>
34#include <net/inet_sock.h> 36#include <net/ip.h>
35#include <net/inet_connection_sock.h> 37#include <net/ipv6.h>
36 38
37#include "objsec.h" 39#include "objsec.h"
38#include "security.h" 40#include "security.h"
@@ -79,8 +81,6 @@ static int selinux_netlbl_sock_setsid(struct sock *sk)
79 int rc; 81 int rc;
80 struct sk_security_struct *sksec = sk->sk_security; 82 struct sk_security_struct *sksec = sk->sk_security;
81 struct netlbl_lsm_secattr secattr; 83 struct netlbl_lsm_secattr secattr;
82 struct inet_sock *sk_inet;
83 struct inet_connection_sock *sk_conn;
84 84
85 if (sksec->nlbl_state != NLBL_REQUIRE) 85 if (sksec->nlbl_state != NLBL_REQUIRE)
86 return 0; 86 return 0;
@@ -96,20 +96,6 @@ static int selinux_netlbl_sock_setsid(struct sock *sk)
96 sksec->nlbl_state = NLBL_LABELED; 96 sksec->nlbl_state = NLBL_LABELED;
97 break; 97 break;
98 case -EDESTADDRREQ: 98 case -EDESTADDRREQ:
99 /* we are going to possibly end up labeling the individual
100 * packets later which is problematic for stream sockets
101 * because of the additional IP header size, our solution is to
102 * allow for the maximum IP header length (40 bytes for IPv4,
103 * we don't have to worry about IPv6 yet) just in case */
104 sk_inet = inet_sk(sk);
105 if (sk_inet->is_icsk) {
106 sk_conn = inet_csk(sk);
107 if (sk_inet->opt)
108 sk_conn->icsk_ext_hdr_len -=
109 sk_inet->opt->optlen;
110 sk_conn->icsk_ext_hdr_len += 40;
111 sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
112 }
113 sksec->nlbl_state = NLBL_REQSKB; 99 sksec->nlbl_state = NLBL_REQSKB;
114 rc = 0; 100 rc = 0;
115 break; 101 break;
@@ -247,21 +233,77 @@ skbuff_setsid_return:
247} 233}
248 234
249/** 235/**
250 * selinux_netlbl_sock_graft - Netlabel the new socket 236 * selinux_netlbl_inet_conn_established - Netlabel the newly accepted connection
251 * @sk: the new connection 237 * @sk: the new connection
252 * @sock: the new socket
253 * 238 *
254 * Description: 239 * Description:
255 * The connection represented by @sk is being grafted onto @sock so set the 240 * A new connection has been established on @sk so make sure it is labeled
256 * socket's NetLabel to match the SID of @sk. 241 * correctly with the NetLabel susbsystem.
257 * 242 *
258 */ 243 */
259void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) 244void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family)
260{ 245{
261 /* Try to set the NetLabel on the socket to save time later, if we fail 246 int rc;
262 * here we will pick up the pieces in later calls to 247 struct sk_security_struct *sksec = sk->sk_security;
263 * selinux_netlbl_inode_permission(). */ 248 struct netlbl_lsm_secattr secattr;
264 selinux_netlbl_sock_setsid(sk); 249 struct inet_sock *sk_inet = inet_sk(sk);
250 struct sockaddr_in addr;
251
252 if (sksec->nlbl_state != NLBL_REQUIRE)
253 return;
254
255 netlbl_secattr_init(&secattr);
256 if (security_netlbl_sid_to_secattr(sksec->sid, &secattr) != 0)
257 goto inet_conn_established_return;
258
259 rc = netlbl_sock_setattr(sk, &secattr);
260 switch (rc) {
261 case 0:
262 sksec->nlbl_state = NLBL_LABELED;
263 break;
264 case -EDESTADDRREQ:
265 /* no PF_INET6 support yet because we don't support any IPv6
266 * labeling protocols */
267 if (family != PF_INET) {
268 sksec->nlbl_state = NLBL_UNSET;
269 goto inet_conn_established_return;
270 }
271
272 addr.sin_family = family;
273 addr.sin_addr.s_addr = sk_inet->daddr;
274 if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr,
275 &secattr) != 0) {
276 /* we failed to label the connected socket (could be
277 * for a variety of reasons, the actual "why" isn't
278 * important here) so we have to go to our backup plan,
279 * labeling the packets individually in the netfilter
280 * local output hook. this is okay but we need to
281 * adjust the MSS of the connection to take into
282 * account any labeling overhead, since we don't know
283 * the exact overhead at this point we'll use the worst
284 * case value which is 40 bytes for IPv4 */
285 struct inet_connection_sock *sk_conn = inet_csk(sk);
286 sk_conn->icsk_ext_hdr_len += 40 -
287 (sk_inet->opt ? sk_inet->opt->optlen : 0);
288 sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
289
290 sksec->nlbl_state = NLBL_REQSKB;
291 } else
292 sksec->nlbl_state = NLBL_CONNLABELED;
293 break;
294 default:
295 /* note that we are failing to label the socket which could be
296 * a bad thing since it means traffic could leave the system
297 * without the desired labeling, however, all is not lost as
298 * we have a check in selinux_netlbl_inode_permission() to
299 * pick up the pieces that we might drop here because we can't
300 * return an error code */
301 break;
302 }
303
304inet_conn_established_return:
305 netlbl_secattr_destroy(&secattr);
306 return;
265} 307}
266 308
267/** 309/**
@@ -398,7 +440,8 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
398 struct netlbl_lsm_secattr secattr; 440 struct netlbl_lsm_secattr secattr;
399 441
400 if (level == IPPROTO_IP && optname == IP_OPTIONS && 442 if (level == IPPROTO_IP && optname == IP_OPTIONS &&
401 sksec->nlbl_state == NLBL_LABELED) { 443 (sksec->nlbl_state == NLBL_LABELED ||
444 sksec->nlbl_state == NLBL_CONNLABELED)) {
402 netlbl_secattr_init(&secattr); 445 netlbl_secattr_init(&secattr);
403 lock_sock(sk); 446 lock_sock(sk);
404 rc = netlbl_sock_getattr(sk, &secattr); 447 rc = netlbl_sock_getattr(sk, &secattr);
@@ -410,3 +453,51 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
410 453
411 return rc; 454 return rc;
412} 455}
456
457/**
458 * selinux_netlbl_socket_connect - Label a client-side socket on connect
459 * @sk: the socket to label
460 * @addr: the destination address
461 *
462 * Description:
463 * Attempt to label a connected socket with NetLabel using the given address.
464 * Returns zero values on success, negative values on failure.
465 *
466 */
467int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
468{
469 int rc;
470 struct sk_security_struct *sksec = sk->sk_security;
471 struct netlbl_lsm_secattr secattr;
472
473 if (sksec->nlbl_state != NLBL_REQSKB &&
474 sksec->nlbl_state != NLBL_CONNLABELED)
475 return 0;
476
477 netlbl_secattr_init(&secattr);
478 local_bh_disable();
479 bh_lock_sock_nested(sk);
480
481 /* connected sockets are allowed to disconnect when the address family
482 * is set to AF_UNSPEC, if that is what is happening we want to reset
483 * the socket */
484 if (addr->sa_family == AF_UNSPEC) {
485 netlbl_sock_delattr(sk);
486 sksec->nlbl_state = NLBL_REQSKB;
487 rc = 0;
488 goto socket_connect_return;
489 }
490 rc = security_netlbl_sid_to_secattr(sksec->sid, &secattr);
491 if (rc != 0)
492 goto socket_connect_return;
493 rc = netlbl_conn_setattr(sk, addr, &secattr);
494 if (rc != 0)
495 goto socket_connect_return;
496 sksec->nlbl_state = NLBL_CONNLABELED;
497
498socket_connect_return:
499 bh_unlock_sock(sk);
500 local_bh_enable();
501 netlbl_secattr_destroy(&secattr);
502 return rc;
503}