18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * SELinux NetLabel Support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This file provides the necessary glue to tie NetLabel into the SELinux 68c2ecf20Sopenharmony_ci * subsystem. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Author: Paul Moore <paul@paul-moore.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci/* 128c2ecf20Sopenharmony_ci * (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 168c2ecf20Sopenharmony_ci#include <linux/rcupdate.h> 178c2ecf20Sopenharmony_ci#include <linux/gfp.h> 188c2ecf20Sopenharmony_ci#include <linux/ip.h> 198c2ecf20Sopenharmony_ci#include <linux/ipv6.h> 208c2ecf20Sopenharmony_ci#include <net/sock.h> 218c2ecf20Sopenharmony_ci#include <net/netlabel.h> 228c2ecf20Sopenharmony_ci#include <net/ip.h> 238c2ecf20Sopenharmony_ci#include <net/ipv6.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "objsec.h" 268c2ecf20Sopenharmony_ci#include "security.h" 278c2ecf20Sopenharmony_ci#include "netlabel.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/** 308c2ecf20Sopenharmony_ci * selinux_netlbl_sidlookup_cached - Cache a SID lookup 318c2ecf20Sopenharmony_ci * @skb: the packet 328c2ecf20Sopenharmony_ci * @secattr: the NetLabel security attributes 338c2ecf20Sopenharmony_ci * @sid: the SID 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * Description: 368c2ecf20Sopenharmony_ci * Query the SELinux security server to lookup the correct SID for the given 378c2ecf20Sopenharmony_ci * security attributes. If the query is successful, cache the result to speed 388c2ecf20Sopenharmony_ci * up future lookups. Returns zero on success, negative values on failure. 398c2ecf20Sopenharmony_ci * 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_cistatic int selinux_netlbl_sidlookup_cached(struct sk_buff *skb, 428c2ecf20Sopenharmony_ci u16 family, 438c2ecf20Sopenharmony_ci struct netlbl_lsm_secattr *secattr, 448c2ecf20Sopenharmony_ci u32 *sid) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci int rc; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci rc = security_netlbl_secattr_to_sid(&selinux_state, secattr, sid); 498c2ecf20Sopenharmony_ci if (rc == 0 && 508c2ecf20Sopenharmony_ci (secattr->flags & NETLBL_SECATTR_CACHEABLE) && 518c2ecf20Sopenharmony_ci (secattr->flags & NETLBL_SECATTR_CACHE)) 528c2ecf20Sopenharmony_ci netlbl_cache_add(skb, family, secattr); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci return rc; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/** 588c2ecf20Sopenharmony_ci * selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr 598c2ecf20Sopenharmony_ci * @sk: the socket 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci * Description: 628c2ecf20Sopenharmony_ci * Generate the NetLabel security attributes for a socket, making full use of 638c2ecf20Sopenharmony_ci * the socket's attribute cache. Returns a pointer to the security attributes 648c2ecf20Sopenharmony_ci * on success, NULL on failure. 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_cistatic struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci int rc; 708c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 718c2ecf20Sopenharmony_ci struct netlbl_lsm_secattr *secattr; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if (sksec->nlbl_secattr != NULL) 748c2ecf20Sopenharmony_ci return sksec->nlbl_secattr; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci secattr = netlbl_secattr_alloc(GFP_ATOMIC); 778c2ecf20Sopenharmony_ci if (secattr == NULL) 788c2ecf20Sopenharmony_ci return NULL; 798c2ecf20Sopenharmony_ci rc = security_netlbl_sid_to_secattr(&selinux_state, sksec->sid, 808c2ecf20Sopenharmony_ci secattr); 818c2ecf20Sopenharmony_ci if (rc != 0) { 828c2ecf20Sopenharmony_ci netlbl_secattr_free(secattr); 838c2ecf20Sopenharmony_ci return NULL; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci sksec->nlbl_secattr = secattr; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci return secattr; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/** 918c2ecf20Sopenharmony_ci * selinux_netlbl_sock_getattr - Get the cached NetLabel secattr 928c2ecf20Sopenharmony_ci * @sk: the socket 938c2ecf20Sopenharmony_ci * @sid: the SID 948c2ecf20Sopenharmony_ci * 958c2ecf20Sopenharmony_ci * Query the socket's cached secattr and if the SID matches the cached value 968c2ecf20Sopenharmony_ci * return the cache, otherwise return NULL. 978c2ecf20Sopenharmony_ci * 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_cistatic struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr( 1008c2ecf20Sopenharmony_ci const struct sock *sk, 1018c2ecf20Sopenharmony_ci u32 sid) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 1048c2ecf20Sopenharmony_ci struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (secattr == NULL) 1078c2ecf20Sopenharmony_ci return NULL; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if ((secattr->flags & NETLBL_SECATTR_SECID) && 1108c2ecf20Sopenharmony_ci (secattr->attr.secid == sid)) 1118c2ecf20Sopenharmony_ci return secattr; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci return NULL; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci/** 1178c2ecf20Sopenharmony_ci * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache 1188c2ecf20Sopenharmony_ci * 1198c2ecf20Sopenharmony_ci * Description: 1208c2ecf20Sopenharmony_ci * Invalidate the NetLabel security attribute mapping cache. 1218c2ecf20Sopenharmony_ci * 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_civoid selinux_netlbl_cache_invalidate(void) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci netlbl_cache_invalidate(); 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci/** 1298c2ecf20Sopenharmony_ci * selinux_netlbl_err - Handle a NetLabel packet error 1308c2ecf20Sopenharmony_ci * @skb: the packet 1318c2ecf20Sopenharmony_ci * @error: the error code 1328c2ecf20Sopenharmony_ci * @gateway: true if host is acting as a gateway, false otherwise 1338c2ecf20Sopenharmony_ci * 1348c2ecf20Sopenharmony_ci * Description: 1358c2ecf20Sopenharmony_ci * When a packet is dropped due to a call to avc_has_perm() pass the error 1368c2ecf20Sopenharmony_ci * code to the NetLabel subsystem so any protocol specific processing can be 1378c2ecf20Sopenharmony_ci * done. This is safe to call even if you are unsure if NetLabel labeling is 1388c2ecf20Sopenharmony_ci * present on the packet, NetLabel is smart enough to only act when it should. 1398c2ecf20Sopenharmony_ci * 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_civoid selinux_netlbl_err(struct sk_buff *skb, u16 family, int error, int gateway) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci netlbl_skbuff_err(skb, family, error, gateway); 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/** 1478c2ecf20Sopenharmony_ci * selinux_netlbl_sk_security_free - Free the NetLabel fields 1488c2ecf20Sopenharmony_ci * @sksec: the sk_security_struct 1498c2ecf20Sopenharmony_ci * 1508c2ecf20Sopenharmony_ci * Description: 1518c2ecf20Sopenharmony_ci * Free all of the memory in the NetLabel fields of a sk_security_struct. 1528c2ecf20Sopenharmony_ci * 1538c2ecf20Sopenharmony_ci */ 1548c2ecf20Sopenharmony_civoid selinux_netlbl_sk_security_free(struct sk_security_struct *sksec) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci if (sksec->nlbl_secattr != NULL) 1578c2ecf20Sopenharmony_ci netlbl_secattr_free(sksec->nlbl_secattr); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/** 1618c2ecf20Sopenharmony_ci * selinux_netlbl_sk_security_reset - Reset the NetLabel fields 1628c2ecf20Sopenharmony_ci * @sksec: the sk_security_struct 1638c2ecf20Sopenharmony_ci * @family: the socket family 1648c2ecf20Sopenharmony_ci * 1658c2ecf20Sopenharmony_ci * Description: 1668c2ecf20Sopenharmony_ci * Called when the NetLabel state of a sk_security_struct needs to be reset. 1678c2ecf20Sopenharmony_ci * The caller is responsible for all the NetLabel sk_security_struct locking. 1688c2ecf20Sopenharmony_ci * 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_civoid selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci sksec->nlbl_state = NLBL_UNSET; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/** 1768c2ecf20Sopenharmony_ci * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel 1778c2ecf20Sopenharmony_ci * @skb: the packet 1788c2ecf20Sopenharmony_ci * @family: protocol family 1798c2ecf20Sopenharmony_ci * @type: NetLabel labeling protocol type 1808c2ecf20Sopenharmony_ci * @sid: the SID 1818c2ecf20Sopenharmony_ci * 1828c2ecf20Sopenharmony_ci * Description: 1838c2ecf20Sopenharmony_ci * Call the NetLabel mechanism to get the security attributes of the given 1848c2ecf20Sopenharmony_ci * packet and use those attributes to determine the correct context/SID to 1858c2ecf20Sopenharmony_ci * assign to the packet. Returns zero on success, negative values on failure. 1868c2ecf20Sopenharmony_ci * 1878c2ecf20Sopenharmony_ci */ 1888c2ecf20Sopenharmony_ciint selinux_netlbl_skbuff_getsid(struct sk_buff *skb, 1898c2ecf20Sopenharmony_ci u16 family, 1908c2ecf20Sopenharmony_ci u32 *type, 1918c2ecf20Sopenharmony_ci u32 *sid) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci int rc; 1948c2ecf20Sopenharmony_ci struct netlbl_lsm_secattr secattr; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (!netlbl_enabled()) { 1978c2ecf20Sopenharmony_ci *sid = SECSID_NULL; 1988c2ecf20Sopenharmony_ci return 0; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci netlbl_secattr_init(&secattr); 2028c2ecf20Sopenharmony_ci rc = netlbl_skbuff_getattr(skb, family, &secattr); 2038c2ecf20Sopenharmony_ci if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) 2048c2ecf20Sopenharmony_ci rc = selinux_netlbl_sidlookup_cached(skb, family, 2058c2ecf20Sopenharmony_ci &secattr, sid); 2068c2ecf20Sopenharmony_ci else 2078c2ecf20Sopenharmony_ci *sid = SECSID_NULL; 2088c2ecf20Sopenharmony_ci *type = secattr.type; 2098c2ecf20Sopenharmony_ci netlbl_secattr_destroy(&secattr); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci return rc; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci/** 2158c2ecf20Sopenharmony_ci * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid 2168c2ecf20Sopenharmony_ci * @skb: the packet 2178c2ecf20Sopenharmony_ci * @family: protocol family 2188c2ecf20Sopenharmony_ci * @sid: the SID 2198c2ecf20Sopenharmony_ci * 2208c2ecf20Sopenharmony_ci * Description 2218c2ecf20Sopenharmony_ci * Call the NetLabel mechanism to set the label of a packet using @sid. 2228c2ecf20Sopenharmony_ci * Returns zero on success, negative values on failure. 2238c2ecf20Sopenharmony_ci * 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ciint selinux_netlbl_skbuff_setsid(struct sk_buff *skb, 2268c2ecf20Sopenharmony_ci u16 family, 2278c2ecf20Sopenharmony_ci u32 sid) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci int rc; 2308c2ecf20Sopenharmony_ci struct netlbl_lsm_secattr secattr_storage; 2318c2ecf20Sopenharmony_ci struct netlbl_lsm_secattr *secattr = NULL; 2328c2ecf20Sopenharmony_ci struct sock *sk; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci /* if this is a locally generated packet check to see if it is already 2358c2ecf20Sopenharmony_ci * being labeled by it's parent socket, if it is just exit */ 2368c2ecf20Sopenharmony_ci sk = skb_to_full_sk(skb); 2378c2ecf20Sopenharmony_ci if (sk != NULL) { 2388c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (sksec->nlbl_state != NLBL_REQSKB) 2418c2ecf20Sopenharmony_ci return 0; 2428c2ecf20Sopenharmony_ci secattr = selinux_netlbl_sock_getattr(sk, sid); 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci if (secattr == NULL) { 2458c2ecf20Sopenharmony_ci secattr = &secattr_storage; 2468c2ecf20Sopenharmony_ci netlbl_secattr_init(secattr); 2478c2ecf20Sopenharmony_ci rc = security_netlbl_sid_to_secattr(&selinux_state, sid, 2488c2ecf20Sopenharmony_ci secattr); 2498c2ecf20Sopenharmony_ci if (rc != 0) 2508c2ecf20Sopenharmony_ci goto skbuff_setsid_return; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci rc = netlbl_skbuff_setattr(skb, family, secattr); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ciskbuff_setsid_return: 2568c2ecf20Sopenharmony_ci if (secattr == &secattr_storage) 2578c2ecf20Sopenharmony_ci netlbl_secattr_destroy(secattr); 2588c2ecf20Sopenharmony_ci return rc; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci/** 2628c2ecf20Sopenharmony_ci * selinux_netlbl_sctp_assoc_request - Label an incoming sctp association. 2638c2ecf20Sopenharmony_ci * @ep: incoming association endpoint. 2648c2ecf20Sopenharmony_ci * @skb: the packet. 2658c2ecf20Sopenharmony_ci * 2668c2ecf20Sopenharmony_ci * Description: 2678c2ecf20Sopenharmony_ci * A new incoming connection is represented by @ep, ...... 2688c2ecf20Sopenharmony_ci * Returns zero on success, negative values on failure. 2698c2ecf20Sopenharmony_ci * 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_ciint selinux_netlbl_sctp_assoc_request(struct sctp_endpoint *ep, 2728c2ecf20Sopenharmony_ci struct sk_buff *skb) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci int rc; 2758c2ecf20Sopenharmony_ci struct netlbl_lsm_secattr secattr; 2768c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = ep->base.sk->sk_security; 2778c2ecf20Sopenharmony_ci struct sockaddr_in addr4; 2788c2ecf20Sopenharmony_ci struct sockaddr_in6 addr6; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (ep->base.sk->sk_family != PF_INET && 2818c2ecf20Sopenharmony_ci ep->base.sk->sk_family != PF_INET6) 2828c2ecf20Sopenharmony_ci return 0; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci netlbl_secattr_init(&secattr); 2858c2ecf20Sopenharmony_ci rc = security_netlbl_sid_to_secattr(&selinux_state, 2868c2ecf20Sopenharmony_ci ep->secid, &secattr); 2878c2ecf20Sopenharmony_ci if (rc != 0) 2888c2ecf20Sopenharmony_ci goto assoc_request_return; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* Move skb hdr address info to a struct sockaddr and then call 2918c2ecf20Sopenharmony_ci * netlbl_conn_setattr(). 2928c2ecf20Sopenharmony_ci */ 2938c2ecf20Sopenharmony_ci if (ip_hdr(skb)->version == 4) { 2948c2ecf20Sopenharmony_ci addr4.sin_family = AF_INET; 2958c2ecf20Sopenharmony_ci addr4.sin_addr.s_addr = ip_hdr(skb)->saddr; 2968c2ecf20Sopenharmony_ci rc = netlbl_conn_setattr(ep->base.sk, (void *)&addr4, &secattr); 2978c2ecf20Sopenharmony_ci } else if (IS_ENABLED(CONFIG_IPV6) && ip_hdr(skb)->version == 6) { 2988c2ecf20Sopenharmony_ci addr6.sin6_family = AF_INET6; 2998c2ecf20Sopenharmony_ci addr6.sin6_addr = ipv6_hdr(skb)->saddr; 3008c2ecf20Sopenharmony_ci rc = netlbl_conn_setattr(ep->base.sk, (void *)&addr6, &secattr); 3018c2ecf20Sopenharmony_ci } else { 3028c2ecf20Sopenharmony_ci rc = -EAFNOSUPPORT; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci if (rc == 0) 3068c2ecf20Sopenharmony_ci sksec->nlbl_state = NLBL_LABELED; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ciassoc_request_return: 3098c2ecf20Sopenharmony_ci netlbl_secattr_destroy(&secattr); 3108c2ecf20Sopenharmony_ci return rc; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci/** 3148c2ecf20Sopenharmony_ci * selinux_netlbl_inet_conn_request - Label an incoming stream connection 3158c2ecf20Sopenharmony_ci * @req: incoming connection request socket 3168c2ecf20Sopenharmony_ci * 3178c2ecf20Sopenharmony_ci * Description: 3188c2ecf20Sopenharmony_ci * A new incoming connection request is represented by @req, we need to label 3198c2ecf20Sopenharmony_ci * the new request_sock here and the stack will ensure the on-the-wire label 3208c2ecf20Sopenharmony_ci * will get preserved when a full sock is created once the connection handshake 3218c2ecf20Sopenharmony_ci * is complete. Returns zero on success, negative values on failure. 3228c2ecf20Sopenharmony_ci * 3238c2ecf20Sopenharmony_ci */ 3248c2ecf20Sopenharmony_ciint selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci int rc; 3278c2ecf20Sopenharmony_ci struct netlbl_lsm_secattr secattr; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (family != PF_INET && family != PF_INET6) 3308c2ecf20Sopenharmony_ci return 0; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci netlbl_secattr_init(&secattr); 3338c2ecf20Sopenharmony_ci rc = security_netlbl_sid_to_secattr(&selinux_state, req->secid, 3348c2ecf20Sopenharmony_ci &secattr); 3358c2ecf20Sopenharmony_ci if (rc != 0) 3368c2ecf20Sopenharmony_ci goto inet_conn_request_return; 3378c2ecf20Sopenharmony_ci rc = netlbl_req_setattr(req, &secattr); 3388c2ecf20Sopenharmony_ciinet_conn_request_return: 3398c2ecf20Sopenharmony_ci netlbl_secattr_destroy(&secattr); 3408c2ecf20Sopenharmony_ci return rc; 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci/** 3448c2ecf20Sopenharmony_ci * selinux_netlbl_inet_csk_clone - Initialize the newly created sock 3458c2ecf20Sopenharmony_ci * @sk: the new sock 3468c2ecf20Sopenharmony_ci * 3478c2ecf20Sopenharmony_ci * Description: 3488c2ecf20Sopenharmony_ci * A new connection has been established using @sk, we've already labeled the 3498c2ecf20Sopenharmony_ci * socket via the request_sock struct in selinux_netlbl_inet_conn_request() but 3508c2ecf20Sopenharmony_ci * we need to set the NetLabel state here since we now have a sock structure. 3518c2ecf20Sopenharmony_ci * 3528c2ecf20Sopenharmony_ci */ 3538c2ecf20Sopenharmony_civoid selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (family == PF_INET) 3588c2ecf20Sopenharmony_ci sksec->nlbl_state = NLBL_LABELED; 3598c2ecf20Sopenharmony_ci else 3608c2ecf20Sopenharmony_ci sksec->nlbl_state = NLBL_UNSET; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci/** 3648c2ecf20Sopenharmony_ci * selinux_netlbl_sctp_sk_clone - Copy state to the newly created sock 3658c2ecf20Sopenharmony_ci * @sk: current sock 3668c2ecf20Sopenharmony_ci * @newsk: the new sock 3678c2ecf20Sopenharmony_ci * 3688c2ecf20Sopenharmony_ci * Description: 3698c2ecf20Sopenharmony_ci * Called whenever a new socket is created by accept(2) or sctp_peeloff(3). 3708c2ecf20Sopenharmony_ci */ 3718c2ecf20Sopenharmony_civoid selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 3748c2ecf20Sopenharmony_ci struct sk_security_struct *newsksec = newsk->sk_security; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci newsksec->nlbl_state = sksec->nlbl_state; 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci/** 3808c2ecf20Sopenharmony_ci * selinux_netlbl_socket_post_create - Label a socket using NetLabel 3818c2ecf20Sopenharmony_ci * @sock: the socket to label 3828c2ecf20Sopenharmony_ci * @family: protocol family 3838c2ecf20Sopenharmony_ci * 3848c2ecf20Sopenharmony_ci * Description: 3858c2ecf20Sopenharmony_ci * Attempt to label a socket using the NetLabel mechanism using the given 3868c2ecf20Sopenharmony_ci * SID. Returns zero values on success, negative values on failure. 3878c2ecf20Sopenharmony_ci * 3888c2ecf20Sopenharmony_ci */ 3898c2ecf20Sopenharmony_ciint selinux_netlbl_socket_post_create(struct sock *sk, u16 family) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci int rc; 3928c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 3938c2ecf20Sopenharmony_ci struct netlbl_lsm_secattr *secattr; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (family != PF_INET && family != PF_INET6) 3968c2ecf20Sopenharmony_ci return 0; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci secattr = selinux_netlbl_sock_genattr(sk); 3998c2ecf20Sopenharmony_ci if (secattr == NULL) 4008c2ecf20Sopenharmony_ci return -ENOMEM; 4018c2ecf20Sopenharmony_ci rc = netlbl_sock_setattr(sk, family, secattr); 4028c2ecf20Sopenharmony_ci switch (rc) { 4038c2ecf20Sopenharmony_ci case 0: 4048c2ecf20Sopenharmony_ci sksec->nlbl_state = NLBL_LABELED; 4058c2ecf20Sopenharmony_ci break; 4068c2ecf20Sopenharmony_ci case -EDESTADDRREQ: 4078c2ecf20Sopenharmony_ci sksec->nlbl_state = NLBL_REQSKB; 4088c2ecf20Sopenharmony_ci rc = 0; 4098c2ecf20Sopenharmony_ci break; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci return rc; 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci/** 4168c2ecf20Sopenharmony_ci * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel 4178c2ecf20Sopenharmony_ci * @sksec: the sock's sk_security_struct 4188c2ecf20Sopenharmony_ci * @skb: the packet 4198c2ecf20Sopenharmony_ci * @family: protocol family 4208c2ecf20Sopenharmony_ci * @ad: the audit data 4218c2ecf20Sopenharmony_ci * 4228c2ecf20Sopenharmony_ci * Description: 4238c2ecf20Sopenharmony_ci * Fetch the NetLabel security attributes from @skb and perform an access check 4248c2ecf20Sopenharmony_ci * against the receiving socket. Returns zero on success, negative values on 4258c2ecf20Sopenharmony_ci * error. 4268c2ecf20Sopenharmony_ci * 4278c2ecf20Sopenharmony_ci */ 4288c2ecf20Sopenharmony_ciint selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, 4298c2ecf20Sopenharmony_ci struct sk_buff *skb, 4308c2ecf20Sopenharmony_ci u16 family, 4318c2ecf20Sopenharmony_ci struct common_audit_data *ad) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci int rc; 4348c2ecf20Sopenharmony_ci u32 nlbl_sid; 4358c2ecf20Sopenharmony_ci u32 perm; 4368c2ecf20Sopenharmony_ci struct netlbl_lsm_secattr secattr; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (!netlbl_enabled()) 4398c2ecf20Sopenharmony_ci return 0; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci netlbl_secattr_init(&secattr); 4428c2ecf20Sopenharmony_ci rc = netlbl_skbuff_getattr(skb, family, &secattr); 4438c2ecf20Sopenharmony_ci if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) 4448c2ecf20Sopenharmony_ci rc = selinux_netlbl_sidlookup_cached(skb, family, 4458c2ecf20Sopenharmony_ci &secattr, &nlbl_sid); 4468c2ecf20Sopenharmony_ci else 4478c2ecf20Sopenharmony_ci nlbl_sid = SECINITSID_UNLABELED; 4488c2ecf20Sopenharmony_ci netlbl_secattr_destroy(&secattr); 4498c2ecf20Sopenharmony_ci if (rc != 0) 4508c2ecf20Sopenharmony_ci return rc; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci switch (sksec->sclass) { 4538c2ecf20Sopenharmony_ci case SECCLASS_UDP_SOCKET: 4548c2ecf20Sopenharmony_ci perm = UDP_SOCKET__RECVFROM; 4558c2ecf20Sopenharmony_ci break; 4568c2ecf20Sopenharmony_ci case SECCLASS_TCP_SOCKET: 4578c2ecf20Sopenharmony_ci perm = TCP_SOCKET__RECVFROM; 4588c2ecf20Sopenharmony_ci break; 4598c2ecf20Sopenharmony_ci default: 4608c2ecf20Sopenharmony_ci perm = RAWIP_SOCKET__RECVFROM; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 4648c2ecf20Sopenharmony_ci sksec->sid, nlbl_sid, sksec->sclass, perm, ad); 4658c2ecf20Sopenharmony_ci if (rc == 0) 4668c2ecf20Sopenharmony_ci return 0; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci if (nlbl_sid != SECINITSID_UNLABELED) 4698c2ecf20Sopenharmony_ci netlbl_skbuff_err(skb, family, rc, 0); 4708c2ecf20Sopenharmony_ci return rc; 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci/** 4748c2ecf20Sopenharmony_ci * selinux_netlbl_option - Is this a NetLabel option 4758c2ecf20Sopenharmony_ci * @level: the socket level or protocol 4768c2ecf20Sopenharmony_ci * @optname: the socket option name 4778c2ecf20Sopenharmony_ci * 4788c2ecf20Sopenharmony_ci * Description: 4798c2ecf20Sopenharmony_ci * Returns true if @level and @optname refer to a NetLabel option. 4808c2ecf20Sopenharmony_ci * Helper for selinux_netlbl_socket_setsockopt(). 4818c2ecf20Sopenharmony_ci */ 4828c2ecf20Sopenharmony_cistatic inline int selinux_netlbl_option(int level, int optname) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci return (level == IPPROTO_IP && optname == IP_OPTIONS) || 4858c2ecf20Sopenharmony_ci (level == IPPROTO_IPV6 && optname == IPV6_HOPOPTS); 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci/** 4898c2ecf20Sopenharmony_ci * selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel 4908c2ecf20Sopenharmony_ci * @sock: the socket 4918c2ecf20Sopenharmony_ci * @level: the socket level or protocol 4928c2ecf20Sopenharmony_ci * @optname: the socket option name 4938c2ecf20Sopenharmony_ci * 4948c2ecf20Sopenharmony_ci * Description: 4958c2ecf20Sopenharmony_ci * Check the setsockopt() call and if the user is trying to replace the IP 4968c2ecf20Sopenharmony_ci * options on a socket and a NetLabel is in place for the socket deny the 4978c2ecf20Sopenharmony_ci * access; otherwise allow the access. Returns zero when the access is 4988c2ecf20Sopenharmony_ci * allowed, -EACCES when denied, and other negative values on error. 4998c2ecf20Sopenharmony_ci * 5008c2ecf20Sopenharmony_ci */ 5018c2ecf20Sopenharmony_ciint selinux_netlbl_socket_setsockopt(struct socket *sock, 5028c2ecf20Sopenharmony_ci int level, 5038c2ecf20Sopenharmony_ci int optname) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci int rc = 0; 5068c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 5078c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 5088c2ecf20Sopenharmony_ci struct netlbl_lsm_secattr secattr; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci if (selinux_netlbl_option(level, optname) && 5118c2ecf20Sopenharmony_ci (sksec->nlbl_state == NLBL_LABELED || 5128c2ecf20Sopenharmony_ci sksec->nlbl_state == NLBL_CONNLABELED)) { 5138c2ecf20Sopenharmony_ci netlbl_secattr_init(&secattr); 5148c2ecf20Sopenharmony_ci lock_sock(sk); 5158c2ecf20Sopenharmony_ci /* call the netlabel function directly as we want to see the 5168c2ecf20Sopenharmony_ci * on-the-wire label that is assigned via the socket's options 5178c2ecf20Sopenharmony_ci * and not the cached netlabel/lsm attributes */ 5188c2ecf20Sopenharmony_ci rc = netlbl_sock_getattr(sk, &secattr); 5198c2ecf20Sopenharmony_ci release_sock(sk); 5208c2ecf20Sopenharmony_ci if (rc == 0) 5218c2ecf20Sopenharmony_ci rc = -EACCES; 5228c2ecf20Sopenharmony_ci else if (rc == -ENOMSG) 5238c2ecf20Sopenharmony_ci rc = 0; 5248c2ecf20Sopenharmony_ci netlbl_secattr_destroy(&secattr); 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci return rc; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci/** 5318c2ecf20Sopenharmony_ci * selinux_netlbl_socket_connect_helper - Help label a client-side socket on 5328c2ecf20Sopenharmony_ci * connect 5338c2ecf20Sopenharmony_ci * @sk: the socket to label 5348c2ecf20Sopenharmony_ci * @addr: the destination address 5358c2ecf20Sopenharmony_ci * 5368c2ecf20Sopenharmony_ci * Description: 5378c2ecf20Sopenharmony_ci * Attempt to label a connected socket with NetLabel using the given address. 5388c2ecf20Sopenharmony_ci * Returns zero values on success, negative values on failure. 5398c2ecf20Sopenharmony_ci * 5408c2ecf20Sopenharmony_ci */ 5418c2ecf20Sopenharmony_cistatic int selinux_netlbl_socket_connect_helper(struct sock *sk, 5428c2ecf20Sopenharmony_ci struct sockaddr *addr) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci int rc; 5458c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 5468c2ecf20Sopenharmony_ci struct netlbl_lsm_secattr *secattr; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci /* connected sockets are allowed to disconnect when the address family 5498c2ecf20Sopenharmony_ci * is set to AF_UNSPEC, if that is what is happening we want to reset 5508c2ecf20Sopenharmony_ci * the socket */ 5518c2ecf20Sopenharmony_ci if (addr->sa_family == AF_UNSPEC) { 5528c2ecf20Sopenharmony_ci netlbl_sock_delattr(sk); 5538c2ecf20Sopenharmony_ci sksec->nlbl_state = NLBL_REQSKB; 5548c2ecf20Sopenharmony_ci rc = 0; 5558c2ecf20Sopenharmony_ci return rc; 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci secattr = selinux_netlbl_sock_genattr(sk); 5588c2ecf20Sopenharmony_ci if (secattr == NULL) { 5598c2ecf20Sopenharmony_ci rc = -ENOMEM; 5608c2ecf20Sopenharmony_ci return rc; 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci rc = netlbl_conn_setattr(sk, addr, secattr); 5638c2ecf20Sopenharmony_ci if (rc == 0) 5648c2ecf20Sopenharmony_ci sksec->nlbl_state = NLBL_CONNLABELED; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci return rc; 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci/** 5708c2ecf20Sopenharmony_ci * selinux_netlbl_socket_connect_locked - Label a client-side socket on 5718c2ecf20Sopenharmony_ci * connect 5728c2ecf20Sopenharmony_ci * @sk: the socket to label 5738c2ecf20Sopenharmony_ci * @addr: the destination address 5748c2ecf20Sopenharmony_ci * 5758c2ecf20Sopenharmony_ci * Description: 5768c2ecf20Sopenharmony_ci * Attempt to label a connected socket that already has the socket locked 5778c2ecf20Sopenharmony_ci * with NetLabel using the given address. 5788c2ecf20Sopenharmony_ci * Returns zero values on success, negative values on failure. 5798c2ecf20Sopenharmony_ci * 5808c2ecf20Sopenharmony_ci */ 5818c2ecf20Sopenharmony_ciint selinux_netlbl_socket_connect_locked(struct sock *sk, 5828c2ecf20Sopenharmony_ci struct sockaddr *addr) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (sksec->nlbl_state != NLBL_REQSKB && 5878c2ecf20Sopenharmony_ci sksec->nlbl_state != NLBL_CONNLABELED) 5888c2ecf20Sopenharmony_ci return 0; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci return selinux_netlbl_socket_connect_helper(sk, addr); 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci/** 5948c2ecf20Sopenharmony_ci * selinux_netlbl_socket_connect - Label a client-side socket on connect 5958c2ecf20Sopenharmony_ci * @sk: the socket to label 5968c2ecf20Sopenharmony_ci * @addr: the destination address 5978c2ecf20Sopenharmony_ci * 5988c2ecf20Sopenharmony_ci * Description: 5998c2ecf20Sopenharmony_ci * Attempt to label a connected socket with NetLabel using the given address. 6008c2ecf20Sopenharmony_ci * Returns zero values on success, negative values on failure. 6018c2ecf20Sopenharmony_ci * 6028c2ecf20Sopenharmony_ci */ 6038c2ecf20Sopenharmony_ciint selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci int rc; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci lock_sock(sk); 6088c2ecf20Sopenharmony_ci rc = selinux_netlbl_socket_connect_locked(sk, addr); 6098c2ecf20Sopenharmony_ci release_sock(sk); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci return rc; 6128c2ecf20Sopenharmony_ci} 613