11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 25778eabdSPaul Moore /* 35778eabdSPaul Moore * SELinux NetLabel Support 45778eabdSPaul Moore * 55778eabdSPaul Moore * This file provides the necessary glue to tie NetLabel into the SELinux 65778eabdSPaul Moore * subsystem. 75778eabdSPaul Moore * 882c21bfaSPaul Moore * Author: Paul Moore <paul@paul-moore.com> 95778eabdSPaul Moore */ 105778eabdSPaul Moore 115778eabdSPaul Moore /* 12948bf85cSPaul Moore * (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008 135778eabdSPaul Moore */ 145778eabdSPaul Moore 155778eabdSPaul Moore #include <linux/spinlock.h> 165778eabdSPaul Moore #include <linux/rcupdate.h> 175a0e3ad6STejun Heo #include <linux/gfp.h> 18014ab19aSPaul Moore #include <linux/ip.h> 19014ab19aSPaul Moore #include <linux/ipv6.h> 205778eabdSPaul Moore #include <net/sock.h> 215778eabdSPaul Moore #include <net/netlabel.h> 22014ab19aSPaul Moore #include <net/ip.h> 23014ab19aSPaul Moore #include <net/ipv6.h> 245778eabdSPaul Moore 255778eabdSPaul Moore #include "objsec.h" 265778eabdSPaul Moore #include "security.h" 27d4ee4231SAdrian Bunk #include "netlabel.h" 285778eabdSPaul Moore 295778eabdSPaul Moore /** 305dbe1eb0SPaul Moore * selinux_netlbl_sidlookup_cached - Cache a SID lookup 315dbe1eb0SPaul Moore * @skb: the packet 32e9fd7292SPaul Moore * @family: the packet's address family 335dbe1eb0SPaul Moore * @secattr: the NetLabel security attributes 345dbe1eb0SPaul Moore * @sid: the SID 355dbe1eb0SPaul Moore * 365dbe1eb0SPaul Moore * Description: 375dbe1eb0SPaul Moore * Query the SELinux security server to lookup the correct SID for the given 385dbe1eb0SPaul Moore * security attributes. If the query is successful, cache the result to speed 395dbe1eb0SPaul Moore * up future lookups. Returns zero on success, negative values on failure. 405dbe1eb0SPaul Moore * 415dbe1eb0SPaul Moore */ 425dbe1eb0SPaul Moore static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb, 434fee5242SHuw Davies u16 family, 445dbe1eb0SPaul Moore struct netlbl_lsm_secattr *secattr, 455dbe1eb0SPaul Moore u32 *sid) 465dbe1eb0SPaul Moore { 475dbe1eb0SPaul Moore int rc; 485dbe1eb0SPaul Moore 49*e67b7985SStephen Smalley rc = security_netlbl_secattr_to_sid(secattr, sid); 505dbe1eb0SPaul Moore if (rc == 0 && 515dbe1eb0SPaul Moore (secattr->flags & NETLBL_SECATTR_CACHEABLE) && 525dbe1eb0SPaul Moore (secattr->flags & NETLBL_SECATTR_CACHE)) 534fee5242SHuw Davies netlbl_cache_add(skb, family, secattr); 545dbe1eb0SPaul Moore 555dbe1eb0SPaul Moore return rc; 565dbe1eb0SPaul Moore } 575dbe1eb0SPaul Moore 585dbe1eb0SPaul Moore /** 596c5b3fc0SPaul Moore * selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr 606c5b3fc0SPaul Moore * @sk: the socket 616c5b3fc0SPaul Moore * 626c5b3fc0SPaul Moore * Description: 636c5b3fc0SPaul Moore * Generate the NetLabel security attributes for a socket, making full use of 646c5b3fc0SPaul Moore * the socket's attribute cache. Returns a pointer to the security attributes 656c5b3fc0SPaul Moore * on success, NULL on failure. 666c5b3fc0SPaul Moore * 676c5b3fc0SPaul Moore */ 686c5b3fc0SPaul Moore static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk) 696c5b3fc0SPaul Moore { 706c5b3fc0SPaul Moore int rc; 716c5b3fc0SPaul Moore struct sk_security_struct *sksec = sk->sk_security; 726c5b3fc0SPaul Moore struct netlbl_lsm_secattr *secattr; 736c5b3fc0SPaul Moore 746c5b3fc0SPaul Moore if (sksec->nlbl_secattr != NULL) 756c5b3fc0SPaul Moore return sksec->nlbl_secattr; 766c5b3fc0SPaul Moore 776c5b3fc0SPaul Moore secattr = netlbl_secattr_alloc(GFP_ATOMIC); 786c5b3fc0SPaul Moore if (secattr == NULL) 796c5b3fc0SPaul Moore return NULL; 80*e67b7985SStephen Smalley rc = security_netlbl_sid_to_secattr(sksec->sid, secattr); 816c5b3fc0SPaul Moore if (rc != 0) { 826c5b3fc0SPaul Moore netlbl_secattr_free(secattr); 836c5b3fc0SPaul Moore return NULL; 846c5b3fc0SPaul Moore } 856c5b3fc0SPaul Moore sksec->nlbl_secattr = secattr; 866c5b3fc0SPaul Moore 876c5b3fc0SPaul Moore return secattr; 886c5b3fc0SPaul Moore } 896c5b3fc0SPaul Moore 906c5b3fc0SPaul Moore /** 91050d032bSPaul Moore * selinux_netlbl_sock_getattr - Get the cached NetLabel secattr 92050d032bSPaul Moore * @sk: the socket 93050d032bSPaul Moore * @sid: the SID 94050d032bSPaul Moore * 95050d032bSPaul Moore * Query the socket's cached secattr and if the SID matches the cached value 96050d032bSPaul Moore * return the cache, otherwise return NULL. 97050d032bSPaul Moore * 98050d032bSPaul Moore */ 99050d032bSPaul Moore static struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr( 100050d032bSPaul Moore const struct sock *sk, 101050d032bSPaul Moore u32 sid) 102050d032bSPaul Moore { 103050d032bSPaul Moore struct sk_security_struct *sksec = sk->sk_security; 104050d032bSPaul Moore struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr; 105050d032bSPaul Moore 106050d032bSPaul Moore if (secattr == NULL) 107050d032bSPaul Moore return NULL; 108050d032bSPaul Moore 109050d032bSPaul Moore if ((secattr->flags & NETLBL_SECATTR_SECID) && 110050d032bSPaul Moore (secattr->attr.secid == sid)) 111050d032bSPaul Moore return secattr; 112050d032bSPaul Moore 113050d032bSPaul Moore return NULL; 114050d032bSPaul Moore } 115050d032bSPaul Moore 116050d032bSPaul Moore /** 1175778eabdSPaul Moore * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache 1185778eabdSPaul Moore * 1195778eabdSPaul Moore * Description: 1205778eabdSPaul Moore * Invalidate the NetLabel security attribute mapping cache. 1215778eabdSPaul Moore * 1225778eabdSPaul Moore */ 1235778eabdSPaul Moore void selinux_netlbl_cache_invalidate(void) 1245778eabdSPaul Moore { 1255778eabdSPaul Moore netlbl_cache_invalidate(); 1265778eabdSPaul Moore } 1275778eabdSPaul Moore 1285778eabdSPaul Moore /** 129dfaebe98SPaul Moore * selinux_netlbl_err - Handle a NetLabel packet error 130dfaebe98SPaul Moore * @skb: the packet 131e9fd7292SPaul Moore * @family: the packet's address family 132dfaebe98SPaul Moore * @error: the error code 133dfaebe98SPaul Moore * @gateway: true if host is acting as a gateway, false otherwise 134dfaebe98SPaul Moore * 135dfaebe98SPaul Moore * Description: 136dfaebe98SPaul Moore * When a packet is dropped due to a call to avc_has_perm() pass the error 137dfaebe98SPaul Moore * code to the NetLabel subsystem so any protocol specific processing can be 138dfaebe98SPaul Moore * done. This is safe to call even if you are unsure if NetLabel labeling is 139dfaebe98SPaul Moore * present on the packet, NetLabel is smart enough to only act when it should. 140dfaebe98SPaul Moore * 141dfaebe98SPaul Moore */ 142a04e71f6SHuw Davies void selinux_netlbl_err(struct sk_buff *skb, u16 family, int error, int gateway) 143dfaebe98SPaul Moore { 144a04e71f6SHuw Davies netlbl_skbuff_err(skb, family, error, gateway); 145dfaebe98SPaul Moore } 146dfaebe98SPaul Moore 147dfaebe98SPaul Moore /** 1486c5b3fc0SPaul Moore * selinux_netlbl_sk_security_free - Free the NetLabel fields 149dd3e7836SEric Paris * @sksec: the sk_security_struct 1506c5b3fc0SPaul Moore * 1516c5b3fc0SPaul Moore * Description: 1526c5b3fc0SPaul Moore * Free all of the memory in the NetLabel fields of a sk_security_struct. 1536c5b3fc0SPaul Moore * 1546c5b3fc0SPaul Moore */ 155dd3e7836SEric Paris void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec) 1566c5b3fc0SPaul Moore { 157dd3e7836SEric Paris if (sksec->nlbl_secattr != NULL) 158dd3e7836SEric Paris netlbl_secattr_free(sksec->nlbl_secattr); 1596c5b3fc0SPaul Moore } 1606c5b3fc0SPaul Moore 1616c5b3fc0SPaul Moore /** 1625778eabdSPaul Moore * selinux_netlbl_sk_security_reset - Reset the NetLabel fields 163dd3e7836SEric Paris * @sksec: the sk_security_struct 1645778eabdSPaul Moore * 1655778eabdSPaul Moore * Description: 1665778eabdSPaul Moore * Called when the NetLabel state of a sk_security_struct needs to be reset. 16725985edcSLucas De Marchi * The caller is responsible for all the NetLabel sk_security_struct locking. 1685778eabdSPaul Moore * 1695778eabdSPaul Moore */ 170dd3e7836SEric Paris void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec) 1715778eabdSPaul Moore { 172dd3e7836SEric Paris sksec->nlbl_state = NLBL_UNSET; 1735778eabdSPaul Moore } 1745778eabdSPaul Moore 1755778eabdSPaul Moore /** 1765778eabdSPaul Moore * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel 1775778eabdSPaul Moore * @skb: the packet 17875e22910SPaul Moore * @family: protocol family 179220deb96SPaul Moore * @type: NetLabel labeling protocol type 1805778eabdSPaul Moore * @sid: the SID 1815778eabdSPaul Moore * 1825778eabdSPaul Moore * Description: 1835778eabdSPaul Moore * Call the NetLabel mechanism to get the security attributes of the given 1845778eabdSPaul Moore * packet and use those attributes to determine the correct context/SID to 1855778eabdSPaul Moore * assign to the packet. Returns zero on success, negative values on failure. 1865778eabdSPaul Moore * 1875778eabdSPaul Moore */ 18875e22910SPaul Moore int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, 18975e22910SPaul Moore u16 family, 190220deb96SPaul Moore u32 *type, 19175e22910SPaul Moore u32 *sid) 1925778eabdSPaul Moore { 1935778eabdSPaul Moore int rc; 1945778eabdSPaul Moore struct netlbl_lsm_secattr secattr; 1955778eabdSPaul Moore 19623bcdc1aSPaul Moore if (!netlbl_enabled()) { 19723bcdc1aSPaul Moore *sid = SECSID_NULL; 19823bcdc1aSPaul Moore return 0; 19923bcdc1aSPaul Moore } 20023bcdc1aSPaul Moore 2015778eabdSPaul Moore netlbl_secattr_init(&secattr); 20275e22910SPaul Moore rc = netlbl_skbuff_getattr(skb, family, &secattr); 2035dbe1eb0SPaul Moore if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) 2044fee5242SHuw Davies rc = selinux_netlbl_sidlookup_cached(skb, family, 2054fee5242SHuw Davies &secattr, sid); 2065dbe1eb0SPaul Moore else 2075778eabdSPaul Moore *sid = SECSID_NULL; 208220deb96SPaul Moore *type = secattr.type; 2095778eabdSPaul Moore netlbl_secattr_destroy(&secattr); 2105778eabdSPaul Moore 2115778eabdSPaul Moore return rc; 2125778eabdSPaul Moore } 2135778eabdSPaul Moore 2145778eabdSPaul Moore /** 215948bf85cSPaul Moore * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid 216948bf85cSPaul Moore * @skb: the packet 217948bf85cSPaul Moore * @family: protocol family 218948bf85cSPaul Moore * @sid: the SID 219948bf85cSPaul Moore * 220948bf85cSPaul Moore * Description 221948bf85cSPaul Moore * Call the NetLabel mechanism to set the label of a packet using @sid. 222af901ca1SAndré Goddard Rosa * Returns zero on success, negative values on failure. 223948bf85cSPaul Moore * 224948bf85cSPaul Moore */ 225948bf85cSPaul Moore int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, 226948bf85cSPaul Moore u16 family, 227948bf85cSPaul Moore u32 sid) 228948bf85cSPaul Moore { 229948bf85cSPaul Moore int rc; 2306c5b3fc0SPaul Moore struct netlbl_lsm_secattr secattr_storage; 2316c5b3fc0SPaul Moore struct netlbl_lsm_secattr *secattr = NULL; 232948bf85cSPaul Moore struct sock *sk; 233948bf85cSPaul Moore 234948bf85cSPaul Moore /* if this is a locally generated packet check to see if it is already 235948bf85cSPaul Moore * being labeled by it's parent socket, if it is just exit */ 23654abc686SEric Dumazet sk = skb_to_full_sk(skb); 237948bf85cSPaul Moore if (sk != NULL) { 238948bf85cSPaul Moore struct sk_security_struct *sksec = sk->sk_security; 239d452930fSRichard Haines 240948bf85cSPaul Moore if (sksec->nlbl_state != NLBL_REQSKB) 241948bf85cSPaul Moore return 0; 242050d032bSPaul Moore secattr = selinux_netlbl_sock_getattr(sk, sid); 243948bf85cSPaul Moore } 2446c5b3fc0SPaul Moore if (secattr == NULL) { 2456c5b3fc0SPaul Moore secattr = &secattr_storage; 2466c5b3fc0SPaul Moore netlbl_secattr_init(secattr); 247*e67b7985SStephen Smalley rc = security_netlbl_sid_to_secattr(sid, secattr); 248948bf85cSPaul Moore if (rc != 0) 249948bf85cSPaul Moore goto skbuff_setsid_return; 2506c5b3fc0SPaul Moore } 2516c5b3fc0SPaul Moore 2526c5b3fc0SPaul Moore rc = netlbl_skbuff_setattr(skb, family, secattr); 253948bf85cSPaul Moore 254948bf85cSPaul Moore skbuff_setsid_return: 2556c5b3fc0SPaul Moore if (secattr == &secattr_storage) 2566c5b3fc0SPaul Moore netlbl_secattr_destroy(secattr); 257948bf85cSPaul Moore return rc; 258948bf85cSPaul Moore } 259948bf85cSPaul Moore 260948bf85cSPaul Moore /** 261d452930fSRichard Haines * selinux_netlbl_sctp_assoc_request - Label an incoming sctp association. 262c081d53fSXin Long * @asoc: incoming association. 263d452930fSRichard Haines * @skb: the packet. 264d452930fSRichard Haines * 265d452930fSRichard Haines * Description: 266c081d53fSXin Long * A new incoming connection is represented by @asoc, ...... 267d452930fSRichard Haines * Returns zero on success, negative values on failure. 268d452930fSRichard Haines * 269d452930fSRichard Haines */ 270c081d53fSXin Long int selinux_netlbl_sctp_assoc_request(struct sctp_association *asoc, 271d452930fSRichard Haines struct sk_buff *skb) 272d452930fSRichard Haines { 273d452930fSRichard Haines int rc; 274d452930fSRichard Haines struct netlbl_lsm_secattr secattr; 275c081d53fSXin Long struct sk_security_struct *sksec = asoc->base.sk->sk_security; 276d452930fSRichard Haines struct sockaddr_in addr4; 277d452930fSRichard Haines struct sockaddr_in6 addr6; 278d452930fSRichard Haines 279c081d53fSXin Long if (asoc->base.sk->sk_family != PF_INET && 280c081d53fSXin Long asoc->base.sk->sk_family != PF_INET6) 281d452930fSRichard Haines return 0; 282d452930fSRichard Haines 283d452930fSRichard Haines netlbl_secattr_init(&secattr); 284*e67b7985SStephen Smalley rc = security_netlbl_sid_to_secattr(asoc->secid, &secattr); 285d452930fSRichard Haines if (rc != 0) 286d452930fSRichard Haines goto assoc_request_return; 287d452930fSRichard Haines 288d452930fSRichard Haines /* Move skb hdr address info to a struct sockaddr and then call 289d452930fSRichard Haines * netlbl_conn_setattr(). 290d452930fSRichard Haines */ 291d452930fSRichard Haines if (ip_hdr(skb)->version == 4) { 292d452930fSRichard Haines addr4.sin_family = AF_INET; 293d452930fSRichard Haines addr4.sin_addr.s_addr = ip_hdr(skb)->saddr; 294c081d53fSXin Long rc = netlbl_conn_setattr(asoc->base.sk, (void *)&addr4, &secattr); 29598bbbb76SArnd Bergmann } else if (IS_ENABLED(CONFIG_IPV6) && ip_hdr(skb)->version == 6) { 296d452930fSRichard Haines addr6.sin6_family = AF_INET6; 297d452930fSRichard Haines addr6.sin6_addr = ipv6_hdr(skb)->saddr; 298c081d53fSXin Long rc = netlbl_conn_setattr(asoc->base.sk, (void *)&addr6, &secattr); 29998bbbb76SArnd Bergmann } else { 30098bbbb76SArnd Bergmann rc = -EAFNOSUPPORT; 301d452930fSRichard Haines } 302d452930fSRichard Haines 303d452930fSRichard Haines if (rc == 0) 304d452930fSRichard Haines sksec->nlbl_state = NLBL_LABELED; 305d452930fSRichard Haines 306d452930fSRichard Haines assoc_request_return: 307d452930fSRichard Haines netlbl_secattr_destroy(&secattr); 308d452930fSRichard Haines return rc; 309d452930fSRichard Haines } 310d452930fSRichard Haines 311d452930fSRichard Haines /** 312389fb800SPaul Moore * selinux_netlbl_inet_conn_request - Label an incoming stream connection 313389fb800SPaul Moore * @req: incoming connection request socket 314e9fd7292SPaul Moore * @family: the request socket's address family 3155778eabdSPaul Moore * 3165778eabdSPaul Moore * Description: 317389fb800SPaul Moore * A new incoming connection request is represented by @req, we need to label 318389fb800SPaul Moore * the new request_sock here and the stack will ensure the on-the-wire label 319389fb800SPaul Moore * will get preserved when a full sock is created once the connection handshake 320389fb800SPaul Moore * is complete. Returns zero on success, negative values on failure. 3215778eabdSPaul Moore * 3225778eabdSPaul Moore */ 323389fb800SPaul Moore int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family) 3245778eabdSPaul Moore { 325014ab19aSPaul Moore int rc; 326389fb800SPaul Moore struct netlbl_lsm_secattr secattr; 327389fb800SPaul Moore 328e1adea92SHuw Davies if (family != PF_INET && family != PF_INET6) 329389fb800SPaul Moore return 0; 330389fb800SPaul Moore 331389fb800SPaul Moore netlbl_secattr_init(&secattr); 332*e67b7985SStephen Smalley rc = security_netlbl_sid_to_secattr(req->secid, &secattr); 333389fb800SPaul Moore if (rc != 0) 334389fb800SPaul Moore goto inet_conn_request_return; 335389fb800SPaul Moore rc = netlbl_req_setattr(req, &secattr); 336389fb800SPaul Moore inet_conn_request_return: 337389fb800SPaul Moore netlbl_secattr_destroy(&secattr); 338389fb800SPaul Moore return rc; 339389fb800SPaul Moore } 340389fb800SPaul Moore 341389fb800SPaul Moore /** 342389fb800SPaul Moore * selinux_netlbl_inet_csk_clone - Initialize the newly created sock 343389fb800SPaul Moore * @sk: the new sock 344e9fd7292SPaul Moore * @family: the sock's address family 345389fb800SPaul Moore * 346389fb800SPaul Moore * Description: 347389fb800SPaul Moore * A new connection has been established using @sk, we've already labeled the 348389fb800SPaul Moore * socket via the request_sock struct in selinux_netlbl_inet_conn_request() but 349389fb800SPaul Moore * we need to set the NetLabel state here since we now have a sock structure. 350389fb800SPaul Moore * 351389fb800SPaul Moore */ 352389fb800SPaul Moore void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family) 353389fb800SPaul Moore { 354014ab19aSPaul Moore struct sk_security_struct *sksec = sk->sk_security; 355014ab19aSPaul Moore 356389fb800SPaul Moore if (family == PF_INET) 357014ab19aSPaul Moore sksec->nlbl_state = NLBL_LABELED; 358389fb800SPaul Moore else 359014ab19aSPaul Moore sksec->nlbl_state = NLBL_UNSET; 3605778eabdSPaul Moore } 3615778eabdSPaul Moore 3625778eabdSPaul Moore /** 363d452930fSRichard Haines * selinux_netlbl_sctp_sk_clone - Copy state to the newly created sock 364d452930fSRichard Haines * @sk: current sock 365d452930fSRichard Haines * @newsk: the new sock 366d452930fSRichard Haines * 367d452930fSRichard Haines * Description: 368d452930fSRichard Haines * Called whenever a new socket is created by accept(2) or sctp_peeloff(3). 369d452930fSRichard Haines */ 370d452930fSRichard Haines void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk) 371d452930fSRichard Haines { 372d452930fSRichard Haines struct sk_security_struct *sksec = sk->sk_security; 373d452930fSRichard Haines struct sk_security_struct *newsksec = newsk->sk_security; 374d452930fSRichard Haines 375d452930fSRichard Haines newsksec->nlbl_state = sksec->nlbl_state; 376d452930fSRichard Haines } 377d452930fSRichard Haines 378d452930fSRichard Haines /** 3795778eabdSPaul Moore * selinux_netlbl_socket_post_create - Label a socket using NetLabel 380e9fd7292SPaul Moore * @sk: the sock to label 381389fb800SPaul Moore * @family: protocol family 3825778eabdSPaul Moore * 3835778eabdSPaul Moore * Description: 3845778eabdSPaul Moore * Attempt to label a socket using the NetLabel mechanism using the given 3855778eabdSPaul Moore * SID. Returns zero values on success, negative values on failure. 3865778eabdSPaul Moore * 3875778eabdSPaul Moore */ 388389fb800SPaul Moore int selinux_netlbl_socket_post_create(struct sock *sk, u16 family) 3895778eabdSPaul Moore { 3905778eabdSPaul Moore int rc; 391389fb800SPaul Moore struct sk_security_struct *sksec = sk->sk_security; 392389fb800SPaul Moore struct netlbl_lsm_secattr *secattr; 3935778eabdSPaul Moore 394ceba1832SHuw Davies if (family != PF_INET && family != PF_INET6) 3955778eabdSPaul Moore return 0; 396f74af6e8SPaul Moore 397389fb800SPaul Moore secattr = selinux_netlbl_sock_genattr(sk); 398389fb800SPaul Moore if (secattr == NULL) 399389fb800SPaul Moore return -ENOMEM; 400389fb800SPaul Moore rc = netlbl_sock_setattr(sk, family, secattr); 401389fb800SPaul Moore switch (rc) { 402389fb800SPaul Moore case 0: 403389fb800SPaul Moore sksec->nlbl_state = NLBL_LABELED; 404389fb800SPaul Moore break; 405389fb800SPaul Moore case -EDESTADDRREQ: 406389fb800SPaul Moore sksec->nlbl_state = NLBL_REQSKB; 407f74af6e8SPaul Moore rc = 0; 408389fb800SPaul Moore break; 409389fb800SPaul Moore } 4105778eabdSPaul Moore 4115778eabdSPaul Moore return rc; 4125778eabdSPaul Moore } 4135778eabdSPaul Moore 4145778eabdSPaul Moore /** 4155778eabdSPaul Moore * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel 4165778eabdSPaul Moore * @sksec: the sock's sk_security_struct 4175778eabdSPaul Moore * @skb: the packet 41875e22910SPaul Moore * @family: protocol family 4195778eabdSPaul Moore * @ad: the audit data 4205778eabdSPaul Moore * 4215778eabdSPaul Moore * Description: 4225778eabdSPaul Moore * Fetch the NetLabel security attributes from @skb and perform an access check 4235778eabdSPaul Moore * against the receiving socket. Returns zero on success, negative values on 4245778eabdSPaul Moore * error. 4255778eabdSPaul Moore * 4265778eabdSPaul Moore */ 4275778eabdSPaul Moore int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, 4285778eabdSPaul Moore struct sk_buff *skb, 42975e22910SPaul Moore u16 family, 4302bf49690SThomas Liu struct common_audit_data *ad) 4315778eabdSPaul Moore { 4325778eabdSPaul Moore int rc; 433f36158c4SPaul Moore u32 nlbl_sid; 434f36158c4SPaul Moore u32 perm; 435f36158c4SPaul Moore struct netlbl_lsm_secattr secattr; 4365778eabdSPaul Moore 43723bcdc1aSPaul Moore if (!netlbl_enabled()) 43823bcdc1aSPaul Moore return 0; 43923bcdc1aSPaul Moore 440f36158c4SPaul Moore netlbl_secattr_init(&secattr); 44175e22910SPaul Moore rc = netlbl_skbuff_getattr(skb, family, &secattr); 4425dbe1eb0SPaul Moore if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) 4434fee5242SHuw Davies rc = selinux_netlbl_sidlookup_cached(skb, family, 4444fee5242SHuw Davies &secattr, &nlbl_sid); 4455dbe1eb0SPaul Moore else 446f36158c4SPaul Moore nlbl_sid = SECINITSID_UNLABELED; 447f36158c4SPaul Moore netlbl_secattr_destroy(&secattr); 4485778eabdSPaul Moore if (rc != 0) 4495778eabdSPaul Moore return rc; 4508d9107e8SLinus Torvalds 4515778eabdSPaul Moore switch (sksec->sclass) { 4525778eabdSPaul Moore case SECCLASS_UDP_SOCKET: 453f36158c4SPaul Moore perm = UDP_SOCKET__RECVFROM; 4545778eabdSPaul Moore break; 4555778eabdSPaul Moore case SECCLASS_TCP_SOCKET: 456f36158c4SPaul Moore perm = TCP_SOCKET__RECVFROM; 4575778eabdSPaul Moore break; 4585778eabdSPaul Moore default: 459f36158c4SPaul Moore perm = RAWIP_SOCKET__RECVFROM; 4605778eabdSPaul Moore } 4615778eabdSPaul Moore 462*e67b7985SStephen Smalley rc = avc_has_perm(sksec->sid, nlbl_sid, sksec->sclass, perm, ad); 4635778eabdSPaul Moore if (rc == 0) 4645778eabdSPaul Moore return 0; 4655778eabdSPaul Moore 466f36158c4SPaul Moore if (nlbl_sid != SECINITSID_UNLABELED) 467a04e71f6SHuw Davies netlbl_skbuff_err(skb, family, rc, 0); 4685778eabdSPaul Moore return rc; 4695778eabdSPaul Moore } 4705778eabdSPaul Moore 4715778eabdSPaul Moore /** 4721f440c99SHuw Davies * selinux_netlbl_option - Is this a NetLabel option 4731f440c99SHuw Davies * @level: the socket level or protocol 4741f440c99SHuw Davies * @optname: the socket option name 4751f440c99SHuw Davies * 4761f440c99SHuw Davies * Description: 4771f440c99SHuw Davies * Returns true if @level and @optname refer to a NetLabel option. 4781f440c99SHuw Davies * Helper for selinux_netlbl_socket_setsockopt(). 4791f440c99SHuw Davies */ 4801f440c99SHuw Davies static inline int selinux_netlbl_option(int level, int optname) 4811f440c99SHuw Davies { 4821f440c99SHuw Davies return (level == IPPROTO_IP && optname == IP_OPTIONS) || 4831f440c99SHuw Davies (level == IPPROTO_IPV6 && optname == IPV6_HOPOPTS); 4841f440c99SHuw Davies } 4851f440c99SHuw Davies 4861f440c99SHuw Davies /** 4875778eabdSPaul Moore * selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel 4885778eabdSPaul Moore * @sock: the socket 4895778eabdSPaul Moore * @level: the socket level or protocol 4905778eabdSPaul Moore * @optname: the socket option name 4915778eabdSPaul Moore * 4925778eabdSPaul Moore * Description: 4935778eabdSPaul Moore * Check the setsockopt() call and if the user is trying to replace the IP 4945778eabdSPaul Moore * options on a socket and a NetLabel is in place for the socket deny the 4955778eabdSPaul Moore * access; otherwise allow the access. Returns zero when the access is 4965778eabdSPaul Moore * allowed, -EACCES when denied, and other negative values on error. 4975778eabdSPaul Moore * 4985778eabdSPaul Moore */ 4995778eabdSPaul Moore int selinux_netlbl_socket_setsockopt(struct socket *sock, 5005778eabdSPaul Moore int level, 5015778eabdSPaul Moore int optname) 5025778eabdSPaul Moore { 5035778eabdSPaul Moore int rc = 0; 504ba6ff9f2SPaul Moore struct sock *sk = sock->sk; 505ba6ff9f2SPaul Moore struct sk_security_struct *sksec = sk->sk_security; 5065778eabdSPaul Moore struct netlbl_lsm_secattr secattr; 5075778eabdSPaul Moore 5081f440c99SHuw Davies if (selinux_netlbl_option(level, optname) && 509014ab19aSPaul Moore (sksec->nlbl_state == NLBL_LABELED || 510014ab19aSPaul Moore sksec->nlbl_state == NLBL_CONNLABELED)) { 5115778eabdSPaul Moore netlbl_secattr_init(&secattr); 512ba6ff9f2SPaul Moore lock_sock(sk); 513050d032bSPaul Moore /* call the netlabel function directly as we want to see the 514050d032bSPaul Moore * on-the-wire label that is assigned via the socket's options 515050d032bSPaul Moore * and not the cached netlabel/lsm attributes */ 516ba6ff9f2SPaul Moore rc = netlbl_sock_getattr(sk, &secattr); 517ba6ff9f2SPaul Moore release_sock(sk); 51809c50b4aSPaul Moore if (rc == 0) 5195778eabdSPaul Moore rc = -EACCES; 52009c50b4aSPaul Moore else if (rc == -ENOMSG) 52109c50b4aSPaul Moore rc = 0; 5225778eabdSPaul Moore netlbl_secattr_destroy(&secattr); 5235778eabdSPaul Moore } 5245778eabdSPaul Moore 5255778eabdSPaul Moore return rc; 5265778eabdSPaul Moore } 527014ab19aSPaul Moore 528014ab19aSPaul Moore /** 529d452930fSRichard Haines * selinux_netlbl_socket_connect_helper - Help label a client-side socket on 530d452930fSRichard Haines * connect 531d452930fSRichard Haines * @sk: the socket to label 532d452930fSRichard Haines * @addr: the destination address 533d452930fSRichard Haines * 534d452930fSRichard Haines * Description: 535d452930fSRichard Haines * Attempt to label a connected socket with NetLabel using the given address. 536d452930fSRichard Haines * Returns zero values on success, negative values on failure. 537d452930fSRichard Haines * 538d452930fSRichard Haines */ 539d452930fSRichard Haines static int selinux_netlbl_socket_connect_helper(struct sock *sk, 540d452930fSRichard Haines struct sockaddr *addr) 541d452930fSRichard Haines { 542d452930fSRichard Haines int rc; 543d452930fSRichard Haines struct sk_security_struct *sksec = sk->sk_security; 544d452930fSRichard Haines struct netlbl_lsm_secattr *secattr; 545d452930fSRichard Haines 546d452930fSRichard Haines /* connected sockets are allowed to disconnect when the address family 547d452930fSRichard Haines * is set to AF_UNSPEC, if that is what is happening we want to reset 548d452930fSRichard Haines * the socket */ 549d452930fSRichard Haines if (addr->sa_family == AF_UNSPEC) { 550d452930fSRichard Haines netlbl_sock_delattr(sk); 551d452930fSRichard Haines sksec->nlbl_state = NLBL_REQSKB; 552d452930fSRichard Haines rc = 0; 553d452930fSRichard Haines return rc; 554d452930fSRichard Haines } 555d452930fSRichard Haines secattr = selinux_netlbl_sock_genattr(sk); 556d452930fSRichard Haines if (secattr == NULL) { 557d452930fSRichard Haines rc = -ENOMEM; 558d452930fSRichard Haines return rc; 559d452930fSRichard Haines } 560d452930fSRichard Haines rc = netlbl_conn_setattr(sk, addr, secattr); 561d452930fSRichard Haines if (rc == 0) 562d452930fSRichard Haines sksec->nlbl_state = NLBL_CONNLABELED; 563d452930fSRichard Haines 564d452930fSRichard Haines return rc; 565d452930fSRichard Haines } 566d452930fSRichard Haines 567d452930fSRichard Haines /** 568d452930fSRichard Haines * selinux_netlbl_socket_connect_locked - Label a client-side socket on 569d452930fSRichard Haines * connect 570d452930fSRichard Haines * @sk: the socket to label 571d452930fSRichard Haines * @addr: the destination address 572d452930fSRichard Haines * 573d452930fSRichard Haines * Description: 574d452930fSRichard Haines * Attempt to label a connected socket that already has the socket locked 575d452930fSRichard Haines * with NetLabel using the given address. 576d452930fSRichard Haines * Returns zero values on success, negative values on failure. 577d452930fSRichard Haines * 578d452930fSRichard Haines */ 579d452930fSRichard Haines int selinux_netlbl_socket_connect_locked(struct sock *sk, 580d452930fSRichard Haines struct sockaddr *addr) 581d452930fSRichard Haines { 582d452930fSRichard Haines struct sk_security_struct *sksec = sk->sk_security; 583d452930fSRichard Haines 584d452930fSRichard Haines if (sksec->nlbl_state != NLBL_REQSKB && 585d452930fSRichard Haines sksec->nlbl_state != NLBL_CONNLABELED) 586d452930fSRichard Haines return 0; 587d452930fSRichard Haines 588d452930fSRichard Haines return selinux_netlbl_socket_connect_helper(sk, addr); 589d452930fSRichard Haines } 590d452930fSRichard Haines 591d452930fSRichard Haines /** 592014ab19aSPaul Moore * selinux_netlbl_socket_connect - Label a client-side socket on connect 593014ab19aSPaul Moore * @sk: the socket to label 594014ab19aSPaul Moore * @addr: the destination address 595014ab19aSPaul Moore * 596014ab19aSPaul Moore * Description: 597014ab19aSPaul Moore * Attempt to label a connected socket with NetLabel using the given address. 598014ab19aSPaul Moore * Returns zero values on success, negative values on failure. 599014ab19aSPaul Moore * 600014ab19aSPaul Moore */ 601014ab19aSPaul Moore int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) 602014ab19aSPaul Moore { 603014ab19aSPaul Moore int rc; 604014ab19aSPaul Moore 60542d64e1aSPaul Moore lock_sock(sk); 606d452930fSRichard Haines rc = selinux_netlbl_socket_connect_locked(sk, addr); 60742d64e1aSPaul Moore release_sock(sk); 608d452930fSRichard Haines 609014ab19aSPaul Moore return rc; 610014ab19aSPaul Moore } 611