diff options
Diffstat (limited to 'security/selinux/netlabel.c')
-rw-r--r-- | security/selinux/netlabel.c | 148 |
1 files changed, 132 insertions, 16 deletions
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 2c297b995b16..186e727b737b 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c | |||
@@ -59,7 +59,7 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb, | |||
59 | { | 59 | { |
60 | int rc; | 60 | int rc; |
61 | 61 | ||
62 | rc = security_netlbl_secattr_to_sid(secattr, sid); | 62 | rc = security_netlbl_secattr_to_sid(&selinux_state, secattr, sid); |
63 | if (rc == 0 && | 63 | if (rc == 0 && |
64 | (secattr->flags & NETLBL_SECATTR_CACHEABLE) && | 64 | (secattr->flags & NETLBL_SECATTR_CACHEABLE) && |
65 | (secattr->flags & NETLBL_SECATTR_CACHE)) | 65 | (secattr->flags & NETLBL_SECATTR_CACHE)) |
@@ -90,7 +90,8 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk) | |||
90 | secattr = netlbl_secattr_alloc(GFP_ATOMIC); | 90 | secattr = netlbl_secattr_alloc(GFP_ATOMIC); |
91 | if (secattr == NULL) | 91 | if (secattr == NULL) |
92 | return NULL; | 92 | return NULL; |
93 | rc = security_netlbl_sid_to_secattr(sksec->sid, secattr); | 93 | rc = security_netlbl_sid_to_secattr(&selinux_state, sksec->sid, |
94 | secattr); | ||
94 | if (rc != 0) { | 95 | if (rc != 0) { |
95 | netlbl_secattr_free(secattr); | 96 | netlbl_secattr_free(secattr); |
96 | return NULL; | 97 | return NULL; |
@@ -249,6 +250,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | |||
249 | sk = skb_to_full_sk(skb); | 250 | sk = skb_to_full_sk(skb); |
250 | if (sk != NULL) { | 251 | if (sk != NULL) { |
251 | struct sk_security_struct *sksec = sk->sk_security; | 252 | struct sk_security_struct *sksec = sk->sk_security; |
253 | |||
252 | if (sksec->nlbl_state != NLBL_REQSKB) | 254 | if (sksec->nlbl_state != NLBL_REQSKB) |
253 | return 0; | 255 | return 0; |
254 | secattr = selinux_netlbl_sock_getattr(sk, sid); | 256 | secattr = selinux_netlbl_sock_getattr(sk, sid); |
@@ -256,7 +258,8 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | |||
256 | if (secattr == NULL) { | 258 | if (secattr == NULL) { |
257 | secattr = &secattr_storage; | 259 | secattr = &secattr_storage; |
258 | netlbl_secattr_init(secattr); | 260 | netlbl_secattr_init(secattr); |
259 | rc = security_netlbl_sid_to_secattr(sid, secattr); | 261 | rc = security_netlbl_sid_to_secattr(&selinux_state, sid, |
262 | secattr); | ||
260 | if (rc != 0) | 263 | if (rc != 0) |
261 | goto skbuff_setsid_return; | 264 | goto skbuff_setsid_return; |
262 | } | 265 | } |
@@ -270,6 +273,62 @@ skbuff_setsid_return: | |||
270 | } | 273 | } |
271 | 274 | ||
272 | /** | 275 | /** |
276 | * selinux_netlbl_sctp_assoc_request - Label an incoming sctp association. | ||
277 | * @ep: incoming association endpoint. | ||
278 | * @skb: the packet. | ||
279 | * | ||
280 | * Description: | ||
281 | * A new incoming connection is represented by @ep, ...... | ||
282 | * Returns zero on success, negative values on failure. | ||
283 | * | ||
284 | */ | ||
285 | int selinux_netlbl_sctp_assoc_request(struct sctp_endpoint *ep, | ||
286 | struct sk_buff *skb) | ||
287 | { | ||
288 | int rc; | ||
289 | struct netlbl_lsm_secattr secattr; | ||
290 | struct sk_security_struct *sksec = ep->base.sk->sk_security; | ||
291 | struct sockaddr *addr; | ||
292 | struct sockaddr_in addr4; | ||
293 | #if IS_ENABLED(CONFIG_IPV6) | ||
294 | struct sockaddr_in6 addr6; | ||
295 | #endif | ||
296 | |||
297 | if (ep->base.sk->sk_family != PF_INET && | ||
298 | ep->base.sk->sk_family != PF_INET6) | ||
299 | return 0; | ||
300 | |||
301 | netlbl_secattr_init(&secattr); | ||
302 | rc = security_netlbl_sid_to_secattr(&selinux_state, | ||
303 | ep->secid, &secattr); | ||
304 | if (rc != 0) | ||
305 | goto assoc_request_return; | ||
306 | |||
307 | /* Move skb hdr address info to a struct sockaddr and then call | ||
308 | * netlbl_conn_setattr(). | ||
309 | */ | ||
310 | if (ip_hdr(skb)->version == 4) { | ||
311 | addr4.sin_family = AF_INET; | ||
312 | addr4.sin_addr.s_addr = ip_hdr(skb)->saddr; | ||
313 | addr = (struct sockaddr *)&addr4; | ||
314 | #if IS_ENABLED(CONFIG_IPV6) | ||
315 | } else { | ||
316 | addr6.sin6_family = AF_INET6; | ||
317 | addr6.sin6_addr = ipv6_hdr(skb)->saddr; | ||
318 | addr = (struct sockaddr *)&addr6; | ||
319 | #endif | ||
320 | } | ||
321 | |||
322 | rc = netlbl_conn_setattr(ep->base.sk, addr, &secattr); | ||
323 | if (rc == 0) | ||
324 | sksec->nlbl_state = NLBL_LABELED; | ||
325 | |||
326 | assoc_request_return: | ||
327 | netlbl_secattr_destroy(&secattr); | ||
328 | return rc; | ||
329 | } | ||
330 | |||
331 | /** | ||
273 | * selinux_netlbl_inet_conn_request - Label an incoming stream connection | 332 | * selinux_netlbl_inet_conn_request - Label an incoming stream connection |
274 | * @req: incoming connection request socket | 333 | * @req: incoming connection request socket |
275 | * | 334 | * |
@@ -289,7 +348,8 @@ int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family) | |||
289 | return 0; | 348 | return 0; |
290 | 349 | ||
291 | netlbl_secattr_init(&secattr); | 350 | netlbl_secattr_init(&secattr); |
292 | rc = security_netlbl_sid_to_secattr(req->secid, &secattr); | 351 | rc = security_netlbl_sid_to_secattr(&selinux_state, req->secid, |
352 | &secattr); | ||
293 | if (rc != 0) | 353 | if (rc != 0) |
294 | goto inet_conn_request_return; | 354 | goto inet_conn_request_return; |
295 | rc = netlbl_req_setattr(req, &secattr); | 355 | rc = netlbl_req_setattr(req, &secattr); |
@@ -319,6 +379,22 @@ void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family) | |||
319 | } | 379 | } |
320 | 380 | ||
321 | /** | 381 | /** |
382 | * selinux_netlbl_sctp_sk_clone - Copy state to the newly created sock | ||
383 | * @sk: current sock | ||
384 | * @newsk: the new sock | ||
385 | * | ||
386 | * Description: | ||
387 | * Called whenever a new socket is created by accept(2) or sctp_peeloff(3). | ||
388 | */ | ||
389 | void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk) | ||
390 | { | ||
391 | struct sk_security_struct *sksec = sk->sk_security; | ||
392 | struct sk_security_struct *newsksec = newsk->sk_security; | ||
393 | |||
394 | newsksec->nlbl_state = sksec->nlbl_state; | ||
395 | } | ||
396 | |||
397 | /** | ||
322 | * selinux_netlbl_socket_post_create - Label a socket using NetLabel | 398 | * selinux_netlbl_socket_post_create - Label a socket using NetLabel |
323 | * @sock: the socket to label | 399 | * @sock: the socket to label |
324 | * @family: protocol family | 400 | * @family: protocol family |
@@ -402,7 +478,8 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | |||
402 | perm = RAWIP_SOCKET__RECVFROM; | 478 | perm = RAWIP_SOCKET__RECVFROM; |
403 | } | 479 | } |
404 | 480 | ||
405 | rc = avc_has_perm(sksec->sid, nlbl_sid, sksec->sclass, perm, ad); | 481 | rc = avc_has_perm(&selinux_state, |
482 | sksec->sid, nlbl_sid, sksec->sclass, perm, ad); | ||
406 | if (rc == 0) | 483 | if (rc == 0) |
407 | return 0; | 484 | return 0; |
408 | 485 | ||
@@ -469,7 +546,8 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, | |||
469 | } | 546 | } |
470 | 547 | ||
471 | /** | 548 | /** |
472 | * selinux_netlbl_socket_connect - Label a client-side socket on connect | 549 | * selinux_netlbl_socket_connect_helper - Help label a client-side socket on |
550 | * connect | ||
473 | * @sk: the socket to label | 551 | * @sk: the socket to label |
474 | * @addr: the destination address | 552 | * @addr: the destination address |
475 | * | 553 | * |
@@ -478,18 +556,13 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, | |||
478 | * Returns zero values on success, negative values on failure. | 556 | * Returns zero values on success, negative values on failure. |
479 | * | 557 | * |
480 | */ | 558 | */ |
481 | int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) | 559 | static int selinux_netlbl_socket_connect_helper(struct sock *sk, |
560 | struct sockaddr *addr) | ||
482 | { | 561 | { |
483 | int rc; | 562 | int rc; |
484 | struct sk_security_struct *sksec = sk->sk_security; | 563 | struct sk_security_struct *sksec = sk->sk_security; |
485 | struct netlbl_lsm_secattr *secattr; | 564 | struct netlbl_lsm_secattr *secattr; |
486 | 565 | ||
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 | 566 | /* 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 | 567 | * is set to AF_UNSPEC, if that is what is happening we want to reset |
495 | * the socket */ | 568 | * the socket */ |
@@ -497,18 +570,61 @@ int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) | |||
497 | netlbl_sock_delattr(sk); | 570 | netlbl_sock_delattr(sk); |
498 | sksec->nlbl_state = NLBL_REQSKB; | 571 | sksec->nlbl_state = NLBL_REQSKB; |
499 | rc = 0; | 572 | rc = 0; |
500 | goto socket_connect_return; | 573 | return rc; |
501 | } | 574 | } |
502 | secattr = selinux_netlbl_sock_genattr(sk); | 575 | secattr = selinux_netlbl_sock_genattr(sk); |
503 | if (secattr == NULL) { | 576 | if (secattr == NULL) { |
504 | rc = -ENOMEM; | 577 | rc = -ENOMEM; |
505 | goto socket_connect_return; | 578 | return rc; |
506 | } | 579 | } |
507 | rc = netlbl_conn_setattr(sk, addr, secattr); | 580 | rc = netlbl_conn_setattr(sk, addr, secattr); |
508 | if (rc == 0) | 581 | if (rc == 0) |
509 | sksec->nlbl_state = NLBL_CONNLABELED; | 582 | sksec->nlbl_state = NLBL_CONNLABELED; |
510 | 583 | ||
511 | socket_connect_return: | 584 | return rc; |
585 | } | ||
586 | |||
587 | /** | ||
588 | * selinux_netlbl_socket_connect_locked - Label a client-side socket on | ||
589 | * connect | ||
590 | * @sk: the socket to label | ||
591 | * @addr: the destination address | ||
592 | * | ||
593 | * Description: | ||
594 | * Attempt to label a connected socket that already has the socket locked | ||
595 | * with NetLabel using the given address. | ||
596 | * Returns zero values on success, negative values on failure. | ||
597 | * | ||
598 | */ | ||
599 | int selinux_netlbl_socket_connect_locked(struct sock *sk, | ||
600 | struct sockaddr *addr) | ||
601 | { | ||
602 | struct sk_security_struct *sksec = sk->sk_security; | ||
603 | |||
604 | if (sksec->nlbl_state != NLBL_REQSKB && | ||
605 | sksec->nlbl_state != NLBL_CONNLABELED) | ||
606 | return 0; | ||
607 | |||
608 | return selinux_netlbl_socket_connect_helper(sk, addr); | ||
609 | } | ||
610 | |||
611 | /** | ||
612 | * selinux_netlbl_socket_connect - Label a client-side socket on connect | ||
613 | * @sk: the socket to label | ||
614 | * @addr: the destination address | ||
615 | * | ||
616 | * Description: | ||
617 | * Attempt to label a connected socket with NetLabel using the given address. | ||
618 | * Returns zero values on success, negative values on failure. | ||
619 | * | ||
620 | */ | ||
621 | int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) | ||
622 | { | ||
623 | int rc; | ||
624 | |||
625 | lock_sock(sk); | ||
626 | rc = selinux_netlbl_socket_connect_locked(sk, addr); | ||
512 | release_sock(sk); | 627 | release_sock(sk); |
628 | |||
513 | return rc; | 629 | return rc; |
514 | } | 630 | } |