netlabel.c 16.4 KB
Newer Older
1 2 3 4 5 6
/*
 * SELinux NetLabel Support
 *
 * This file provides the necessary glue to tie NetLabel into the SELinux
 * subsystem.
 *
7
 * Author: Paul Moore <paul@paul-moore.com>
8 9 10 11
 *
 */

/*
12
 * (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008
13 14 15 16 17 18 19 20 21 22 23 24
 *
 * This program is free software;  you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY;  without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 * the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
25
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
26 27 28 29 30
 *
 */

#include <linux/spinlock.h>
#include <linux/rcupdate.h>
31
#include <linux/gfp.h>
32 33
#include <linux/ip.h>
#include <linux/ipv6.h>
34 35
#include <net/sock.h>
#include <net/netlabel.h>
36 37
#include <net/ip.h>
#include <net/ipv6.h>
38 39 40

#include "objsec.h"
#include "security.h"
41
#include "netlabel.h"
42

43 44 45 46 47 48 49 50 51 52 53 54 55
/**
 * selinux_netlbl_sidlookup_cached - Cache a SID lookup
 * @skb: the packet
 * @secattr: the NetLabel security attributes
 * @sid: the SID
 *
 * Description:
 * Query the SELinux security server to lookup the correct SID for the given
 * security attributes.  If the query is successful, cache the result to speed
 * up future lookups.  Returns zero on success, negative values on failure.
 *
 */
static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
H
Huw Davies 已提交
56
					   u16 family,
57 58 59 60 61
					   struct netlbl_lsm_secattr *secattr,
					   u32 *sid)
{
	int rc;

62
	rc = security_netlbl_secattr_to_sid(&selinux_state, secattr, sid);
63 64 65
	if (rc == 0 &&
	    (secattr->flags & NETLBL_SECATTR_CACHEABLE) &&
	    (secattr->flags & NETLBL_SECATTR_CACHE))
H
Huw Davies 已提交
66
		netlbl_cache_add(skb, family, secattr);
67 68 69 70

	return rc;
}

71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
/**
 * selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr
 * @sk: the socket
 *
 * Description:
 * Generate the NetLabel security attributes for a socket, making full use of
 * the socket's attribute cache.  Returns a pointer to the security attributes
 * on success, NULL on failure.
 *
 */
static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
{
	int rc;
	struct sk_security_struct *sksec = sk->sk_security;
	struct netlbl_lsm_secattr *secattr;

	if (sksec->nlbl_secattr != NULL)
		return sksec->nlbl_secattr;

	secattr = netlbl_secattr_alloc(GFP_ATOMIC);
	if (secattr == NULL)
		return NULL;
93 94
	rc = security_netlbl_sid_to_secattr(&selinux_state, sksec->sid,
					    secattr);
95 96 97 98 99 100 101 102 103
	if (rc != 0) {
		netlbl_secattr_free(secattr);
		return NULL;
	}
	sksec->nlbl_secattr = secattr;

	return secattr;
}

104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
/**
 * selinux_netlbl_sock_getattr - Get the cached NetLabel secattr
 * @sk: the socket
 * @sid: the SID
 *
 * Query the socket's cached secattr and if the SID matches the cached value
 * return the cache, otherwise return NULL.
 *
 */
static struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr(
							const struct sock *sk,
							u32 sid)
{
	struct sk_security_struct *sksec = sk->sk_security;
	struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr;

	if (secattr == NULL)
		return NULL;

	if ((secattr->flags & NETLBL_SECATTR_SECID) &&
	    (secattr->attr.secid == sid))
		return secattr;

	return NULL;
}

130 131 132 133 134 135 136 137 138 139 140 141
/**
 * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
 *
 * Description:
 * Invalidate the NetLabel security attribute mapping cache.
 *
 */
void selinux_netlbl_cache_invalidate(void)
{
	netlbl_cache_invalidate();
}

142 143 144 145 146 147 148 149 150 151 152 153 154
/**
 * selinux_netlbl_err - Handle a NetLabel packet error
 * @skb: the packet
 * @error: the error code
 * @gateway: true if host is acting as a gateway, false otherwise
 *
 * Description:
 * When a packet is dropped due to a call to avc_has_perm() pass the error
 * code to the NetLabel subsystem so any protocol specific processing can be
 * done.  This is safe to call even if you are unsure if NetLabel labeling is
 * present on the packet, NetLabel is smart enough to only act when it should.
 *
 */
155
void selinux_netlbl_err(struct sk_buff *skb, u16 family, int error, int gateway)
156
{
157
	netlbl_skbuff_err(skb, family, error, gateway);
158 159
}

160 161
/**
 * selinux_netlbl_sk_security_free - Free the NetLabel fields
162
 * @sksec: the sk_security_struct
163 164 165 166 167
 *
 * Description:
 * Free all of the memory in the NetLabel fields of a sk_security_struct.
 *
 */
168
void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec)
169
{
170 171
	if (sksec->nlbl_secattr != NULL)
		netlbl_secattr_free(sksec->nlbl_secattr);
172 173
}

174 175
/**
 * selinux_netlbl_sk_security_reset - Reset the NetLabel fields
176
 * @sksec: the sk_security_struct
177 178 179 180
 * @family: the socket family
 *
 * Description:
 * Called when the NetLabel state of a sk_security_struct needs to be reset.
L
Lucas De Marchi 已提交
181
 * The caller is responsible for all the NetLabel sk_security_struct locking.
182 183
 *
 */
184
void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec)
185
{
186
	sksec->nlbl_state = NLBL_UNSET;
187 188 189 190 191
}

/**
 * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
 * @skb: the packet
192
 * @family: protocol family
193
 * @type: NetLabel labeling protocol type
194 195 196 197 198 199 200 201
 * @sid: the SID
 *
 * Description:
 * Call the NetLabel mechanism to get the security attributes of the given
 * packet and use those attributes to determine the correct context/SID to
 * assign to the packet.  Returns zero on success, negative values on failure.
 *
 */
202 203
int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
				 u16 family,
204
				 u32 *type,
205
				 u32 *sid)
206 207 208 209
{
	int rc;
	struct netlbl_lsm_secattr secattr;

210 211 212 213 214
	if (!netlbl_enabled()) {
		*sid = SECSID_NULL;
		return 0;
	}

215
	netlbl_secattr_init(&secattr);
216
	rc = netlbl_skbuff_getattr(skb, family, &secattr);
217
	if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
H
Huw Davies 已提交
218 219
		rc = selinux_netlbl_sidlookup_cached(skb, family,
						     &secattr, sid);
220
	else
221
		*sid = SECSID_NULL;
222
	*type = secattr.type;
223 224 225 226 227
	netlbl_secattr_destroy(&secattr);

	return rc;
}

228 229 230 231 232 233 234 235
/**
 * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid
 * @skb: the packet
 * @family: protocol family
 * @sid: the SID
 *
 * Description
 * Call the NetLabel mechanism to set the label of a packet using @sid.
236
 * Returns zero on success, negative values on failure.
237 238 239 240 241 242 243
 *
 */
int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
				 u16 family,
				 u32 sid)
{
	int rc;
244 245
	struct netlbl_lsm_secattr secattr_storage;
	struct netlbl_lsm_secattr *secattr = NULL;
246 247 248 249
	struct sock *sk;

	/* if this is a locally generated packet check to see if it is already
	 * being labeled by it's parent socket, if it is just exit */
250
	sk = skb_to_full_sk(skb);
251 252
	if (sk != NULL) {
		struct sk_security_struct *sksec = sk->sk_security;
R
Richard Haines 已提交
253

254 255
		if (sksec->nlbl_state != NLBL_REQSKB)
			return 0;
256
		secattr = selinux_netlbl_sock_getattr(sk, sid);
257 258 259 260
	}
	if (secattr == NULL) {
		secattr = &secattr_storage;
		netlbl_secattr_init(secattr);
261 262
		rc = security_netlbl_sid_to_secattr(&selinux_state, sid,
						    secattr);
263 264
		if (rc != 0)
			goto skbuff_setsid_return;
265 266
	}

267
	rc = netlbl_skbuff_setattr(skb, family, secattr);
268 269

skbuff_setsid_return:
270 271
	if (secattr == &secattr_storage)
		netlbl_secattr_destroy(secattr);
272 273 274
	return rc;
}

R
Richard Haines 已提交
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
/**
 * selinux_netlbl_sctp_assoc_request - Label an incoming sctp association.
 * @ep: incoming association endpoint.
 * @skb: the packet.
 *
 * Description:
 * A new incoming connection is represented by @ep, ......
 * Returns zero on success, negative values on failure.
 *
 */
int selinux_netlbl_sctp_assoc_request(struct sctp_endpoint *ep,
				     struct sk_buff *skb)
{
	int rc;
	struct netlbl_lsm_secattr secattr;
	struct sk_security_struct *sksec = ep->base.sk->sk_security;
	struct sockaddr *addr;
	struct sockaddr_in addr4;
#if IS_ENABLED(CONFIG_IPV6)
	struct sockaddr_in6 addr6;
#endif

	if (ep->base.sk->sk_family != PF_INET &&
				ep->base.sk->sk_family != PF_INET6)
		return 0;

	netlbl_secattr_init(&secattr);
302 303
	rc = security_netlbl_sid_to_secattr(&selinux_state,
					    ep->secid, &secattr);
R
Richard Haines 已提交
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
	if (rc != 0)
		goto assoc_request_return;

	/* Move skb hdr address info to a struct sockaddr and then call
	 * netlbl_conn_setattr().
	 */
	if (ip_hdr(skb)->version == 4) {
		addr4.sin_family = AF_INET;
		addr4.sin_addr.s_addr = ip_hdr(skb)->saddr;
		addr = (struct sockaddr *)&addr4;
#if IS_ENABLED(CONFIG_IPV6)
	} else {
		addr6.sin6_family = AF_INET6;
		addr6.sin6_addr = ipv6_hdr(skb)->saddr;
		addr = (struct sockaddr *)&addr6;
#endif
	}

	rc = netlbl_conn_setattr(ep->base.sk, addr, &secattr);
	if (rc == 0)
		sksec->nlbl_state = NLBL_LABELED;

assoc_request_return:
	netlbl_secattr_destroy(&secattr);
	return rc;
}

331
/**
332 333
 * selinux_netlbl_inet_conn_request - Label an incoming stream connection
 * @req: incoming connection request socket
334 335
 *
 * Description:
336 337 338 339
 * A new incoming connection request is represented by @req, we need to label
 * the new request_sock here and the stack will ensure the on-the-wire label
 * will get preserved when a full sock is created once the connection handshake
 * is complete.  Returns zero on success, negative values on failure.
340 341
 *
 */
342
int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
343
{
344
	int rc;
345
	struct netlbl_lsm_secattr secattr;
346

347
	if (family != PF_INET && family != PF_INET6)
348
		return 0;
349

350
	netlbl_secattr_init(&secattr);
351 352
	rc = security_netlbl_sid_to_secattr(&selinux_state, req->secid,
					    &secattr);
353 354 355 356 357 358
	if (rc != 0)
		goto inet_conn_request_return;
	rc = netlbl_req_setattr(req, &secattr);
inet_conn_request_return:
	netlbl_secattr_destroy(&secattr);
	return rc;
359 360 361
}

/**
362 363
 * selinux_netlbl_inet_csk_clone - Initialize the newly created sock
 * @sk: the new sock
364 365
 *
 * Description:
366 367 368
 * A new connection has been established using @sk, we've already labeled the
 * socket via the request_sock struct in selinux_netlbl_inet_conn_request() but
 * we need to set the NetLabel state here since we now have a sock structure.
369 370
 *
 */
371
void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
372
{
373 374 375 376 377 378
	struct sk_security_struct *sksec = sk->sk_security;

	if (family == PF_INET)
		sksec->nlbl_state = NLBL_LABELED;
	else
		sksec->nlbl_state = NLBL_UNSET;
379 380
}

R
Richard Haines 已提交
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
/**
 * selinux_netlbl_sctp_sk_clone - Copy state to the newly created sock
 * @sk: current sock
 * @newsk: the new sock
 *
 * Description:
 * Called whenever a new socket is created by accept(2) or sctp_peeloff(3).
 */
void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk)
{
	struct sk_security_struct *sksec = sk->sk_security;
	struct sk_security_struct *newsksec = newsk->sk_security;

	newsksec->nlbl_state = sksec->nlbl_state;
}

397
/**
398 399 400
 * selinux_netlbl_socket_post_create - Label a socket using NetLabel
 * @sock: the socket to label
 * @family: protocol family
401 402
 *
 * Description:
403 404
 * Attempt to label a socket using the NetLabel mechanism using the given
 * SID.  Returns zero values on success, negative values on failure.
405 406
 *
 */
407
int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
408 409
{
	int rc;
410 411
	struct sk_security_struct *sksec = sk->sk_security;
	struct netlbl_lsm_secattr *secattr;
412

413
	if (family != PF_INET && family != PF_INET6)
414
		return 0;
415

416 417 418 419 420 421 422 423 424 425
	secattr = selinux_netlbl_sock_genattr(sk);
	if (secattr == NULL)
		return -ENOMEM;
	rc = netlbl_sock_setattr(sk, family, secattr);
	switch (rc) {
	case 0:
		sksec->nlbl_state = NLBL_LABELED;
		break;
	case -EDESTADDRREQ:
		sksec->nlbl_state = NLBL_REQSKB;
426
		rc = 0;
427 428
		break;
	}
429 430 431 432 433 434 435 436

	return rc;
}

/**
 * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel
 * @sksec: the sock's sk_security_struct
 * @skb: the packet
437
 * @family: protocol family
438 439 440 441 442 443 444 445 446 447
 * @ad: the audit data
 *
 * Description:
 * Fetch the NetLabel security attributes from @skb and perform an access check
 * against the receiving socket.  Returns zero on success, negative values on
 * error.
 *
 */
int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
				struct sk_buff *skb,
448
				u16 family,
449
				struct common_audit_data *ad)
450 451
{
	int rc;
452 453 454
	u32 nlbl_sid;
	u32 perm;
	struct netlbl_lsm_secattr secattr;
455

456 457 458
	if (!netlbl_enabled())
		return 0;

459
	netlbl_secattr_init(&secattr);
460
	rc = netlbl_skbuff_getattr(skb, family, &secattr);
461
	if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
H
Huw Davies 已提交
462 463
		rc = selinux_netlbl_sidlookup_cached(skb, family,
						     &secattr, &nlbl_sid);
464
	else
465 466
		nlbl_sid = SECINITSID_UNLABELED;
	netlbl_secattr_destroy(&secattr);
467 468
	if (rc != 0)
		return rc;
469

470 471
	switch (sksec->sclass) {
	case SECCLASS_UDP_SOCKET:
472
		perm = UDP_SOCKET__RECVFROM;
473 474
		break;
	case SECCLASS_TCP_SOCKET:
475
		perm = TCP_SOCKET__RECVFROM;
476 477
		break;
	default:
478
		perm = RAWIP_SOCKET__RECVFROM;
479 480
	}

S
Stephen Smalley 已提交
481 482
	rc = avc_has_perm(&selinux_state,
			  sksec->sid, nlbl_sid, sksec->sclass, perm, ad);
483 484 485
	if (rc == 0)
		return 0;

486
	if (nlbl_sid != SECINITSID_UNLABELED)
487
		netlbl_skbuff_err(skb, family, rc, 0);
488 489 490
	return rc;
}

491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
/**
 * selinux_netlbl_option - Is this a NetLabel option
 * @level: the socket level or protocol
 * @optname: the socket option name
 *
 * Description:
 * Returns true if @level and @optname refer to a NetLabel option.
 * Helper for selinux_netlbl_socket_setsockopt().
 */
static inline int selinux_netlbl_option(int level, int optname)
{
	return (level == IPPROTO_IP && optname == IP_OPTIONS) ||
		(level == IPPROTO_IPV6 && optname == IPV6_HOPOPTS);
}

506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
/**
 * selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel
 * @sock: the socket
 * @level: the socket level or protocol
 * @optname: the socket option name
 *
 * Description:
 * Check the setsockopt() call and if the user is trying to replace the IP
 * options on a socket and a NetLabel is in place for the socket deny the
 * access; otherwise allow the access.  Returns zero when the access is
 * allowed, -EACCES when denied, and other negative values on error.
 *
 */
int selinux_netlbl_socket_setsockopt(struct socket *sock,
				     int level,
				     int optname)
{
	int rc = 0;
524 525
	struct sock *sk = sock->sk;
	struct sk_security_struct *sksec = sk->sk_security;
526 527
	struct netlbl_lsm_secattr secattr;

528
	if (selinux_netlbl_option(level, optname) &&
529 530
	    (sksec->nlbl_state == NLBL_LABELED ||
	     sksec->nlbl_state == NLBL_CONNLABELED)) {
531
		netlbl_secattr_init(&secattr);
532
		lock_sock(sk);
533 534 535
		/* call the netlabel function directly as we want to see the
		 * on-the-wire label that is assigned via the socket's options
		 * and not the cached netlabel/lsm attributes */
536 537
		rc = netlbl_sock_getattr(sk, &secattr);
		release_sock(sk);
538
		if (rc == 0)
539
			rc = -EACCES;
540 541
		else if (rc == -ENOMSG)
			rc = 0;
542 543 544 545 546
		netlbl_secattr_destroy(&secattr);
	}

	return rc;
}
547 548

/**
R
Richard Haines 已提交
549 550
 * selinux_netlbl_socket_connect_helper - Help label a client-side socket on
 * connect
551 552 553 554 555 556 557 558
 * @sk: the socket to label
 * @addr: the destination address
 *
 * Description:
 * Attempt to label a connected socket with NetLabel using the given address.
 * Returns zero values on success, negative values on failure.
 *
 */
R
Richard Haines 已提交
559 560
static int selinux_netlbl_socket_connect_helper(struct sock *sk,
						struct sockaddr *addr)
561 562 563
{
	int rc;
	struct sk_security_struct *sksec = sk->sk_security;
564
	struct netlbl_lsm_secattr *secattr;
565 566 567 568 569 570 571 572

	/* connected sockets are allowed to disconnect when the address family
	 * is set to AF_UNSPEC, if that is what is happening we want to reset
	 * the socket */
	if (addr->sa_family == AF_UNSPEC) {
		netlbl_sock_delattr(sk);
		sksec->nlbl_state = NLBL_REQSKB;
		rc = 0;
R
Richard Haines 已提交
573
		return rc;
574
	}
575 576 577
	secattr = selinux_netlbl_sock_genattr(sk);
	if (secattr == NULL) {
		rc = -ENOMEM;
R
Richard Haines 已提交
578
		return rc;
579 580 581 582
	}
	rc = netlbl_conn_setattr(sk, addr, secattr);
	if (rc == 0)
		sksec->nlbl_state = NLBL_CONNLABELED;
583

R
Richard Haines 已提交
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
	return rc;
}

/**
 * selinux_netlbl_socket_connect_locked - Label a client-side socket on
 * connect
 * @sk: the socket to label
 * @addr: the destination address
 *
 * Description:
 * Attempt to label a connected socket that already has the socket locked
 * with NetLabel using the given address.
 * Returns zero values on success, negative values on failure.
 *
 */
int selinux_netlbl_socket_connect_locked(struct sock *sk,
					 struct sockaddr *addr)
{
	struct sk_security_struct *sksec = sk->sk_security;

	if (sksec->nlbl_state != NLBL_REQSKB &&
	    sksec->nlbl_state != NLBL_CONNLABELED)
		return 0;

	return selinux_netlbl_socket_connect_helper(sk, addr);
}

/**
 * selinux_netlbl_socket_connect - Label a client-side socket on connect
 * @sk: the socket to label
 * @addr: the destination address
 *
 * Description:
 * Attempt to label a connected socket with NetLabel using the given address.
 * Returns zero values on success, negative values on failure.
 *
 */
int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
{
	int rc;

	lock_sock(sk);
	rc = selinux_netlbl_socket_connect_locked(sk, addr);
627
	release_sock(sk);
R
Richard Haines 已提交
628

629 630
	return rc;
}