162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * SELinux NetLabel Support 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This file provides the necessary glue to tie NetLabel into the SELinux 662306a36Sopenharmony_ci * subsystem. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Author: Paul Moore <paul@paul-moore.com> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci/* 1262306a36Sopenharmony_ci * (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/spinlock.h> 1662306a36Sopenharmony_ci#include <linux/rcupdate.h> 1762306a36Sopenharmony_ci#include <linux/gfp.h> 1862306a36Sopenharmony_ci#include <linux/ip.h> 1962306a36Sopenharmony_ci#include <linux/ipv6.h> 2062306a36Sopenharmony_ci#include <net/sock.h> 2162306a36Sopenharmony_ci#include <net/netlabel.h> 2262306a36Sopenharmony_ci#include <net/ip.h> 2362306a36Sopenharmony_ci#include <net/ipv6.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include "objsec.h" 2662306a36Sopenharmony_ci#include "security.h" 2762306a36Sopenharmony_ci#include "netlabel.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/** 3062306a36Sopenharmony_ci * selinux_netlbl_sidlookup_cached - Cache a SID lookup 3162306a36Sopenharmony_ci * @skb: the packet 3262306a36Sopenharmony_ci * @family: the packet's address family 3362306a36Sopenharmony_ci * @secattr: the NetLabel security attributes 3462306a36Sopenharmony_ci * @sid: the SID 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * Description: 3762306a36Sopenharmony_ci * Query the SELinux security server to lookup the correct SID for the given 3862306a36Sopenharmony_ci * security attributes. If the query is successful, cache the result to speed 3962306a36Sopenharmony_ci * up future lookups. Returns zero on success, negative values on failure. 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_cistatic int selinux_netlbl_sidlookup_cached(struct sk_buff *skb, 4362306a36Sopenharmony_ci u16 family, 4462306a36Sopenharmony_ci struct netlbl_lsm_secattr *secattr, 4562306a36Sopenharmony_ci u32 *sid) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci int rc; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci rc = security_netlbl_secattr_to_sid(secattr, sid); 5062306a36Sopenharmony_ci if (rc == 0 && 5162306a36Sopenharmony_ci (secattr->flags & NETLBL_SECATTR_CACHEABLE) && 5262306a36Sopenharmony_ci (secattr->flags & NETLBL_SECATTR_CACHE)) 5362306a36Sopenharmony_ci netlbl_cache_add(skb, family, secattr); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci return rc; 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/** 5962306a36Sopenharmony_ci * selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr 6062306a36Sopenharmony_ci * @sk: the socket 6162306a36Sopenharmony_ci * 6262306a36Sopenharmony_ci * Description: 6362306a36Sopenharmony_ci * Generate the NetLabel security attributes for a socket, making full use of 6462306a36Sopenharmony_ci * the socket's attribute cache. Returns a pointer to the security attributes 6562306a36Sopenharmony_ci * on success, NULL on failure. 6662306a36Sopenharmony_ci * 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_cistatic struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci int rc; 7162306a36Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 7262306a36Sopenharmony_ci struct netlbl_lsm_secattr *secattr; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (sksec->nlbl_secattr != NULL) 7562306a36Sopenharmony_ci return sksec->nlbl_secattr; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci secattr = netlbl_secattr_alloc(GFP_ATOMIC); 7862306a36Sopenharmony_ci if (secattr == NULL) 7962306a36Sopenharmony_ci return NULL; 8062306a36Sopenharmony_ci rc = security_netlbl_sid_to_secattr(sksec->sid, secattr); 8162306a36Sopenharmony_ci if (rc != 0) { 8262306a36Sopenharmony_ci netlbl_secattr_free(secattr); 8362306a36Sopenharmony_ci return NULL; 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci sksec->nlbl_secattr = secattr; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci return secattr; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/** 9162306a36Sopenharmony_ci * selinux_netlbl_sock_getattr - Get the cached NetLabel secattr 9262306a36Sopenharmony_ci * @sk: the socket 9362306a36Sopenharmony_ci * @sid: the SID 9462306a36Sopenharmony_ci * 9562306a36Sopenharmony_ci * Query the socket's cached secattr and if the SID matches the cached value 9662306a36Sopenharmony_ci * return the cache, otherwise return NULL. 9762306a36Sopenharmony_ci * 9862306a36Sopenharmony_ci */ 9962306a36Sopenharmony_cistatic struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr( 10062306a36Sopenharmony_ci const struct sock *sk, 10162306a36Sopenharmony_ci u32 sid) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 10462306a36Sopenharmony_ci struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (secattr == NULL) 10762306a36Sopenharmony_ci return NULL; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if ((secattr->flags & NETLBL_SECATTR_SECID) && 11062306a36Sopenharmony_ci (secattr->attr.secid == sid)) 11162306a36Sopenharmony_ci return secattr; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return NULL; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci/** 11762306a36Sopenharmony_ci * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache 11862306a36Sopenharmony_ci * 11962306a36Sopenharmony_ci * Description: 12062306a36Sopenharmony_ci * Invalidate the NetLabel security attribute mapping cache. 12162306a36Sopenharmony_ci * 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_civoid selinux_netlbl_cache_invalidate(void) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci netlbl_cache_invalidate(); 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci/** 12962306a36Sopenharmony_ci * selinux_netlbl_err - Handle a NetLabel packet error 13062306a36Sopenharmony_ci * @skb: the packet 13162306a36Sopenharmony_ci * @family: the packet's address family 13262306a36Sopenharmony_ci * @error: the error code 13362306a36Sopenharmony_ci * @gateway: true if host is acting as a gateway, false otherwise 13462306a36Sopenharmony_ci * 13562306a36Sopenharmony_ci * Description: 13662306a36Sopenharmony_ci * When a packet is dropped due to a call to avc_has_perm() pass the error 13762306a36Sopenharmony_ci * code to the NetLabel subsystem so any protocol specific processing can be 13862306a36Sopenharmony_ci * done. This is safe to call even if you are unsure if NetLabel labeling is 13962306a36Sopenharmony_ci * present on the packet, NetLabel is smart enough to only act when it should. 14062306a36Sopenharmony_ci * 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_civoid selinux_netlbl_err(struct sk_buff *skb, u16 family, int error, int gateway) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci netlbl_skbuff_err(skb, family, error, gateway); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci/** 14862306a36Sopenharmony_ci * selinux_netlbl_sk_security_free - Free the NetLabel fields 14962306a36Sopenharmony_ci * @sksec: the sk_security_struct 15062306a36Sopenharmony_ci * 15162306a36Sopenharmony_ci * Description: 15262306a36Sopenharmony_ci * Free all of the memory in the NetLabel fields of a sk_security_struct. 15362306a36Sopenharmony_ci * 15462306a36Sopenharmony_ci */ 15562306a36Sopenharmony_civoid selinux_netlbl_sk_security_free(struct sk_security_struct *sksec) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci if (!sksec->nlbl_secattr) 15862306a36Sopenharmony_ci return; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci netlbl_secattr_free(sksec->nlbl_secattr); 16162306a36Sopenharmony_ci sksec->nlbl_secattr = NULL; 16262306a36Sopenharmony_ci sksec->nlbl_state = NLBL_UNSET; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/** 16662306a36Sopenharmony_ci * selinux_netlbl_sk_security_reset - Reset the NetLabel fields 16762306a36Sopenharmony_ci * @sksec: the sk_security_struct 16862306a36Sopenharmony_ci * 16962306a36Sopenharmony_ci * Description: 17062306a36Sopenharmony_ci * Called when the NetLabel state of a sk_security_struct needs to be reset. 17162306a36Sopenharmony_ci * The caller is responsible for all the NetLabel sk_security_struct locking. 17262306a36Sopenharmony_ci * 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_civoid selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci sksec->nlbl_state = NLBL_UNSET; 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/** 18062306a36Sopenharmony_ci * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel 18162306a36Sopenharmony_ci * @skb: the packet 18262306a36Sopenharmony_ci * @family: protocol family 18362306a36Sopenharmony_ci * @type: NetLabel labeling protocol type 18462306a36Sopenharmony_ci * @sid: the SID 18562306a36Sopenharmony_ci * 18662306a36Sopenharmony_ci * Description: 18762306a36Sopenharmony_ci * Call the NetLabel mechanism to get the security attributes of the given 18862306a36Sopenharmony_ci * packet and use those attributes to determine the correct context/SID to 18962306a36Sopenharmony_ci * assign to the packet. Returns zero on success, negative values on failure. 19062306a36Sopenharmony_ci * 19162306a36Sopenharmony_ci */ 19262306a36Sopenharmony_ciint selinux_netlbl_skbuff_getsid(struct sk_buff *skb, 19362306a36Sopenharmony_ci u16 family, 19462306a36Sopenharmony_ci u32 *type, 19562306a36Sopenharmony_ci u32 *sid) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci int rc; 19862306a36Sopenharmony_ci struct netlbl_lsm_secattr secattr; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (!netlbl_enabled()) { 20162306a36Sopenharmony_ci *type = NETLBL_NLTYPE_NONE; 20262306a36Sopenharmony_ci *sid = SECSID_NULL; 20362306a36Sopenharmony_ci return 0; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci netlbl_secattr_init(&secattr); 20762306a36Sopenharmony_ci rc = netlbl_skbuff_getattr(skb, family, &secattr); 20862306a36Sopenharmony_ci if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) 20962306a36Sopenharmony_ci rc = selinux_netlbl_sidlookup_cached(skb, family, 21062306a36Sopenharmony_ci &secattr, sid); 21162306a36Sopenharmony_ci else 21262306a36Sopenharmony_ci *sid = SECSID_NULL; 21362306a36Sopenharmony_ci *type = secattr.type; 21462306a36Sopenharmony_ci netlbl_secattr_destroy(&secattr); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci return rc; 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci/** 22062306a36Sopenharmony_ci * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid 22162306a36Sopenharmony_ci * @skb: the packet 22262306a36Sopenharmony_ci * @family: protocol family 22362306a36Sopenharmony_ci * @sid: the SID 22462306a36Sopenharmony_ci * 22562306a36Sopenharmony_ci * Description 22662306a36Sopenharmony_ci * Call the NetLabel mechanism to set the label of a packet using @sid. 22762306a36Sopenharmony_ci * Returns zero on success, negative values on failure. 22862306a36Sopenharmony_ci * 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_ciint selinux_netlbl_skbuff_setsid(struct sk_buff *skb, 23162306a36Sopenharmony_ci u16 family, 23262306a36Sopenharmony_ci u32 sid) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci int rc; 23562306a36Sopenharmony_ci struct netlbl_lsm_secattr secattr_storage; 23662306a36Sopenharmony_ci struct netlbl_lsm_secattr *secattr = NULL; 23762306a36Sopenharmony_ci struct sock *sk; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci /* if this is a locally generated packet check to see if it is already 24062306a36Sopenharmony_ci * being labeled by it's parent socket, if it is just exit */ 24162306a36Sopenharmony_ci sk = skb_to_full_sk(skb); 24262306a36Sopenharmony_ci if (sk != NULL) { 24362306a36Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (sksec->nlbl_state != NLBL_REQSKB) 24662306a36Sopenharmony_ci return 0; 24762306a36Sopenharmony_ci secattr = selinux_netlbl_sock_getattr(sk, sid); 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci if (secattr == NULL) { 25062306a36Sopenharmony_ci secattr = &secattr_storage; 25162306a36Sopenharmony_ci netlbl_secattr_init(secattr); 25262306a36Sopenharmony_ci rc = security_netlbl_sid_to_secattr(sid, secattr); 25362306a36Sopenharmony_ci if (rc != 0) 25462306a36Sopenharmony_ci goto skbuff_setsid_return; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci rc = netlbl_skbuff_setattr(skb, family, secattr); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ciskbuff_setsid_return: 26062306a36Sopenharmony_ci if (secattr == &secattr_storage) 26162306a36Sopenharmony_ci netlbl_secattr_destroy(secattr); 26262306a36Sopenharmony_ci return rc; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci/** 26662306a36Sopenharmony_ci * selinux_netlbl_sctp_assoc_request - Label an incoming sctp association. 26762306a36Sopenharmony_ci * @asoc: incoming association. 26862306a36Sopenharmony_ci * @skb: the packet. 26962306a36Sopenharmony_ci * 27062306a36Sopenharmony_ci * Description: 27162306a36Sopenharmony_ci * A new incoming connection is represented by @asoc, ...... 27262306a36Sopenharmony_ci * Returns zero on success, negative values on failure. 27362306a36Sopenharmony_ci * 27462306a36Sopenharmony_ci */ 27562306a36Sopenharmony_ciint selinux_netlbl_sctp_assoc_request(struct sctp_association *asoc, 27662306a36Sopenharmony_ci struct sk_buff *skb) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci int rc; 27962306a36Sopenharmony_ci struct netlbl_lsm_secattr secattr; 28062306a36Sopenharmony_ci struct sk_security_struct *sksec = asoc->base.sk->sk_security; 28162306a36Sopenharmony_ci struct sockaddr_in addr4; 28262306a36Sopenharmony_ci struct sockaddr_in6 addr6; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (asoc->base.sk->sk_family != PF_INET && 28562306a36Sopenharmony_ci asoc->base.sk->sk_family != PF_INET6) 28662306a36Sopenharmony_ci return 0; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci netlbl_secattr_init(&secattr); 28962306a36Sopenharmony_ci rc = security_netlbl_sid_to_secattr(asoc->secid, &secattr); 29062306a36Sopenharmony_ci if (rc != 0) 29162306a36Sopenharmony_ci goto assoc_request_return; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci /* Move skb hdr address info to a struct sockaddr and then call 29462306a36Sopenharmony_ci * netlbl_conn_setattr(). 29562306a36Sopenharmony_ci */ 29662306a36Sopenharmony_ci if (ip_hdr(skb)->version == 4) { 29762306a36Sopenharmony_ci addr4.sin_family = AF_INET; 29862306a36Sopenharmony_ci addr4.sin_addr.s_addr = ip_hdr(skb)->saddr; 29962306a36Sopenharmony_ci rc = netlbl_conn_setattr(asoc->base.sk, (void *)&addr4, &secattr); 30062306a36Sopenharmony_ci } else if (IS_ENABLED(CONFIG_IPV6) && ip_hdr(skb)->version == 6) { 30162306a36Sopenharmony_ci addr6.sin6_family = AF_INET6; 30262306a36Sopenharmony_ci addr6.sin6_addr = ipv6_hdr(skb)->saddr; 30362306a36Sopenharmony_ci rc = netlbl_conn_setattr(asoc->base.sk, (void *)&addr6, &secattr); 30462306a36Sopenharmony_ci } else { 30562306a36Sopenharmony_ci rc = -EAFNOSUPPORT; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (rc == 0) 30962306a36Sopenharmony_ci sksec->nlbl_state = NLBL_LABELED; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ciassoc_request_return: 31262306a36Sopenharmony_ci netlbl_secattr_destroy(&secattr); 31362306a36Sopenharmony_ci return rc; 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci/** 31762306a36Sopenharmony_ci * selinux_netlbl_inet_conn_request - Label an incoming stream connection 31862306a36Sopenharmony_ci * @req: incoming connection request socket 31962306a36Sopenharmony_ci * @family: the request socket's address family 32062306a36Sopenharmony_ci * 32162306a36Sopenharmony_ci * Description: 32262306a36Sopenharmony_ci * A new incoming connection request is represented by @req, we need to label 32362306a36Sopenharmony_ci * the new request_sock here and the stack will ensure the on-the-wire label 32462306a36Sopenharmony_ci * will get preserved when a full sock is created once the connection handshake 32562306a36Sopenharmony_ci * is complete. Returns zero on success, negative values on failure. 32662306a36Sopenharmony_ci * 32762306a36Sopenharmony_ci */ 32862306a36Sopenharmony_ciint selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci int rc; 33162306a36Sopenharmony_ci struct netlbl_lsm_secattr secattr; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (family != PF_INET && family != PF_INET6) 33462306a36Sopenharmony_ci return 0; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci netlbl_secattr_init(&secattr); 33762306a36Sopenharmony_ci rc = security_netlbl_sid_to_secattr(req->secid, &secattr); 33862306a36Sopenharmony_ci if (rc != 0) 33962306a36Sopenharmony_ci goto inet_conn_request_return; 34062306a36Sopenharmony_ci rc = netlbl_req_setattr(req, &secattr); 34162306a36Sopenharmony_ciinet_conn_request_return: 34262306a36Sopenharmony_ci netlbl_secattr_destroy(&secattr); 34362306a36Sopenharmony_ci return rc; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci/** 34762306a36Sopenharmony_ci * selinux_netlbl_inet_csk_clone - Initialize the newly created sock 34862306a36Sopenharmony_ci * @sk: the new sock 34962306a36Sopenharmony_ci * @family: the sock's address family 35062306a36Sopenharmony_ci * 35162306a36Sopenharmony_ci * Description: 35262306a36Sopenharmony_ci * A new connection has been established using @sk, we've already labeled the 35362306a36Sopenharmony_ci * socket via the request_sock struct in selinux_netlbl_inet_conn_request() but 35462306a36Sopenharmony_ci * we need to set the NetLabel state here since we now have a sock structure. 35562306a36Sopenharmony_ci * 35662306a36Sopenharmony_ci */ 35762306a36Sopenharmony_civoid selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (family == PF_INET) 36262306a36Sopenharmony_ci sksec->nlbl_state = NLBL_LABELED; 36362306a36Sopenharmony_ci else 36462306a36Sopenharmony_ci sksec->nlbl_state = NLBL_UNSET; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci/** 36862306a36Sopenharmony_ci * selinux_netlbl_sctp_sk_clone - Copy state to the newly created sock 36962306a36Sopenharmony_ci * @sk: current sock 37062306a36Sopenharmony_ci * @newsk: the new sock 37162306a36Sopenharmony_ci * 37262306a36Sopenharmony_ci * Description: 37362306a36Sopenharmony_ci * Called whenever a new socket is created by accept(2) or sctp_peeloff(3). 37462306a36Sopenharmony_ci */ 37562306a36Sopenharmony_civoid selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 37862306a36Sopenharmony_ci struct sk_security_struct *newsksec = newsk->sk_security; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci newsksec->nlbl_state = sksec->nlbl_state; 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci/** 38462306a36Sopenharmony_ci * selinux_netlbl_socket_post_create - Label a socket using NetLabel 38562306a36Sopenharmony_ci * @sk: the sock to label 38662306a36Sopenharmony_ci * @family: protocol family 38762306a36Sopenharmony_ci * 38862306a36Sopenharmony_ci * Description: 38962306a36Sopenharmony_ci * Attempt to label a socket using the NetLabel mechanism using the given 39062306a36Sopenharmony_ci * SID. Returns zero values on success, negative values on failure. 39162306a36Sopenharmony_ci * 39262306a36Sopenharmony_ci */ 39362306a36Sopenharmony_ciint selinux_netlbl_socket_post_create(struct sock *sk, u16 family) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci int rc; 39662306a36Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 39762306a36Sopenharmony_ci struct netlbl_lsm_secattr *secattr; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci if (family != PF_INET && family != PF_INET6) 40062306a36Sopenharmony_ci return 0; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci secattr = selinux_netlbl_sock_genattr(sk); 40362306a36Sopenharmony_ci if (secattr == NULL) 40462306a36Sopenharmony_ci return -ENOMEM; 40562306a36Sopenharmony_ci rc = netlbl_sock_setattr(sk, family, secattr); 40662306a36Sopenharmony_ci switch (rc) { 40762306a36Sopenharmony_ci case 0: 40862306a36Sopenharmony_ci sksec->nlbl_state = NLBL_LABELED; 40962306a36Sopenharmony_ci break; 41062306a36Sopenharmony_ci case -EDESTADDRREQ: 41162306a36Sopenharmony_ci sksec->nlbl_state = NLBL_REQSKB; 41262306a36Sopenharmony_ci rc = 0; 41362306a36Sopenharmony_ci break; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci return rc; 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci/** 42062306a36Sopenharmony_ci * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel 42162306a36Sopenharmony_ci * @sksec: the sock's sk_security_struct 42262306a36Sopenharmony_ci * @skb: the packet 42362306a36Sopenharmony_ci * @family: protocol family 42462306a36Sopenharmony_ci * @ad: the audit data 42562306a36Sopenharmony_ci * 42662306a36Sopenharmony_ci * Description: 42762306a36Sopenharmony_ci * Fetch the NetLabel security attributes from @skb and perform an access check 42862306a36Sopenharmony_ci * against the receiving socket. Returns zero on success, negative values on 42962306a36Sopenharmony_ci * error. 43062306a36Sopenharmony_ci * 43162306a36Sopenharmony_ci */ 43262306a36Sopenharmony_ciint selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, 43362306a36Sopenharmony_ci struct sk_buff *skb, 43462306a36Sopenharmony_ci u16 family, 43562306a36Sopenharmony_ci struct common_audit_data *ad) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci int rc; 43862306a36Sopenharmony_ci u32 nlbl_sid; 43962306a36Sopenharmony_ci u32 perm; 44062306a36Sopenharmony_ci struct netlbl_lsm_secattr secattr; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (!netlbl_enabled()) 44362306a36Sopenharmony_ci return 0; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci netlbl_secattr_init(&secattr); 44662306a36Sopenharmony_ci rc = netlbl_skbuff_getattr(skb, family, &secattr); 44762306a36Sopenharmony_ci if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) 44862306a36Sopenharmony_ci rc = selinux_netlbl_sidlookup_cached(skb, family, 44962306a36Sopenharmony_ci &secattr, &nlbl_sid); 45062306a36Sopenharmony_ci else 45162306a36Sopenharmony_ci nlbl_sid = SECINITSID_UNLABELED; 45262306a36Sopenharmony_ci netlbl_secattr_destroy(&secattr); 45362306a36Sopenharmony_ci if (rc != 0) 45462306a36Sopenharmony_ci return rc; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci switch (sksec->sclass) { 45762306a36Sopenharmony_ci case SECCLASS_UDP_SOCKET: 45862306a36Sopenharmony_ci perm = UDP_SOCKET__RECVFROM; 45962306a36Sopenharmony_ci break; 46062306a36Sopenharmony_ci case SECCLASS_TCP_SOCKET: 46162306a36Sopenharmony_ci perm = TCP_SOCKET__RECVFROM; 46262306a36Sopenharmony_ci break; 46362306a36Sopenharmony_ci default: 46462306a36Sopenharmony_ci perm = RAWIP_SOCKET__RECVFROM; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci rc = avc_has_perm(sksec->sid, nlbl_sid, sksec->sclass, perm, ad); 46862306a36Sopenharmony_ci if (rc == 0) 46962306a36Sopenharmony_ci return 0; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (nlbl_sid != SECINITSID_UNLABELED) 47262306a36Sopenharmony_ci netlbl_skbuff_err(skb, family, rc, 0); 47362306a36Sopenharmony_ci return rc; 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci/** 47762306a36Sopenharmony_ci * selinux_netlbl_option - Is this a NetLabel option 47862306a36Sopenharmony_ci * @level: the socket level or protocol 47962306a36Sopenharmony_ci * @optname: the socket option name 48062306a36Sopenharmony_ci * 48162306a36Sopenharmony_ci * Description: 48262306a36Sopenharmony_ci * Returns true if @level and @optname refer to a NetLabel option. 48362306a36Sopenharmony_ci * Helper for selinux_netlbl_socket_setsockopt(). 48462306a36Sopenharmony_ci */ 48562306a36Sopenharmony_cistatic inline int selinux_netlbl_option(int level, int optname) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci return (level == IPPROTO_IP && optname == IP_OPTIONS) || 48862306a36Sopenharmony_ci (level == IPPROTO_IPV6 && optname == IPV6_HOPOPTS); 48962306a36Sopenharmony_ci} 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci/** 49262306a36Sopenharmony_ci * selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel 49362306a36Sopenharmony_ci * @sock: the socket 49462306a36Sopenharmony_ci * @level: the socket level or protocol 49562306a36Sopenharmony_ci * @optname: the socket option name 49662306a36Sopenharmony_ci * 49762306a36Sopenharmony_ci * Description: 49862306a36Sopenharmony_ci * Check the setsockopt() call and if the user is trying to replace the IP 49962306a36Sopenharmony_ci * options on a socket and a NetLabel is in place for the socket deny the 50062306a36Sopenharmony_ci * access; otherwise allow the access. Returns zero when the access is 50162306a36Sopenharmony_ci * allowed, -EACCES when denied, and other negative values on error. 50262306a36Sopenharmony_ci * 50362306a36Sopenharmony_ci */ 50462306a36Sopenharmony_ciint selinux_netlbl_socket_setsockopt(struct socket *sock, 50562306a36Sopenharmony_ci int level, 50662306a36Sopenharmony_ci int optname) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci int rc = 0; 50962306a36Sopenharmony_ci struct sock *sk = sock->sk; 51062306a36Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 51162306a36Sopenharmony_ci struct netlbl_lsm_secattr secattr; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (selinux_netlbl_option(level, optname) && 51462306a36Sopenharmony_ci (sksec->nlbl_state == NLBL_LABELED || 51562306a36Sopenharmony_ci sksec->nlbl_state == NLBL_CONNLABELED)) { 51662306a36Sopenharmony_ci netlbl_secattr_init(&secattr); 51762306a36Sopenharmony_ci lock_sock(sk); 51862306a36Sopenharmony_ci /* call the netlabel function directly as we want to see the 51962306a36Sopenharmony_ci * on-the-wire label that is assigned via the socket's options 52062306a36Sopenharmony_ci * and not the cached netlabel/lsm attributes */ 52162306a36Sopenharmony_ci rc = netlbl_sock_getattr(sk, &secattr); 52262306a36Sopenharmony_ci release_sock(sk); 52362306a36Sopenharmony_ci if (rc == 0) 52462306a36Sopenharmony_ci rc = -EACCES; 52562306a36Sopenharmony_ci else if (rc == -ENOMSG) 52662306a36Sopenharmony_ci rc = 0; 52762306a36Sopenharmony_ci netlbl_secattr_destroy(&secattr); 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci return rc; 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci/** 53462306a36Sopenharmony_ci * selinux_netlbl_socket_connect_helper - Help label a client-side socket on 53562306a36Sopenharmony_ci * connect 53662306a36Sopenharmony_ci * @sk: the socket to label 53762306a36Sopenharmony_ci * @addr: the destination address 53862306a36Sopenharmony_ci * 53962306a36Sopenharmony_ci * Description: 54062306a36Sopenharmony_ci * Attempt to label a connected socket with NetLabel using the given address. 54162306a36Sopenharmony_ci * Returns zero values on success, negative values on failure. 54262306a36Sopenharmony_ci * 54362306a36Sopenharmony_ci */ 54462306a36Sopenharmony_cistatic int selinux_netlbl_socket_connect_helper(struct sock *sk, 54562306a36Sopenharmony_ci struct sockaddr *addr) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci int rc; 54862306a36Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 54962306a36Sopenharmony_ci struct netlbl_lsm_secattr *secattr; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci /* connected sockets are allowed to disconnect when the address family 55262306a36Sopenharmony_ci * is set to AF_UNSPEC, if that is what is happening we want to reset 55362306a36Sopenharmony_ci * the socket */ 55462306a36Sopenharmony_ci if (addr->sa_family == AF_UNSPEC) { 55562306a36Sopenharmony_ci netlbl_sock_delattr(sk); 55662306a36Sopenharmony_ci sksec->nlbl_state = NLBL_REQSKB; 55762306a36Sopenharmony_ci rc = 0; 55862306a36Sopenharmony_ci return rc; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci secattr = selinux_netlbl_sock_genattr(sk); 56162306a36Sopenharmony_ci if (secattr == NULL) { 56262306a36Sopenharmony_ci rc = -ENOMEM; 56362306a36Sopenharmony_ci return rc; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci rc = netlbl_conn_setattr(sk, addr, secattr); 56662306a36Sopenharmony_ci if (rc == 0) 56762306a36Sopenharmony_ci sksec->nlbl_state = NLBL_CONNLABELED; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci return rc; 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci/** 57362306a36Sopenharmony_ci * selinux_netlbl_socket_connect_locked - Label a client-side socket on 57462306a36Sopenharmony_ci * connect 57562306a36Sopenharmony_ci * @sk: the socket to label 57662306a36Sopenharmony_ci * @addr: the destination address 57762306a36Sopenharmony_ci * 57862306a36Sopenharmony_ci * Description: 57962306a36Sopenharmony_ci * Attempt to label a connected socket that already has the socket locked 58062306a36Sopenharmony_ci * with NetLabel using the given address. 58162306a36Sopenharmony_ci * Returns zero values on success, negative values on failure. 58262306a36Sopenharmony_ci * 58362306a36Sopenharmony_ci */ 58462306a36Sopenharmony_ciint selinux_netlbl_socket_connect_locked(struct sock *sk, 58562306a36Sopenharmony_ci struct sockaddr *addr) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci if (sksec->nlbl_state != NLBL_REQSKB && 59062306a36Sopenharmony_ci sksec->nlbl_state != NLBL_CONNLABELED) 59162306a36Sopenharmony_ci return 0; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci return selinux_netlbl_socket_connect_helper(sk, addr); 59462306a36Sopenharmony_ci} 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci/** 59762306a36Sopenharmony_ci * selinux_netlbl_socket_connect - Label a client-side socket on connect 59862306a36Sopenharmony_ci * @sk: the socket to label 59962306a36Sopenharmony_ci * @addr: the destination address 60062306a36Sopenharmony_ci * 60162306a36Sopenharmony_ci * Description: 60262306a36Sopenharmony_ci * Attempt to label a connected socket with NetLabel using the given address. 60362306a36Sopenharmony_ci * Returns zero values on success, negative values on failure. 60462306a36Sopenharmony_ci * 60562306a36Sopenharmony_ci */ 60662306a36Sopenharmony_ciint selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci int rc; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci lock_sock(sk); 61162306a36Sopenharmony_ci rc = selinux_netlbl_socket_connect_locked(sk, addr); 61262306a36Sopenharmony_ci release_sock(sk); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci return rc; 61562306a36Sopenharmony_ci} 616