18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * NetLabel Kernel API 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This file defines the kernel API for the NetLabel system. The NetLabel 68c2ecf20Sopenharmony_ci * system manages static and dynamic label mappings for network protocols such 78c2ecf20Sopenharmony_ci * as CIPSO and RIPSO. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Author: Paul Moore <paul@paul-moore.com> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci/* 138c2ecf20Sopenharmony_ci * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/init.h> 178c2ecf20Sopenharmony_ci#include <linux/types.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci#include <linux/audit.h> 208c2ecf20Sopenharmony_ci#include <linux/in.h> 218c2ecf20Sopenharmony_ci#include <linux/in6.h> 228c2ecf20Sopenharmony_ci#include <net/ip.h> 238c2ecf20Sopenharmony_ci#include <net/ipv6.h> 248c2ecf20Sopenharmony_ci#include <net/netlabel.h> 258c2ecf20Sopenharmony_ci#include <net/cipso_ipv4.h> 268c2ecf20Sopenharmony_ci#include <net/calipso.h> 278c2ecf20Sopenharmony_ci#include <asm/bug.h> 288c2ecf20Sopenharmony_ci#include <linux/atomic.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include "netlabel_domainhash.h" 318c2ecf20Sopenharmony_ci#include "netlabel_unlabeled.h" 328c2ecf20Sopenharmony_ci#include "netlabel_cipso_v4.h" 338c2ecf20Sopenharmony_ci#include "netlabel_calipso.h" 348c2ecf20Sopenharmony_ci#include "netlabel_user.h" 358c2ecf20Sopenharmony_ci#include "netlabel_mgmt.h" 368c2ecf20Sopenharmony_ci#include "netlabel_addrlist.h" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* 398c2ecf20Sopenharmony_ci * Configuration Functions 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/** 438c2ecf20Sopenharmony_ci * netlbl_cfg_map_del - Remove a NetLabel/LSM domain mapping 448c2ecf20Sopenharmony_ci * @domain: the domain mapping to remove 458c2ecf20Sopenharmony_ci * @family: address family 468c2ecf20Sopenharmony_ci * @addr: IP address 478c2ecf20Sopenharmony_ci * @mask: IP address mask 488c2ecf20Sopenharmony_ci * @audit_info: NetLabel audit information 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * Description: 518c2ecf20Sopenharmony_ci * Removes a NetLabel/LSM domain mapping. A @domain value of NULL causes the 528c2ecf20Sopenharmony_ci * default domain mapping to be removed. Returns zero on success, negative 538c2ecf20Sopenharmony_ci * values on failure. 548c2ecf20Sopenharmony_ci * 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_ciint netlbl_cfg_map_del(const char *domain, 578c2ecf20Sopenharmony_ci u16 family, 588c2ecf20Sopenharmony_ci const void *addr, 598c2ecf20Sopenharmony_ci const void *mask, 608c2ecf20Sopenharmony_ci struct netlbl_audit *audit_info) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci if (addr == NULL && mask == NULL) { 638c2ecf20Sopenharmony_ci return netlbl_domhsh_remove(domain, family, audit_info); 648c2ecf20Sopenharmony_ci } else if (addr != NULL && mask != NULL) { 658c2ecf20Sopenharmony_ci switch (family) { 668c2ecf20Sopenharmony_ci case AF_INET: 678c2ecf20Sopenharmony_ci return netlbl_domhsh_remove_af4(domain, addr, mask, 688c2ecf20Sopenharmony_ci audit_info); 698c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 708c2ecf20Sopenharmony_ci case AF_INET6: 718c2ecf20Sopenharmony_ci return netlbl_domhsh_remove_af6(domain, addr, mask, 728c2ecf20Sopenharmony_ci audit_info); 738c2ecf20Sopenharmony_ci#endif /* IPv6 */ 748c2ecf20Sopenharmony_ci default: 758c2ecf20Sopenharmony_ci return -EPFNOSUPPORT; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci } else 788c2ecf20Sopenharmony_ci return -EINVAL; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/** 828c2ecf20Sopenharmony_ci * netlbl_cfg_unlbl_map_add - Add a new unlabeled mapping 838c2ecf20Sopenharmony_ci * @domain: the domain mapping to add 848c2ecf20Sopenharmony_ci * @family: address family 858c2ecf20Sopenharmony_ci * @addr: IP address 868c2ecf20Sopenharmony_ci * @mask: IP address mask 878c2ecf20Sopenharmony_ci * @audit_info: NetLabel audit information 888c2ecf20Sopenharmony_ci * 898c2ecf20Sopenharmony_ci * Description: 908c2ecf20Sopenharmony_ci * Adds a new unlabeled NetLabel/LSM domain mapping. A @domain value of NULL 918c2ecf20Sopenharmony_ci * causes a new default domain mapping to be added. Returns zero on success, 928c2ecf20Sopenharmony_ci * negative values on failure. 938c2ecf20Sopenharmony_ci * 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_ciint netlbl_cfg_unlbl_map_add(const char *domain, 968c2ecf20Sopenharmony_ci u16 family, 978c2ecf20Sopenharmony_ci const void *addr, 988c2ecf20Sopenharmony_ci const void *mask, 998c2ecf20Sopenharmony_ci struct netlbl_audit *audit_info) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci int ret_val = -ENOMEM; 1028c2ecf20Sopenharmony_ci struct netlbl_dom_map *entry; 1038c2ecf20Sopenharmony_ci struct netlbl_domaddr_map *addrmap = NULL; 1048c2ecf20Sopenharmony_ci struct netlbl_domaddr4_map *map4 = NULL; 1058c2ecf20Sopenharmony_ci struct netlbl_domaddr6_map *map6 = NULL; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 1088c2ecf20Sopenharmony_ci if (entry == NULL) 1098c2ecf20Sopenharmony_ci return -ENOMEM; 1108c2ecf20Sopenharmony_ci if (domain != NULL) { 1118c2ecf20Sopenharmony_ci entry->domain = kstrdup(domain, GFP_ATOMIC); 1128c2ecf20Sopenharmony_ci if (entry->domain == NULL) 1138c2ecf20Sopenharmony_ci goto cfg_unlbl_map_add_failure; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci entry->family = family; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (addr == NULL && mask == NULL) 1188c2ecf20Sopenharmony_ci entry->def.type = NETLBL_NLTYPE_UNLABELED; 1198c2ecf20Sopenharmony_ci else if (addr != NULL && mask != NULL) { 1208c2ecf20Sopenharmony_ci addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC); 1218c2ecf20Sopenharmony_ci if (addrmap == NULL) 1228c2ecf20Sopenharmony_ci goto cfg_unlbl_map_add_failure; 1238c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&addrmap->list4); 1248c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&addrmap->list6); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci switch (family) { 1278c2ecf20Sopenharmony_ci case AF_INET: { 1288c2ecf20Sopenharmony_ci const struct in_addr *addr4 = addr; 1298c2ecf20Sopenharmony_ci const struct in_addr *mask4 = mask; 1308c2ecf20Sopenharmony_ci map4 = kzalloc(sizeof(*map4), GFP_ATOMIC); 1318c2ecf20Sopenharmony_ci if (map4 == NULL) 1328c2ecf20Sopenharmony_ci goto cfg_unlbl_map_add_failure; 1338c2ecf20Sopenharmony_ci map4->def.type = NETLBL_NLTYPE_UNLABELED; 1348c2ecf20Sopenharmony_ci map4->list.addr = addr4->s_addr & mask4->s_addr; 1358c2ecf20Sopenharmony_ci map4->list.mask = mask4->s_addr; 1368c2ecf20Sopenharmony_ci map4->list.valid = 1; 1378c2ecf20Sopenharmony_ci ret_val = netlbl_af4list_add(&map4->list, 1388c2ecf20Sopenharmony_ci &addrmap->list4); 1398c2ecf20Sopenharmony_ci if (ret_val != 0) 1408c2ecf20Sopenharmony_ci goto cfg_unlbl_map_add_failure; 1418c2ecf20Sopenharmony_ci break; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 1448c2ecf20Sopenharmony_ci case AF_INET6: { 1458c2ecf20Sopenharmony_ci const struct in6_addr *addr6 = addr; 1468c2ecf20Sopenharmony_ci const struct in6_addr *mask6 = mask; 1478c2ecf20Sopenharmony_ci map6 = kzalloc(sizeof(*map6), GFP_ATOMIC); 1488c2ecf20Sopenharmony_ci if (map6 == NULL) 1498c2ecf20Sopenharmony_ci goto cfg_unlbl_map_add_failure; 1508c2ecf20Sopenharmony_ci map6->def.type = NETLBL_NLTYPE_UNLABELED; 1518c2ecf20Sopenharmony_ci map6->list.addr = *addr6; 1528c2ecf20Sopenharmony_ci map6->list.addr.s6_addr32[0] &= mask6->s6_addr32[0]; 1538c2ecf20Sopenharmony_ci map6->list.addr.s6_addr32[1] &= mask6->s6_addr32[1]; 1548c2ecf20Sopenharmony_ci map6->list.addr.s6_addr32[2] &= mask6->s6_addr32[2]; 1558c2ecf20Sopenharmony_ci map6->list.addr.s6_addr32[3] &= mask6->s6_addr32[3]; 1568c2ecf20Sopenharmony_ci map6->list.mask = *mask6; 1578c2ecf20Sopenharmony_ci map6->list.valid = 1; 1588c2ecf20Sopenharmony_ci ret_val = netlbl_af6list_add(&map6->list, 1598c2ecf20Sopenharmony_ci &addrmap->list6); 1608c2ecf20Sopenharmony_ci if (ret_val != 0) 1618c2ecf20Sopenharmony_ci goto cfg_unlbl_map_add_failure; 1628c2ecf20Sopenharmony_ci break; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci#endif /* IPv6 */ 1658c2ecf20Sopenharmony_ci default: 1668c2ecf20Sopenharmony_ci goto cfg_unlbl_map_add_failure; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci entry->def.addrsel = addrmap; 1708c2ecf20Sopenharmony_ci entry->def.type = NETLBL_NLTYPE_ADDRSELECT; 1718c2ecf20Sopenharmony_ci } else { 1728c2ecf20Sopenharmony_ci ret_val = -EINVAL; 1738c2ecf20Sopenharmony_ci goto cfg_unlbl_map_add_failure; 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci ret_val = netlbl_domhsh_add(entry, audit_info); 1778c2ecf20Sopenharmony_ci if (ret_val != 0) 1788c2ecf20Sopenharmony_ci goto cfg_unlbl_map_add_failure; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci return 0; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cicfg_unlbl_map_add_failure: 1838c2ecf20Sopenharmony_ci kfree(entry->domain); 1848c2ecf20Sopenharmony_ci kfree(entry); 1858c2ecf20Sopenharmony_ci kfree(addrmap); 1868c2ecf20Sopenharmony_ci kfree(map4); 1878c2ecf20Sopenharmony_ci kfree(map6); 1888c2ecf20Sopenharmony_ci return ret_val; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/** 1938c2ecf20Sopenharmony_ci * netlbl_cfg_unlbl_static_add - Adds a new static label 1948c2ecf20Sopenharmony_ci * @net: network namespace 1958c2ecf20Sopenharmony_ci * @dev_name: interface name 1968c2ecf20Sopenharmony_ci * @addr: IP address in network byte order (struct in[6]_addr) 1978c2ecf20Sopenharmony_ci * @mask: address mask in network byte order (struct in[6]_addr) 1988c2ecf20Sopenharmony_ci * @family: address family 1998c2ecf20Sopenharmony_ci * @secid: LSM secid value for the entry 2008c2ecf20Sopenharmony_ci * @audit_info: NetLabel audit information 2018c2ecf20Sopenharmony_ci * 2028c2ecf20Sopenharmony_ci * Description: 2038c2ecf20Sopenharmony_ci * Adds a new NetLabel static label to be used when protocol provided labels 2048c2ecf20Sopenharmony_ci * are not present on incoming traffic. If @dev_name is NULL then the default 2058c2ecf20Sopenharmony_ci * interface will be used. Returns zero on success, negative values on failure. 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci */ 2088c2ecf20Sopenharmony_ciint netlbl_cfg_unlbl_static_add(struct net *net, 2098c2ecf20Sopenharmony_ci const char *dev_name, 2108c2ecf20Sopenharmony_ci const void *addr, 2118c2ecf20Sopenharmony_ci const void *mask, 2128c2ecf20Sopenharmony_ci u16 family, 2138c2ecf20Sopenharmony_ci u32 secid, 2148c2ecf20Sopenharmony_ci struct netlbl_audit *audit_info) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci u32 addr_len; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci switch (family) { 2198c2ecf20Sopenharmony_ci case AF_INET: 2208c2ecf20Sopenharmony_ci addr_len = sizeof(struct in_addr); 2218c2ecf20Sopenharmony_ci break; 2228c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 2238c2ecf20Sopenharmony_ci case AF_INET6: 2248c2ecf20Sopenharmony_ci addr_len = sizeof(struct in6_addr); 2258c2ecf20Sopenharmony_ci break; 2268c2ecf20Sopenharmony_ci#endif /* IPv6 */ 2278c2ecf20Sopenharmony_ci default: 2288c2ecf20Sopenharmony_ci return -EPFNOSUPPORT; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci return netlbl_unlhsh_add(net, 2328c2ecf20Sopenharmony_ci dev_name, addr, mask, addr_len, 2338c2ecf20Sopenharmony_ci secid, audit_info); 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci/** 2378c2ecf20Sopenharmony_ci * netlbl_cfg_unlbl_static_del - Removes an existing static label 2388c2ecf20Sopenharmony_ci * @net: network namespace 2398c2ecf20Sopenharmony_ci * @dev_name: interface name 2408c2ecf20Sopenharmony_ci * @addr: IP address in network byte order (struct in[6]_addr) 2418c2ecf20Sopenharmony_ci * @mask: address mask in network byte order (struct in[6]_addr) 2428c2ecf20Sopenharmony_ci * @family: address family 2438c2ecf20Sopenharmony_ci * @audit_info: NetLabel audit information 2448c2ecf20Sopenharmony_ci * 2458c2ecf20Sopenharmony_ci * Description: 2468c2ecf20Sopenharmony_ci * Removes an existing NetLabel static label used when protocol provided labels 2478c2ecf20Sopenharmony_ci * are not present on incoming traffic. If @dev_name is NULL then the default 2488c2ecf20Sopenharmony_ci * interface will be used. Returns zero on success, negative values on failure. 2498c2ecf20Sopenharmony_ci * 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_ciint netlbl_cfg_unlbl_static_del(struct net *net, 2528c2ecf20Sopenharmony_ci const char *dev_name, 2538c2ecf20Sopenharmony_ci const void *addr, 2548c2ecf20Sopenharmony_ci const void *mask, 2558c2ecf20Sopenharmony_ci u16 family, 2568c2ecf20Sopenharmony_ci struct netlbl_audit *audit_info) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci u32 addr_len; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci switch (family) { 2618c2ecf20Sopenharmony_ci case AF_INET: 2628c2ecf20Sopenharmony_ci addr_len = sizeof(struct in_addr); 2638c2ecf20Sopenharmony_ci break; 2648c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 2658c2ecf20Sopenharmony_ci case AF_INET6: 2668c2ecf20Sopenharmony_ci addr_len = sizeof(struct in6_addr); 2678c2ecf20Sopenharmony_ci break; 2688c2ecf20Sopenharmony_ci#endif /* IPv6 */ 2698c2ecf20Sopenharmony_ci default: 2708c2ecf20Sopenharmony_ci return -EPFNOSUPPORT; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return netlbl_unlhsh_remove(net, 2748c2ecf20Sopenharmony_ci dev_name, addr, mask, addr_len, 2758c2ecf20Sopenharmony_ci audit_info); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci/** 2798c2ecf20Sopenharmony_ci * netlbl_cfg_cipsov4_add - Add a new CIPSOv4 DOI definition 2808c2ecf20Sopenharmony_ci * @doi_def: CIPSO DOI definition 2818c2ecf20Sopenharmony_ci * @audit_info: NetLabel audit information 2828c2ecf20Sopenharmony_ci * 2838c2ecf20Sopenharmony_ci * Description: 2848c2ecf20Sopenharmony_ci * Add a new CIPSO DOI definition as defined by @doi_def. Returns zero on 2858c2ecf20Sopenharmony_ci * success and negative values on failure. 2868c2ecf20Sopenharmony_ci * 2878c2ecf20Sopenharmony_ci */ 2888c2ecf20Sopenharmony_ciint netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def, 2898c2ecf20Sopenharmony_ci struct netlbl_audit *audit_info) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci return cipso_v4_doi_add(doi_def, audit_info); 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci/** 2958c2ecf20Sopenharmony_ci * netlbl_cfg_cipsov4_del - Remove an existing CIPSOv4 DOI definition 2968c2ecf20Sopenharmony_ci * @doi: CIPSO DOI 2978c2ecf20Sopenharmony_ci * @audit_info: NetLabel audit information 2988c2ecf20Sopenharmony_ci * 2998c2ecf20Sopenharmony_ci * Description: 3008c2ecf20Sopenharmony_ci * Remove an existing CIPSO DOI definition matching @doi. Returns zero on 3018c2ecf20Sopenharmony_ci * success and negative values on failure. 3028c2ecf20Sopenharmony_ci * 3038c2ecf20Sopenharmony_ci */ 3048c2ecf20Sopenharmony_civoid netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci cipso_v4_doi_remove(doi, audit_info); 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci/** 3108c2ecf20Sopenharmony_ci * netlbl_cfg_cipsov4_map_add - Add a new CIPSOv4 DOI mapping 3118c2ecf20Sopenharmony_ci * @doi: the CIPSO DOI 3128c2ecf20Sopenharmony_ci * @domain: the domain mapping to add 3138c2ecf20Sopenharmony_ci * @addr: IP address 3148c2ecf20Sopenharmony_ci * @mask: IP address mask 3158c2ecf20Sopenharmony_ci * @audit_info: NetLabel audit information 3168c2ecf20Sopenharmony_ci * 3178c2ecf20Sopenharmony_ci * Description: 3188c2ecf20Sopenharmony_ci * Add a new NetLabel/LSM domain mapping for the given CIPSO DOI to the NetLabel 3198c2ecf20Sopenharmony_ci * subsystem. A @domain value of NULL adds a new default domain mapping. 3208c2ecf20Sopenharmony_ci * Returns zero on success, negative values on failure. 3218c2ecf20Sopenharmony_ci * 3228c2ecf20Sopenharmony_ci */ 3238c2ecf20Sopenharmony_ciint netlbl_cfg_cipsov4_map_add(u32 doi, 3248c2ecf20Sopenharmony_ci const char *domain, 3258c2ecf20Sopenharmony_ci const struct in_addr *addr, 3268c2ecf20Sopenharmony_ci const struct in_addr *mask, 3278c2ecf20Sopenharmony_ci struct netlbl_audit *audit_info) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci int ret_val = -ENOMEM; 3308c2ecf20Sopenharmony_ci struct cipso_v4_doi *doi_def; 3318c2ecf20Sopenharmony_ci struct netlbl_dom_map *entry; 3328c2ecf20Sopenharmony_ci struct netlbl_domaddr_map *addrmap = NULL; 3338c2ecf20Sopenharmony_ci struct netlbl_domaddr4_map *addrinfo = NULL; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci doi_def = cipso_v4_doi_getdef(doi); 3368c2ecf20Sopenharmony_ci if (doi_def == NULL) 3378c2ecf20Sopenharmony_ci return -ENOENT; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 3408c2ecf20Sopenharmony_ci if (entry == NULL) 3418c2ecf20Sopenharmony_ci goto out_entry; 3428c2ecf20Sopenharmony_ci entry->family = AF_INET; 3438c2ecf20Sopenharmony_ci if (domain != NULL) { 3448c2ecf20Sopenharmony_ci entry->domain = kstrdup(domain, GFP_ATOMIC); 3458c2ecf20Sopenharmony_ci if (entry->domain == NULL) 3468c2ecf20Sopenharmony_ci goto out_domain; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (addr == NULL && mask == NULL) { 3508c2ecf20Sopenharmony_ci entry->def.cipso = doi_def; 3518c2ecf20Sopenharmony_ci entry->def.type = NETLBL_NLTYPE_CIPSOV4; 3528c2ecf20Sopenharmony_ci } else if (addr != NULL && mask != NULL) { 3538c2ecf20Sopenharmony_ci addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC); 3548c2ecf20Sopenharmony_ci if (addrmap == NULL) 3558c2ecf20Sopenharmony_ci goto out_addrmap; 3568c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&addrmap->list4); 3578c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&addrmap->list6); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci addrinfo = kzalloc(sizeof(*addrinfo), GFP_ATOMIC); 3608c2ecf20Sopenharmony_ci if (addrinfo == NULL) 3618c2ecf20Sopenharmony_ci goto out_addrinfo; 3628c2ecf20Sopenharmony_ci addrinfo->def.cipso = doi_def; 3638c2ecf20Sopenharmony_ci addrinfo->def.type = NETLBL_NLTYPE_CIPSOV4; 3648c2ecf20Sopenharmony_ci addrinfo->list.addr = addr->s_addr & mask->s_addr; 3658c2ecf20Sopenharmony_ci addrinfo->list.mask = mask->s_addr; 3668c2ecf20Sopenharmony_ci addrinfo->list.valid = 1; 3678c2ecf20Sopenharmony_ci ret_val = netlbl_af4list_add(&addrinfo->list, &addrmap->list4); 3688c2ecf20Sopenharmony_ci if (ret_val != 0) 3698c2ecf20Sopenharmony_ci goto cfg_cipsov4_map_add_failure; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci entry->def.addrsel = addrmap; 3728c2ecf20Sopenharmony_ci entry->def.type = NETLBL_NLTYPE_ADDRSELECT; 3738c2ecf20Sopenharmony_ci } else { 3748c2ecf20Sopenharmony_ci ret_val = -EINVAL; 3758c2ecf20Sopenharmony_ci goto out_addrmap; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci ret_val = netlbl_domhsh_add(entry, audit_info); 3798c2ecf20Sopenharmony_ci if (ret_val != 0) 3808c2ecf20Sopenharmony_ci goto cfg_cipsov4_map_add_failure; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci return 0; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cicfg_cipsov4_map_add_failure: 3858c2ecf20Sopenharmony_ci kfree(addrinfo); 3868c2ecf20Sopenharmony_ciout_addrinfo: 3878c2ecf20Sopenharmony_ci kfree(addrmap); 3888c2ecf20Sopenharmony_ciout_addrmap: 3898c2ecf20Sopenharmony_ci kfree(entry->domain); 3908c2ecf20Sopenharmony_ciout_domain: 3918c2ecf20Sopenharmony_ci kfree(entry); 3928c2ecf20Sopenharmony_ciout_entry: 3938c2ecf20Sopenharmony_ci cipso_v4_doi_putdef(doi_def); 3948c2ecf20Sopenharmony_ci return ret_val; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci/** 3988c2ecf20Sopenharmony_ci * netlbl_cfg_calipso_add - Add a new CALIPSO DOI definition 3998c2ecf20Sopenharmony_ci * @doi_def: CALIPSO DOI definition 4008c2ecf20Sopenharmony_ci * @audit_info: NetLabel audit information 4018c2ecf20Sopenharmony_ci * 4028c2ecf20Sopenharmony_ci * Description: 4038c2ecf20Sopenharmony_ci * Add a new CALIPSO DOI definition as defined by @doi_def. Returns zero on 4048c2ecf20Sopenharmony_ci * success and negative values on failure. 4058c2ecf20Sopenharmony_ci * 4068c2ecf20Sopenharmony_ci */ 4078c2ecf20Sopenharmony_ciint netlbl_cfg_calipso_add(struct calipso_doi *doi_def, 4088c2ecf20Sopenharmony_ci struct netlbl_audit *audit_info) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 4118c2ecf20Sopenharmony_ci return calipso_doi_add(doi_def, audit_info); 4128c2ecf20Sopenharmony_ci#else /* IPv6 */ 4138c2ecf20Sopenharmony_ci return -ENOSYS; 4148c2ecf20Sopenharmony_ci#endif /* IPv6 */ 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci/** 4188c2ecf20Sopenharmony_ci * netlbl_cfg_calipso_del - Remove an existing CALIPSO DOI definition 4198c2ecf20Sopenharmony_ci * @doi: CALIPSO DOI 4208c2ecf20Sopenharmony_ci * @audit_info: NetLabel audit information 4218c2ecf20Sopenharmony_ci * 4228c2ecf20Sopenharmony_ci * Description: 4238c2ecf20Sopenharmony_ci * Remove an existing CALIPSO DOI definition matching @doi. Returns zero on 4248c2ecf20Sopenharmony_ci * success and negative values on failure. 4258c2ecf20Sopenharmony_ci * 4268c2ecf20Sopenharmony_ci */ 4278c2ecf20Sopenharmony_civoid netlbl_cfg_calipso_del(u32 doi, struct netlbl_audit *audit_info) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 4308c2ecf20Sopenharmony_ci calipso_doi_remove(doi, audit_info); 4318c2ecf20Sopenharmony_ci#endif /* IPv6 */ 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci/** 4358c2ecf20Sopenharmony_ci * netlbl_cfg_calipso_map_add - Add a new CALIPSO DOI mapping 4368c2ecf20Sopenharmony_ci * @doi: the CALIPSO DOI 4378c2ecf20Sopenharmony_ci * @domain: the domain mapping to add 4388c2ecf20Sopenharmony_ci * @addr: IP address 4398c2ecf20Sopenharmony_ci * @mask: IP address mask 4408c2ecf20Sopenharmony_ci * @audit_info: NetLabel audit information 4418c2ecf20Sopenharmony_ci * 4428c2ecf20Sopenharmony_ci * Description: 4438c2ecf20Sopenharmony_ci * Add a new NetLabel/LSM domain mapping for the given CALIPSO DOI to the 4448c2ecf20Sopenharmony_ci * NetLabel subsystem. A @domain value of NULL adds a new default domain 4458c2ecf20Sopenharmony_ci * mapping. Returns zero on success, negative values on failure. 4468c2ecf20Sopenharmony_ci * 4478c2ecf20Sopenharmony_ci */ 4488c2ecf20Sopenharmony_ciint netlbl_cfg_calipso_map_add(u32 doi, 4498c2ecf20Sopenharmony_ci const char *domain, 4508c2ecf20Sopenharmony_ci const struct in6_addr *addr, 4518c2ecf20Sopenharmony_ci const struct in6_addr *mask, 4528c2ecf20Sopenharmony_ci struct netlbl_audit *audit_info) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 4558c2ecf20Sopenharmony_ci int ret_val = -ENOMEM; 4568c2ecf20Sopenharmony_ci struct calipso_doi *doi_def; 4578c2ecf20Sopenharmony_ci struct netlbl_dom_map *entry; 4588c2ecf20Sopenharmony_ci struct netlbl_domaddr_map *addrmap = NULL; 4598c2ecf20Sopenharmony_ci struct netlbl_domaddr6_map *addrinfo = NULL; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci doi_def = calipso_doi_getdef(doi); 4628c2ecf20Sopenharmony_ci if (doi_def == NULL) 4638c2ecf20Sopenharmony_ci return -ENOENT; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 4668c2ecf20Sopenharmony_ci if (entry == NULL) 4678c2ecf20Sopenharmony_ci goto out_entry; 4688c2ecf20Sopenharmony_ci entry->family = AF_INET6; 4698c2ecf20Sopenharmony_ci if (domain != NULL) { 4708c2ecf20Sopenharmony_ci entry->domain = kstrdup(domain, GFP_ATOMIC); 4718c2ecf20Sopenharmony_ci if (entry->domain == NULL) 4728c2ecf20Sopenharmony_ci goto out_domain; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci if (addr == NULL && mask == NULL) { 4768c2ecf20Sopenharmony_ci entry->def.calipso = doi_def; 4778c2ecf20Sopenharmony_ci entry->def.type = NETLBL_NLTYPE_CALIPSO; 4788c2ecf20Sopenharmony_ci } else if (addr != NULL && mask != NULL) { 4798c2ecf20Sopenharmony_ci addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC); 4808c2ecf20Sopenharmony_ci if (addrmap == NULL) 4818c2ecf20Sopenharmony_ci goto out_addrmap; 4828c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&addrmap->list4); 4838c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&addrmap->list6); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci addrinfo = kzalloc(sizeof(*addrinfo), GFP_ATOMIC); 4868c2ecf20Sopenharmony_ci if (addrinfo == NULL) 4878c2ecf20Sopenharmony_ci goto out_addrinfo; 4888c2ecf20Sopenharmony_ci addrinfo->def.calipso = doi_def; 4898c2ecf20Sopenharmony_ci addrinfo->def.type = NETLBL_NLTYPE_CALIPSO; 4908c2ecf20Sopenharmony_ci addrinfo->list.addr = *addr; 4918c2ecf20Sopenharmony_ci addrinfo->list.addr.s6_addr32[0] &= mask->s6_addr32[0]; 4928c2ecf20Sopenharmony_ci addrinfo->list.addr.s6_addr32[1] &= mask->s6_addr32[1]; 4938c2ecf20Sopenharmony_ci addrinfo->list.addr.s6_addr32[2] &= mask->s6_addr32[2]; 4948c2ecf20Sopenharmony_ci addrinfo->list.addr.s6_addr32[3] &= mask->s6_addr32[3]; 4958c2ecf20Sopenharmony_ci addrinfo->list.mask = *mask; 4968c2ecf20Sopenharmony_ci addrinfo->list.valid = 1; 4978c2ecf20Sopenharmony_ci ret_val = netlbl_af6list_add(&addrinfo->list, &addrmap->list6); 4988c2ecf20Sopenharmony_ci if (ret_val != 0) 4998c2ecf20Sopenharmony_ci goto cfg_calipso_map_add_failure; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci entry->def.addrsel = addrmap; 5028c2ecf20Sopenharmony_ci entry->def.type = NETLBL_NLTYPE_ADDRSELECT; 5038c2ecf20Sopenharmony_ci } else { 5048c2ecf20Sopenharmony_ci ret_val = -EINVAL; 5058c2ecf20Sopenharmony_ci goto out_addrmap; 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci ret_val = netlbl_domhsh_add(entry, audit_info); 5098c2ecf20Sopenharmony_ci if (ret_val != 0) 5108c2ecf20Sopenharmony_ci goto cfg_calipso_map_add_failure; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci return 0; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cicfg_calipso_map_add_failure: 5158c2ecf20Sopenharmony_ci kfree(addrinfo); 5168c2ecf20Sopenharmony_ciout_addrinfo: 5178c2ecf20Sopenharmony_ci kfree(addrmap); 5188c2ecf20Sopenharmony_ciout_addrmap: 5198c2ecf20Sopenharmony_ci kfree(entry->domain); 5208c2ecf20Sopenharmony_ciout_domain: 5218c2ecf20Sopenharmony_ci kfree(entry); 5228c2ecf20Sopenharmony_ciout_entry: 5238c2ecf20Sopenharmony_ci calipso_doi_putdef(doi_def); 5248c2ecf20Sopenharmony_ci return ret_val; 5258c2ecf20Sopenharmony_ci#else /* IPv6 */ 5268c2ecf20Sopenharmony_ci return -ENOSYS; 5278c2ecf20Sopenharmony_ci#endif /* IPv6 */ 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci/* 5318c2ecf20Sopenharmony_ci * Security Attribute Functions 5328c2ecf20Sopenharmony_ci */ 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci#define _CM_F_NONE 0x00000000 5358c2ecf20Sopenharmony_ci#define _CM_F_ALLOC 0x00000001 5368c2ecf20Sopenharmony_ci#define _CM_F_WALK 0x00000002 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci/** 5398c2ecf20Sopenharmony_ci * _netlbl_catmap_getnode - Get a individual node from a catmap 5408c2ecf20Sopenharmony_ci * @catmap: pointer to the category bitmap 5418c2ecf20Sopenharmony_ci * @offset: the requested offset 5428c2ecf20Sopenharmony_ci * @cm_flags: catmap flags, see _CM_F_* 5438c2ecf20Sopenharmony_ci * @gfp_flags: memory allocation flags 5448c2ecf20Sopenharmony_ci * 5458c2ecf20Sopenharmony_ci * Description: 5468c2ecf20Sopenharmony_ci * Iterate through the catmap looking for the node associated with @offset. 5478c2ecf20Sopenharmony_ci * If the _CM_F_ALLOC flag is set in @cm_flags and there is no associated node, 5488c2ecf20Sopenharmony_ci * one will be created and inserted into the catmap. If the _CM_F_WALK flag is 5498c2ecf20Sopenharmony_ci * set in @cm_flags and there is no associated node, the next highest node will 5508c2ecf20Sopenharmony_ci * be returned. Returns a pointer to the node on success, NULL on failure. 5518c2ecf20Sopenharmony_ci * 5528c2ecf20Sopenharmony_ci */ 5538c2ecf20Sopenharmony_cistatic struct netlbl_lsm_catmap *_netlbl_catmap_getnode( 5548c2ecf20Sopenharmony_ci struct netlbl_lsm_catmap **catmap, 5558c2ecf20Sopenharmony_ci u32 offset, 5568c2ecf20Sopenharmony_ci unsigned int cm_flags, 5578c2ecf20Sopenharmony_ci gfp_t gfp_flags) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci struct netlbl_lsm_catmap *iter = *catmap; 5608c2ecf20Sopenharmony_ci struct netlbl_lsm_catmap *prev = NULL; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci if (iter == NULL) 5638c2ecf20Sopenharmony_ci goto catmap_getnode_alloc; 5648c2ecf20Sopenharmony_ci if (offset < iter->startbit) 5658c2ecf20Sopenharmony_ci goto catmap_getnode_walk; 5668c2ecf20Sopenharmony_ci while (iter && offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) { 5678c2ecf20Sopenharmony_ci prev = iter; 5688c2ecf20Sopenharmony_ci iter = iter->next; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci if (iter == NULL || offset < iter->startbit) 5718c2ecf20Sopenharmony_ci goto catmap_getnode_walk; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci return iter; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cicatmap_getnode_walk: 5768c2ecf20Sopenharmony_ci if (cm_flags & _CM_F_WALK) 5778c2ecf20Sopenharmony_ci return iter; 5788c2ecf20Sopenharmony_cicatmap_getnode_alloc: 5798c2ecf20Sopenharmony_ci if (!(cm_flags & _CM_F_ALLOC)) 5808c2ecf20Sopenharmony_ci return NULL; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci iter = netlbl_catmap_alloc(gfp_flags); 5838c2ecf20Sopenharmony_ci if (iter == NULL) 5848c2ecf20Sopenharmony_ci return NULL; 5858c2ecf20Sopenharmony_ci iter->startbit = offset & ~(NETLBL_CATMAP_SIZE - 1); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if (prev == NULL) { 5888c2ecf20Sopenharmony_ci iter->next = *catmap; 5898c2ecf20Sopenharmony_ci *catmap = iter; 5908c2ecf20Sopenharmony_ci } else { 5918c2ecf20Sopenharmony_ci iter->next = prev->next; 5928c2ecf20Sopenharmony_ci prev->next = iter; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci return iter; 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci/** 5998c2ecf20Sopenharmony_ci * netlbl_catmap_walk - Walk a LSM secattr catmap looking for a bit 6008c2ecf20Sopenharmony_ci * @catmap: the category bitmap 6018c2ecf20Sopenharmony_ci * @offset: the offset to start searching at, in bits 6028c2ecf20Sopenharmony_ci * 6038c2ecf20Sopenharmony_ci * Description: 6048c2ecf20Sopenharmony_ci * This function walks a LSM secattr category bitmap starting at @offset and 6058c2ecf20Sopenharmony_ci * returns the spot of the first set bit or -ENOENT if no bits are set. 6068c2ecf20Sopenharmony_ci * 6078c2ecf20Sopenharmony_ci */ 6088c2ecf20Sopenharmony_ciint netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap, u32 offset) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci struct netlbl_lsm_catmap *iter; 6118c2ecf20Sopenharmony_ci u32 idx; 6128c2ecf20Sopenharmony_ci u32 bit; 6138c2ecf20Sopenharmony_ci NETLBL_CATMAP_MAPTYPE bitmap; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci iter = _netlbl_catmap_getnode(&catmap, offset, _CM_F_WALK, 0); 6168c2ecf20Sopenharmony_ci if (iter == NULL) 6178c2ecf20Sopenharmony_ci return -ENOENT; 6188c2ecf20Sopenharmony_ci if (offset > iter->startbit) { 6198c2ecf20Sopenharmony_ci offset -= iter->startbit; 6208c2ecf20Sopenharmony_ci idx = offset / NETLBL_CATMAP_MAPSIZE; 6218c2ecf20Sopenharmony_ci bit = offset % NETLBL_CATMAP_MAPSIZE; 6228c2ecf20Sopenharmony_ci } else { 6238c2ecf20Sopenharmony_ci idx = 0; 6248c2ecf20Sopenharmony_ci bit = 0; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci bitmap = iter->bitmap[idx] >> bit; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci for (;;) { 6298c2ecf20Sopenharmony_ci if (bitmap != 0) { 6308c2ecf20Sopenharmony_ci while ((bitmap & NETLBL_CATMAP_BIT) == 0) { 6318c2ecf20Sopenharmony_ci bitmap >>= 1; 6328c2ecf20Sopenharmony_ci bit++; 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci return iter->startbit + 6358c2ecf20Sopenharmony_ci (NETLBL_CATMAP_MAPSIZE * idx) + bit; 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci if (++idx >= NETLBL_CATMAP_MAPCNT) { 6388c2ecf20Sopenharmony_ci if (iter->next != NULL) { 6398c2ecf20Sopenharmony_ci iter = iter->next; 6408c2ecf20Sopenharmony_ci idx = 0; 6418c2ecf20Sopenharmony_ci } else 6428c2ecf20Sopenharmony_ci return -ENOENT; 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci bitmap = iter->bitmap[idx]; 6458c2ecf20Sopenharmony_ci bit = 0; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci return -ENOENT; 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(netlbl_catmap_walk); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci/** 6538c2ecf20Sopenharmony_ci * netlbl_catmap_walkrng - Find the end of a string of set bits 6548c2ecf20Sopenharmony_ci * @catmap: the category bitmap 6558c2ecf20Sopenharmony_ci * @offset: the offset to start searching at, in bits 6568c2ecf20Sopenharmony_ci * 6578c2ecf20Sopenharmony_ci * Description: 6588c2ecf20Sopenharmony_ci * This function walks a LSM secattr category bitmap starting at @offset and 6598c2ecf20Sopenharmony_ci * returns the spot of the first cleared bit or -ENOENT if the offset is past 6608c2ecf20Sopenharmony_ci * the end of the bitmap. 6618c2ecf20Sopenharmony_ci * 6628c2ecf20Sopenharmony_ci */ 6638c2ecf20Sopenharmony_ciint netlbl_catmap_walkrng(struct netlbl_lsm_catmap *catmap, u32 offset) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci struct netlbl_lsm_catmap *iter; 6668c2ecf20Sopenharmony_ci struct netlbl_lsm_catmap *prev = NULL; 6678c2ecf20Sopenharmony_ci u32 idx; 6688c2ecf20Sopenharmony_ci u32 bit; 6698c2ecf20Sopenharmony_ci NETLBL_CATMAP_MAPTYPE bitmask; 6708c2ecf20Sopenharmony_ci NETLBL_CATMAP_MAPTYPE bitmap; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci iter = _netlbl_catmap_getnode(&catmap, offset, _CM_F_WALK, 0); 6738c2ecf20Sopenharmony_ci if (iter == NULL) 6748c2ecf20Sopenharmony_ci return -ENOENT; 6758c2ecf20Sopenharmony_ci if (offset > iter->startbit) { 6768c2ecf20Sopenharmony_ci offset -= iter->startbit; 6778c2ecf20Sopenharmony_ci idx = offset / NETLBL_CATMAP_MAPSIZE; 6788c2ecf20Sopenharmony_ci bit = offset % NETLBL_CATMAP_MAPSIZE; 6798c2ecf20Sopenharmony_ci } else { 6808c2ecf20Sopenharmony_ci idx = 0; 6818c2ecf20Sopenharmony_ci bit = 0; 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci bitmask = NETLBL_CATMAP_BIT << bit; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci for (;;) { 6868c2ecf20Sopenharmony_ci bitmap = iter->bitmap[idx]; 6878c2ecf20Sopenharmony_ci while (bitmask != 0 && (bitmap & bitmask) != 0) { 6888c2ecf20Sopenharmony_ci bitmask <<= 1; 6898c2ecf20Sopenharmony_ci bit++; 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci if (prev && idx == 0 && bit == 0) 6938c2ecf20Sopenharmony_ci return prev->startbit + NETLBL_CATMAP_SIZE - 1; 6948c2ecf20Sopenharmony_ci else if (bitmask != 0) 6958c2ecf20Sopenharmony_ci return iter->startbit + 6968c2ecf20Sopenharmony_ci (NETLBL_CATMAP_MAPSIZE * idx) + bit - 1; 6978c2ecf20Sopenharmony_ci else if (++idx >= NETLBL_CATMAP_MAPCNT) { 6988c2ecf20Sopenharmony_ci if (iter->next == NULL) 6998c2ecf20Sopenharmony_ci return iter->startbit + NETLBL_CATMAP_SIZE - 1; 7008c2ecf20Sopenharmony_ci prev = iter; 7018c2ecf20Sopenharmony_ci iter = iter->next; 7028c2ecf20Sopenharmony_ci idx = 0; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci bitmask = NETLBL_CATMAP_BIT; 7058c2ecf20Sopenharmony_ci bit = 0; 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci return -ENOENT; 7098c2ecf20Sopenharmony_ci} 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci/** 7128c2ecf20Sopenharmony_ci * netlbl_catmap_getlong - Export an unsigned long bitmap 7138c2ecf20Sopenharmony_ci * @catmap: pointer to the category bitmap 7148c2ecf20Sopenharmony_ci * @offset: pointer to the requested offset 7158c2ecf20Sopenharmony_ci * @bitmap: the exported bitmap 7168c2ecf20Sopenharmony_ci * 7178c2ecf20Sopenharmony_ci * Description: 7188c2ecf20Sopenharmony_ci * Export a bitmap with an offset greater than or equal to @offset and return 7198c2ecf20Sopenharmony_ci * it in @bitmap. The @offset must be aligned to an unsigned long and will be 7208c2ecf20Sopenharmony_ci * updated on return if different from what was requested; if the catmap is 7218c2ecf20Sopenharmony_ci * empty at the requested offset and beyond, the @offset is set to (u32)-1. 7228c2ecf20Sopenharmony_ci * Returns zero on sucess, negative values on failure. 7238c2ecf20Sopenharmony_ci * 7248c2ecf20Sopenharmony_ci */ 7258c2ecf20Sopenharmony_ciint netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap, 7268c2ecf20Sopenharmony_ci u32 *offset, 7278c2ecf20Sopenharmony_ci unsigned long *bitmap) 7288c2ecf20Sopenharmony_ci{ 7298c2ecf20Sopenharmony_ci struct netlbl_lsm_catmap *iter; 7308c2ecf20Sopenharmony_ci u32 off = *offset; 7318c2ecf20Sopenharmony_ci u32 idx; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci /* only allow aligned offsets */ 7348c2ecf20Sopenharmony_ci if ((off & (BITS_PER_LONG - 1)) != 0) 7358c2ecf20Sopenharmony_ci return -EINVAL; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci /* a null catmap is equivalent to an empty one */ 7388c2ecf20Sopenharmony_ci if (!catmap) { 7398c2ecf20Sopenharmony_ci *offset = (u32)-1; 7408c2ecf20Sopenharmony_ci return 0; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci if (off < catmap->startbit) { 7448c2ecf20Sopenharmony_ci off = catmap->startbit; 7458c2ecf20Sopenharmony_ci *offset = off; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci iter = _netlbl_catmap_getnode(&catmap, off, _CM_F_WALK, 0); 7488c2ecf20Sopenharmony_ci if (iter == NULL) { 7498c2ecf20Sopenharmony_ci *offset = (u32)-1; 7508c2ecf20Sopenharmony_ci return 0; 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci if (off < iter->startbit) { 7548c2ecf20Sopenharmony_ci *offset = iter->startbit; 7558c2ecf20Sopenharmony_ci off = 0; 7568c2ecf20Sopenharmony_ci } else 7578c2ecf20Sopenharmony_ci off -= iter->startbit; 7588c2ecf20Sopenharmony_ci idx = off / NETLBL_CATMAP_MAPSIZE; 7598c2ecf20Sopenharmony_ci *bitmap = iter->bitmap[idx] >> (off % NETLBL_CATMAP_MAPSIZE); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci return 0; 7628c2ecf20Sopenharmony_ci} 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci/** 7658c2ecf20Sopenharmony_ci * netlbl_catmap_setbit - Set a bit in a LSM secattr catmap 7668c2ecf20Sopenharmony_ci * @catmap: pointer to the category bitmap 7678c2ecf20Sopenharmony_ci * @bit: the bit to set 7688c2ecf20Sopenharmony_ci * @flags: memory allocation flags 7698c2ecf20Sopenharmony_ci * 7708c2ecf20Sopenharmony_ci * Description: 7718c2ecf20Sopenharmony_ci * Set the bit specified by @bit in @catmap. Returns zero on success, 7728c2ecf20Sopenharmony_ci * negative values on failure. 7738c2ecf20Sopenharmony_ci * 7748c2ecf20Sopenharmony_ci */ 7758c2ecf20Sopenharmony_ciint netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap, 7768c2ecf20Sopenharmony_ci u32 bit, 7778c2ecf20Sopenharmony_ci gfp_t flags) 7788c2ecf20Sopenharmony_ci{ 7798c2ecf20Sopenharmony_ci struct netlbl_lsm_catmap *iter; 7808c2ecf20Sopenharmony_ci u32 idx; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci iter = _netlbl_catmap_getnode(catmap, bit, _CM_F_ALLOC, flags); 7838c2ecf20Sopenharmony_ci if (iter == NULL) 7848c2ecf20Sopenharmony_ci return -ENOMEM; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci bit -= iter->startbit; 7878c2ecf20Sopenharmony_ci idx = bit / NETLBL_CATMAP_MAPSIZE; 7888c2ecf20Sopenharmony_ci iter->bitmap[idx] |= NETLBL_CATMAP_BIT << (bit % NETLBL_CATMAP_MAPSIZE); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci return 0; 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_ciEXPORT_SYMBOL(netlbl_catmap_setbit); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci/** 7958c2ecf20Sopenharmony_ci * netlbl_catmap_setrng - Set a range of bits in a LSM secattr catmap 7968c2ecf20Sopenharmony_ci * @catmap: pointer to the category bitmap 7978c2ecf20Sopenharmony_ci * @start: the starting bit 7988c2ecf20Sopenharmony_ci * @end: the last bit in the string 7998c2ecf20Sopenharmony_ci * @flags: memory allocation flags 8008c2ecf20Sopenharmony_ci * 8018c2ecf20Sopenharmony_ci * Description: 8028c2ecf20Sopenharmony_ci * Set a range of bits, starting at @start and ending with @end. Returns zero 8038c2ecf20Sopenharmony_ci * on success, negative values on failure. 8048c2ecf20Sopenharmony_ci * 8058c2ecf20Sopenharmony_ci */ 8068c2ecf20Sopenharmony_ciint netlbl_catmap_setrng(struct netlbl_lsm_catmap **catmap, 8078c2ecf20Sopenharmony_ci u32 start, 8088c2ecf20Sopenharmony_ci u32 end, 8098c2ecf20Sopenharmony_ci gfp_t flags) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci int rc = 0; 8128c2ecf20Sopenharmony_ci u32 spot = start; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci while (rc == 0 && spot <= end) { 8158c2ecf20Sopenharmony_ci if (((spot & (BITS_PER_LONG - 1)) == 0) && 8168c2ecf20Sopenharmony_ci ((end - spot) > BITS_PER_LONG)) { 8178c2ecf20Sopenharmony_ci rc = netlbl_catmap_setlong(catmap, 8188c2ecf20Sopenharmony_ci spot, 8198c2ecf20Sopenharmony_ci (unsigned long)-1, 8208c2ecf20Sopenharmony_ci flags); 8218c2ecf20Sopenharmony_ci spot += BITS_PER_LONG; 8228c2ecf20Sopenharmony_ci } else 8238c2ecf20Sopenharmony_ci rc = netlbl_catmap_setbit(catmap, spot++, flags); 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci return rc; 8278c2ecf20Sopenharmony_ci} 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci/** 8308c2ecf20Sopenharmony_ci * netlbl_catmap_setlong - Import an unsigned long bitmap 8318c2ecf20Sopenharmony_ci * @catmap: pointer to the category bitmap 8328c2ecf20Sopenharmony_ci * @offset: offset to the start of the imported bitmap 8338c2ecf20Sopenharmony_ci * @bitmap: the bitmap to import 8348c2ecf20Sopenharmony_ci * @flags: memory allocation flags 8358c2ecf20Sopenharmony_ci * 8368c2ecf20Sopenharmony_ci * Description: 8378c2ecf20Sopenharmony_ci * Import the bitmap specified in @bitmap into @catmap, using the offset 8388c2ecf20Sopenharmony_ci * in @offset. The offset must be aligned to an unsigned long. Returns zero 8398c2ecf20Sopenharmony_ci * on success, negative values on failure. 8408c2ecf20Sopenharmony_ci * 8418c2ecf20Sopenharmony_ci */ 8428c2ecf20Sopenharmony_ciint netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap, 8438c2ecf20Sopenharmony_ci u32 offset, 8448c2ecf20Sopenharmony_ci unsigned long bitmap, 8458c2ecf20Sopenharmony_ci gfp_t flags) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci struct netlbl_lsm_catmap *iter; 8488c2ecf20Sopenharmony_ci u32 idx; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci /* only allow aligned offsets */ 8518c2ecf20Sopenharmony_ci if ((offset & (BITS_PER_LONG - 1)) != 0) 8528c2ecf20Sopenharmony_ci return -EINVAL; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci iter = _netlbl_catmap_getnode(catmap, offset, _CM_F_ALLOC, flags); 8558c2ecf20Sopenharmony_ci if (iter == NULL) 8568c2ecf20Sopenharmony_ci return -ENOMEM; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci offset -= iter->startbit; 8598c2ecf20Sopenharmony_ci idx = offset / NETLBL_CATMAP_MAPSIZE; 8608c2ecf20Sopenharmony_ci iter->bitmap[idx] |= (NETLBL_CATMAP_MAPTYPE)bitmap 8618c2ecf20Sopenharmony_ci << (offset % NETLBL_CATMAP_MAPSIZE); 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci return 0; 8648c2ecf20Sopenharmony_ci} 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci/* Bitmap functions 8678c2ecf20Sopenharmony_ci */ 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci/** 8708c2ecf20Sopenharmony_ci * netlbl_bitmap_walk - Walk a bitmap looking for a bit 8718c2ecf20Sopenharmony_ci * @bitmap: the bitmap 8728c2ecf20Sopenharmony_ci * @bitmap_len: length in bits 8738c2ecf20Sopenharmony_ci * @offset: starting offset 8748c2ecf20Sopenharmony_ci * @state: if non-zero, look for a set (1) bit else look for a cleared (0) bit 8758c2ecf20Sopenharmony_ci * 8768c2ecf20Sopenharmony_ci * Description: 8778c2ecf20Sopenharmony_ci * Starting at @offset, walk the bitmap from left to right until either the 8788c2ecf20Sopenharmony_ci * desired bit is found or we reach the end. Return the bit offset, -1 if 8798c2ecf20Sopenharmony_ci * not found, or -2 if error. 8808c2ecf20Sopenharmony_ci */ 8818c2ecf20Sopenharmony_ciint netlbl_bitmap_walk(const unsigned char *bitmap, u32 bitmap_len, 8828c2ecf20Sopenharmony_ci u32 offset, u8 state) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci u32 bit_spot; 8858c2ecf20Sopenharmony_ci u32 byte_offset; 8868c2ecf20Sopenharmony_ci unsigned char bitmask; 8878c2ecf20Sopenharmony_ci unsigned char byte; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci if (offset >= bitmap_len) 8908c2ecf20Sopenharmony_ci return -1; 8918c2ecf20Sopenharmony_ci byte_offset = offset / 8; 8928c2ecf20Sopenharmony_ci byte = bitmap[byte_offset]; 8938c2ecf20Sopenharmony_ci bit_spot = offset; 8948c2ecf20Sopenharmony_ci bitmask = 0x80 >> (offset % 8); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci while (bit_spot < bitmap_len) { 8978c2ecf20Sopenharmony_ci if ((state && (byte & bitmask) == bitmask) || 8988c2ecf20Sopenharmony_ci (state == 0 && (byte & bitmask) == 0)) 8998c2ecf20Sopenharmony_ci return bit_spot; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci if (++bit_spot >= bitmap_len) 9028c2ecf20Sopenharmony_ci return -1; 9038c2ecf20Sopenharmony_ci bitmask >>= 1; 9048c2ecf20Sopenharmony_ci if (bitmask == 0) { 9058c2ecf20Sopenharmony_ci byte = bitmap[++byte_offset]; 9068c2ecf20Sopenharmony_ci bitmask = 0x80; 9078c2ecf20Sopenharmony_ci } 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci return -1; 9118c2ecf20Sopenharmony_ci} 9128c2ecf20Sopenharmony_ciEXPORT_SYMBOL(netlbl_bitmap_walk); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci/** 9158c2ecf20Sopenharmony_ci * netlbl_bitmap_setbit - Sets a single bit in a bitmap 9168c2ecf20Sopenharmony_ci * @bitmap: the bitmap 9178c2ecf20Sopenharmony_ci * @bit: the bit 9188c2ecf20Sopenharmony_ci * @state: if non-zero, set the bit (1) else clear the bit (0) 9198c2ecf20Sopenharmony_ci * 9208c2ecf20Sopenharmony_ci * Description: 9218c2ecf20Sopenharmony_ci * Set a single bit in the bitmask. Returns zero on success, negative values 9228c2ecf20Sopenharmony_ci * on error. 9238c2ecf20Sopenharmony_ci */ 9248c2ecf20Sopenharmony_civoid netlbl_bitmap_setbit(unsigned char *bitmap, u32 bit, u8 state) 9258c2ecf20Sopenharmony_ci{ 9268c2ecf20Sopenharmony_ci u32 byte_spot; 9278c2ecf20Sopenharmony_ci u8 bitmask; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci /* gcc always rounds to zero when doing integer division */ 9308c2ecf20Sopenharmony_ci byte_spot = bit / 8; 9318c2ecf20Sopenharmony_ci bitmask = 0x80 >> (bit % 8); 9328c2ecf20Sopenharmony_ci if (state) 9338c2ecf20Sopenharmony_ci bitmap[byte_spot] |= bitmask; 9348c2ecf20Sopenharmony_ci else 9358c2ecf20Sopenharmony_ci bitmap[byte_spot] &= ~bitmask; 9368c2ecf20Sopenharmony_ci} 9378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(netlbl_bitmap_setbit); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci/* 9408c2ecf20Sopenharmony_ci * LSM Functions 9418c2ecf20Sopenharmony_ci */ 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci/** 9448c2ecf20Sopenharmony_ci * netlbl_enabled - Determine if the NetLabel subsystem is enabled 9458c2ecf20Sopenharmony_ci * 9468c2ecf20Sopenharmony_ci * Description: 9478c2ecf20Sopenharmony_ci * The LSM can use this function to determine if it should use NetLabel 9488c2ecf20Sopenharmony_ci * security attributes in it's enforcement mechanism. Currently, NetLabel is 9498c2ecf20Sopenharmony_ci * considered to be enabled when it's configuration contains a valid setup for 9508c2ecf20Sopenharmony_ci * at least one labeled protocol (i.e. NetLabel can understand incoming 9518c2ecf20Sopenharmony_ci * labeled packets of at least one type); otherwise NetLabel is considered to 9528c2ecf20Sopenharmony_ci * be disabled. 9538c2ecf20Sopenharmony_ci * 9548c2ecf20Sopenharmony_ci */ 9558c2ecf20Sopenharmony_ciint netlbl_enabled(void) 9568c2ecf20Sopenharmony_ci{ 9578c2ecf20Sopenharmony_ci /* At some point we probably want to expose this mechanism to the user 9588c2ecf20Sopenharmony_ci * as well so that admins can toggle NetLabel regardless of the 9598c2ecf20Sopenharmony_ci * configuration */ 9608c2ecf20Sopenharmony_ci return (atomic_read(&netlabel_mgmt_protocount) > 0); 9618c2ecf20Sopenharmony_ci} 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci/** 9648c2ecf20Sopenharmony_ci * netlbl_sock_setattr - Label a socket using the correct protocol 9658c2ecf20Sopenharmony_ci * @sk: the socket to label 9668c2ecf20Sopenharmony_ci * @family: protocol family 9678c2ecf20Sopenharmony_ci * @secattr: the security attributes 9688c2ecf20Sopenharmony_ci * 9698c2ecf20Sopenharmony_ci * Description: 9708c2ecf20Sopenharmony_ci * Attach the correct label to the given socket using the security attributes 9718c2ecf20Sopenharmony_ci * specified in @secattr. This function requires exclusive access to @sk, 9728c2ecf20Sopenharmony_ci * which means it either needs to be in the process of being created or locked. 9738c2ecf20Sopenharmony_ci * Returns zero on success, -EDESTADDRREQ if the domain is configured to use 9748c2ecf20Sopenharmony_ci * network address selectors (can't blindly label the socket), and negative 9758c2ecf20Sopenharmony_ci * values on all other failures. 9768c2ecf20Sopenharmony_ci * 9778c2ecf20Sopenharmony_ci */ 9788c2ecf20Sopenharmony_ciint netlbl_sock_setattr(struct sock *sk, 9798c2ecf20Sopenharmony_ci u16 family, 9808c2ecf20Sopenharmony_ci const struct netlbl_lsm_secattr *secattr) 9818c2ecf20Sopenharmony_ci{ 9828c2ecf20Sopenharmony_ci int ret_val; 9838c2ecf20Sopenharmony_ci struct netlbl_dom_map *dom_entry; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci rcu_read_lock(); 9868c2ecf20Sopenharmony_ci dom_entry = netlbl_domhsh_getentry(secattr->domain, family); 9878c2ecf20Sopenharmony_ci if (dom_entry == NULL) { 9888c2ecf20Sopenharmony_ci ret_val = -ENOENT; 9898c2ecf20Sopenharmony_ci goto socket_setattr_return; 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci switch (family) { 9928c2ecf20Sopenharmony_ci case AF_INET: 9938c2ecf20Sopenharmony_ci switch (dom_entry->def.type) { 9948c2ecf20Sopenharmony_ci case NETLBL_NLTYPE_ADDRSELECT: 9958c2ecf20Sopenharmony_ci ret_val = -EDESTADDRREQ; 9968c2ecf20Sopenharmony_ci break; 9978c2ecf20Sopenharmony_ci case NETLBL_NLTYPE_CIPSOV4: 9988c2ecf20Sopenharmony_ci ret_val = cipso_v4_sock_setattr(sk, 9998c2ecf20Sopenharmony_ci dom_entry->def.cipso, 10008c2ecf20Sopenharmony_ci secattr); 10018c2ecf20Sopenharmony_ci break; 10028c2ecf20Sopenharmony_ci case NETLBL_NLTYPE_UNLABELED: 10038c2ecf20Sopenharmony_ci ret_val = 0; 10048c2ecf20Sopenharmony_ci break; 10058c2ecf20Sopenharmony_ci default: 10068c2ecf20Sopenharmony_ci ret_val = -ENOENT; 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci break; 10098c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 10108c2ecf20Sopenharmony_ci case AF_INET6: 10118c2ecf20Sopenharmony_ci switch (dom_entry->def.type) { 10128c2ecf20Sopenharmony_ci case NETLBL_NLTYPE_ADDRSELECT: 10138c2ecf20Sopenharmony_ci ret_val = -EDESTADDRREQ; 10148c2ecf20Sopenharmony_ci break; 10158c2ecf20Sopenharmony_ci case NETLBL_NLTYPE_CALIPSO: 10168c2ecf20Sopenharmony_ci ret_val = calipso_sock_setattr(sk, 10178c2ecf20Sopenharmony_ci dom_entry->def.calipso, 10188c2ecf20Sopenharmony_ci secattr); 10198c2ecf20Sopenharmony_ci break; 10208c2ecf20Sopenharmony_ci case NETLBL_NLTYPE_UNLABELED: 10218c2ecf20Sopenharmony_ci ret_val = 0; 10228c2ecf20Sopenharmony_ci break; 10238c2ecf20Sopenharmony_ci default: 10248c2ecf20Sopenharmony_ci ret_val = -ENOENT; 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci break; 10278c2ecf20Sopenharmony_ci#endif /* IPv6 */ 10288c2ecf20Sopenharmony_ci default: 10298c2ecf20Sopenharmony_ci ret_val = -EPROTONOSUPPORT; 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_cisocket_setattr_return: 10338c2ecf20Sopenharmony_ci rcu_read_unlock(); 10348c2ecf20Sopenharmony_ci return ret_val; 10358c2ecf20Sopenharmony_ci} 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci/** 10388c2ecf20Sopenharmony_ci * netlbl_sock_delattr - Delete all the NetLabel labels on a socket 10398c2ecf20Sopenharmony_ci * @sk: the socket 10408c2ecf20Sopenharmony_ci * 10418c2ecf20Sopenharmony_ci * Description: 10428c2ecf20Sopenharmony_ci * Remove all the NetLabel labeling from @sk. The caller is responsible for 10438c2ecf20Sopenharmony_ci * ensuring that @sk is locked. 10448c2ecf20Sopenharmony_ci * 10458c2ecf20Sopenharmony_ci */ 10468c2ecf20Sopenharmony_civoid netlbl_sock_delattr(struct sock *sk) 10478c2ecf20Sopenharmony_ci{ 10488c2ecf20Sopenharmony_ci switch (sk->sk_family) { 10498c2ecf20Sopenharmony_ci case AF_INET: 10508c2ecf20Sopenharmony_ci cipso_v4_sock_delattr(sk); 10518c2ecf20Sopenharmony_ci break; 10528c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 10538c2ecf20Sopenharmony_ci case AF_INET6: 10548c2ecf20Sopenharmony_ci calipso_sock_delattr(sk); 10558c2ecf20Sopenharmony_ci break; 10568c2ecf20Sopenharmony_ci#endif /* IPv6 */ 10578c2ecf20Sopenharmony_ci } 10588c2ecf20Sopenharmony_ci} 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci/** 10618c2ecf20Sopenharmony_ci * netlbl_sock_getattr - Determine the security attributes of a sock 10628c2ecf20Sopenharmony_ci * @sk: the sock 10638c2ecf20Sopenharmony_ci * @secattr: the security attributes 10648c2ecf20Sopenharmony_ci * 10658c2ecf20Sopenharmony_ci * Description: 10668c2ecf20Sopenharmony_ci * Examines the given sock to see if any NetLabel style labeling has been 10678c2ecf20Sopenharmony_ci * applied to the sock, if so it parses the socket label and returns the 10688c2ecf20Sopenharmony_ci * security attributes in @secattr. Returns zero on success, negative values 10698c2ecf20Sopenharmony_ci * on failure. 10708c2ecf20Sopenharmony_ci * 10718c2ecf20Sopenharmony_ci */ 10728c2ecf20Sopenharmony_ciint netlbl_sock_getattr(struct sock *sk, 10738c2ecf20Sopenharmony_ci struct netlbl_lsm_secattr *secattr) 10748c2ecf20Sopenharmony_ci{ 10758c2ecf20Sopenharmony_ci int ret_val; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci switch (sk->sk_family) { 10788c2ecf20Sopenharmony_ci case AF_INET: 10798c2ecf20Sopenharmony_ci ret_val = cipso_v4_sock_getattr(sk, secattr); 10808c2ecf20Sopenharmony_ci break; 10818c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 10828c2ecf20Sopenharmony_ci case AF_INET6: 10838c2ecf20Sopenharmony_ci ret_val = calipso_sock_getattr(sk, secattr); 10848c2ecf20Sopenharmony_ci break; 10858c2ecf20Sopenharmony_ci#endif /* IPv6 */ 10868c2ecf20Sopenharmony_ci default: 10878c2ecf20Sopenharmony_ci ret_val = -EPROTONOSUPPORT; 10888c2ecf20Sopenharmony_ci } 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci return ret_val; 10918c2ecf20Sopenharmony_ci} 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci/** 10948c2ecf20Sopenharmony_ci * netlbl_conn_setattr - Label a connected socket using the correct protocol 10958c2ecf20Sopenharmony_ci * @sk: the socket to label 10968c2ecf20Sopenharmony_ci * @addr: the destination address 10978c2ecf20Sopenharmony_ci * @secattr: the security attributes 10988c2ecf20Sopenharmony_ci * 10998c2ecf20Sopenharmony_ci * Description: 11008c2ecf20Sopenharmony_ci * Attach the correct label to the given connected socket using the security 11018c2ecf20Sopenharmony_ci * attributes specified in @secattr. The caller is responsible for ensuring 11028c2ecf20Sopenharmony_ci * that @sk is locked. Returns zero on success, negative values on failure. 11038c2ecf20Sopenharmony_ci * 11048c2ecf20Sopenharmony_ci */ 11058c2ecf20Sopenharmony_ciint netlbl_conn_setattr(struct sock *sk, 11068c2ecf20Sopenharmony_ci struct sockaddr *addr, 11078c2ecf20Sopenharmony_ci const struct netlbl_lsm_secattr *secattr) 11088c2ecf20Sopenharmony_ci{ 11098c2ecf20Sopenharmony_ci int ret_val; 11108c2ecf20Sopenharmony_ci struct sockaddr_in *addr4; 11118c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 11128c2ecf20Sopenharmony_ci struct sockaddr_in6 *addr6; 11138c2ecf20Sopenharmony_ci#endif 11148c2ecf20Sopenharmony_ci struct netlbl_dommap_def *entry; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci rcu_read_lock(); 11178c2ecf20Sopenharmony_ci switch (addr->sa_family) { 11188c2ecf20Sopenharmony_ci case AF_INET: 11198c2ecf20Sopenharmony_ci addr4 = (struct sockaddr_in *)addr; 11208c2ecf20Sopenharmony_ci entry = netlbl_domhsh_getentry_af4(secattr->domain, 11218c2ecf20Sopenharmony_ci addr4->sin_addr.s_addr); 11228c2ecf20Sopenharmony_ci if (entry == NULL) { 11238c2ecf20Sopenharmony_ci ret_val = -ENOENT; 11248c2ecf20Sopenharmony_ci goto conn_setattr_return; 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci switch (entry->type) { 11278c2ecf20Sopenharmony_ci case NETLBL_NLTYPE_CIPSOV4: 11288c2ecf20Sopenharmony_ci ret_val = cipso_v4_sock_setattr(sk, 11298c2ecf20Sopenharmony_ci entry->cipso, secattr); 11308c2ecf20Sopenharmony_ci break; 11318c2ecf20Sopenharmony_ci case NETLBL_NLTYPE_UNLABELED: 11328c2ecf20Sopenharmony_ci /* just delete the protocols we support for right now 11338c2ecf20Sopenharmony_ci * but we could remove other protocols if needed */ 11348c2ecf20Sopenharmony_ci netlbl_sock_delattr(sk); 11358c2ecf20Sopenharmony_ci ret_val = 0; 11368c2ecf20Sopenharmony_ci break; 11378c2ecf20Sopenharmony_ci default: 11388c2ecf20Sopenharmony_ci ret_val = -ENOENT; 11398c2ecf20Sopenharmony_ci } 11408c2ecf20Sopenharmony_ci break; 11418c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 11428c2ecf20Sopenharmony_ci case AF_INET6: 11438c2ecf20Sopenharmony_ci addr6 = (struct sockaddr_in6 *)addr; 11448c2ecf20Sopenharmony_ci entry = netlbl_domhsh_getentry_af6(secattr->domain, 11458c2ecf20Sopenharmony_ci &addr6->sin6_addr); 11468c2ecf20Sopenharmony_ci if (entry == NULL) { 11478c2ecf20Sopenharmony_ci ret_val = -ENOENT; 11488c2ecf20Sopenharmony_ci goto conn_setattr_return; 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci switch (entry->type) { 11518c2ecf20Sopenharmony_ci case NETLBL_NLTYPE_CALIPSO: 11528c2ecf20Sopenharmony_ci ret_val = calipso_sock_setattr(sk, 11538c2ecf20Sopenharmony_ci entry->calipso, secattr); 11548c2ecf20Sopenharmony_ci break; 11558c2ecf20Sopenharmony_ci case NETLBL_NLTYPE_UNLABELED: 11568c2ecf20Sopenharmony_ci /* just delete the protocols we support for right now 11578c2ecf20Sopenharmony_ci * but we could remove other protocols if needed */ 11588c2ecf20Sopenharmony_ci netlbl_sock_delattr(sk); 11598c2ecf20Sopenharmony_ci ret_val = 0; 11608c2ecf20Sopenharmony_ci break; 11618c2ecf20Sopenharmony_ci default: 11628c2ecf20Sopenharmony_ci ret_val = -ENOENT; 11638c2ecf20Sopenharmony_ci } 11648c2ecf20Sopenharmony_ci break; 11658c2ecf20Sopenharmony_ci#endif /* IPv6 */ 11668c2ecf20Sopenharmony_ci default: 11678c2ecf20Sopenharmony_ci ret_val = -EPROTONOSUPPORT; 11688c2ecf20Sopenharmony_ci } 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ciconn_setattr_return: 11718c2ecf20Sopenharmony_ci rcu_read_unlock(); 11728c2ecf20Sopenharmony_ci return ret_val; 11738c2ecf20Sopenharmony_ci} 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci/** 11768c2ecf20Sopenharmony_ci * netlbl_req_setattr - Label a request socket using the correct protocol 11778c2ecf20Sopenharmony_ci * @req: the request socket to label 11788c2ecf20Sopenharmony_ci * @secattr: the security attributes 11798c2ecf20Sopenharmony_ci * 11808c2ecf20Sopenharmony_ci * Description: 11818c2ecf20Sopenharmony_ci * Attach the correct label to the given socket using the security attributes 11828c2ecf20Sopenharmony_ci * specified in @secattr. Returns zero on success, negative values on failure. 11838c2ecf20Sopenharmony_ci * 11848c2ecf20Sopenharmony_ci */ 11858c2ecf20Sopenharmony_ciint netlbl_req_setattr(struct request_sock *req, 11868c2ecf20Sopenharmony_ci const struct netlbl_lsm_secattr *secattr) 11878c2ecf20Sopenharmony_ci{ 11888c2ecf20Sopenharmony_ci int ret_val; 11898c2ecf20Sopenharmony_ci struct netlbl_dommap_def *entry; 11908c2ecf20Sopenharmony_ci struct inet_request_sock *ireq = inet_rsk(req); 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci rcu_read_lock(); 11938c2ecf20Sopenharmony_ci switch (req->rsk_ops->family) { 11948c2ecf20Sopenharmony_ci case AF_INET: 11958c2ecf20Sopenharmony_ci entry = netlbl_domhsh_getentry_af4(secattr->domain, 11968c2ecf20Sopenharmony_ci ireq->ir_rmt_addr); 11978c2ecf20Sopenharmony_ci if (entry == NULL) { 11988c2ecf20Sopenharmony_ci ret_val = -ENOENT; 11998c2ecf20Sopenharmony_ci goto req_setattr_return; 12008c2ecf20Sopenharmony_ci } 12018c2ecf20Sopenharmony_ci switch (entry->type) { 12028c2ecf20Sopenharmony_ci case NETLBL_NLTYPE_CIPSOV4: 12038c2ecf20Sopenharmony_ci ret_val = cipso_v4_req_setattr(req, 12048c2ecf20Sopenharmony_ci entry->cipso, secattr); 12058c2ecf20Sopenharmony_ci break; 12068c2ecf20Sopenharmony_ci case NETLBL_NLTYPE_UNLABELED: 12078c2ecf20Sopenharmony_ci netlbl_req_delattr(req); 12088c2ecf20Sopenharmony_ci ret_val = 0; 12098c2ecf20Sopenharmony_ci break; 12108c2ecf20Sopenharmony_ci default: 12118c2ecf20Sopenharmony_ci ret_val = -ENOENT; 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci break; 12148c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 12158c2ecf20Sopenharmony_ci case AF_INET6: 12168c2ecf20Sopenharmony_ci entry = netlbl_domhsh_getentry_af6(secattr->domain, 12178c2ecf20Sopenharmony_ci &ireq->ir_v6_rmt_addr); 12188c2ecf20Sopenharmony_ci if (entry == NULL) { 12198c2ecf20Sopenharmony_ci ret_val = -ENOENT; 12208c2ecf20Sopenharmony_ci goto req_setattr_return; 12218c2ecf20Sopenharmony_ci } 12228c2ecf20Sopenharmony_ci switch (entry->type) { 12238c2ecf20Sopenharmony_ci case NETLBL_NLTYPE_CALIPSO: 12248c2ecf20Sopenharmony_ci ret_val = calipso_req_setattr(req, 12258c2ecf20Sopenharmony_ci entry->calipso, secattr); 12268c2ecf20Sopenharmony_ci break; 12278c2ecf20Sopenharmony_ci case NETLBL_NLTYPE_UNLABELED: 12288c2ecf20Sopenharmony_ci netlbl_req_delattr(req); 12298c2ecf20Sopenharmony_ci ret_val = 0; 12308c2ecf20Sopenharmony_ci break; 12318c2ecf20Sopenharmony_ci default: 12328c2ecf20Sopenharmony_ci ret_val = -ENOENT; 12338c2ecf20Sopenharmony_ci } 12348c2ecf20Sopenharmony_ci break; 12358c2ecf20Sopenharmony_ci#endif /* IPv6 */ 12368c2ecf20Sopenharmony_ci default: 12378c2ecf20Sopenharmony_ci ret_val = -EPROTONOSUPPORT; 12388c2ecf20Sopenharmony_ci } 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_cireq_setattr_return: 12418c2ecf20Sopenharmony_ci rcu_read_unlock(); 12428c2ecf20Sopenharmony_ci return ret_val; 12438c2ecf20Sopenharmony_ci} 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci/** 12468c2ecf20Sopenharmony_ci* netlbl_req_delattr - Delete all the NetLabel labels on a socket 12478c2ecf20Sopenharmony_ci* @req: the socket 12488c2ecf20Sopenharmony_ci* 12498c2ecf20Sopenharmony_ci* Description: 12508c2ecf20Sopenharmony_ci* Remove all the NetLabel labeling from @req. 12518c2ecf20Sopenharmony_ci* 12528c2ecf20Sopenharmony_ci*/ 12538c2ecf20Sopenharmony_civoid netlbl_req_delattr(struct request_sock *req) 12548c2ecf20Sopenharmony_ci{ 12558c2ecf20Sopenharmony_ci switch (req->rsk_ops->family) { 12568c2ecf20Sopenharmony_ci case AF_INET: 12578c2ecf20Sopenharmony_ci cipso_v4_req_delattr(req); 12588c2ecf20Sopenharmony_ci break; 12598c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 12608c2ecf20Sopenharmony_ci case AF_INET6: 12618c2ecf20Sopenharmony_ci calipso_req_delattr(req); 12628c2ecf20Sopenharmony_ci break; 12638c2ecf20Sopenharmony_ci#endif /* IPv6 */ 12648c2ecf20Sopenharmony_ci } 12658c2ecf20Sopenharmony_ci} 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci/** 12688c2ecf20Sopenharmony_ci * netlbl_skbuff_setattr - Label a packet using the correct protocol 12698c2ecf20Sopenharmony_ci * @skb: the packet 12708c2ecf20Sopenharmony_ci * @family: protocol family 12718c2ecf20Sopenharmony_ci * @secattr: the security attributes 12728c2ecf20Sopenharmony_ci * 12738c2ecf20Sopenharmony_ci * Description: 12748c2ecf20Sopenharmony_ci * Attach the correct label to the given packet using the security attributes 12758c2ecf20Sopenharmony_ci * specified in @secattr. Returns zero on success, negative values on failure. 12768c2ecf20Sopenharmony_ci * 12778c2ecf20Sopenharmony_ci */ 12788c2ecf20Sopenharmony_ciint netlbl_skbuff_setattr(struct sk_buff *skb, 12798c2ecf20Sopenharmony_ci u16 family, 12808c2ecf20Sopenharmony_ci const struct netlbl_lsm_secattr *secattr) 12818c2ecf20Sopenharmony_ci{ 12828c2ecf20Sopenharmony_ci int ret_val; 12838c2ecf20Sopenharmony_ci struct iphdr *hdr4; 12848c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 12858c2ecf20Sopenharmony_ci struct ipv6hdr *hdr6; 12868c2ecf20Sopenharmony_ci#endif 12878c2ecf20Sopenharmony_ci struct netlbl_dommap_def *entry; 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci rcu_read_lock(); 12908c2ecf20Sopenharmony_ci switch (family) { 12918c2ecf20Sopenharmony_ci case AF_INET: 12928c2ecf20Sopenharmony_ci hdr4 = ip_hdr(skb); 12938c2ecf20Sopenharmony_ci entry = netlbl_domhsh_getentry_af4(secattr->domain, 12948c2ecf20Sopenharmony_ci hdr4->daddr); 12958c2ecf20Sopenharmony_ci if (entry == NULL) { 12968c2ecf20Sopenharmony_ci ret_val = -ENOENT; 12978c2ecf20Sopenharmony_ci goto skbuff_setattr_return; 12988c2ecf20Sopenharmony_ci } 12998c2ecf20Sopenharmony_ci switch (entry->type) { 13008c2ecf20Sopenharmony_ci case NETLBL_NLTYPE_CIPSOV4: 13018c2ecf20Sopenharmony_ci ret_val = cipso_v4_skbuff_setattr(skb, entry->cipso, 13028c2ecf20Sopenharmony_ci secattr); 13038c2ecf20Sopenharmony_ci break; 13048c2ecf20Sopenharmony_ci case NETLBL_NLTYPE_UNLABELED: 13058c2ecf20Sopenharmony_ci /* just delete the protocols we support for right now 13068c2ecf20Sopenharmony_ci * but we could remove other protocols if needed */ 13078c2ecf20Sopenharmony_ci ret_val = cipso_v4_skbuff_delattr(skb); 13088c2ecf20Sopenharmony_ci break; 13098c2ecf20Sopenharmony_ci default: 13108c2ecf20Sopenharmony_ci ret_val = -ENOENT; 13118c2ecf20Sopenharmony_ci } 13128c2ecf20Sopenharmony_ci break; 13138c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 13148c2ecf20Sopenharmony_ci case AF_INET6: 13158c2ecf20Sopenharmony_ci hdr6 = ipv6_hdr(skb); 13168c2ecf20Sopenharmony_ci entry = netlbl_domhsh_getentry_af6(secattr->domain, 13178c2ecf20Sopenharmony_ci &hdr6->daddr); 13188c2ecf20Sopenharmony_ci if (entry == NULL) { 13198c2ecf20Sopenharmony_ci ret_val = -ENOENT; 13208c2ecf20Sopenharmony_ci goto skbuff_setattr_return; 13218c2ecf20Sopenharmony_ci } 13228c2ecf20Sopenharmony_ci switch (entry->type) { 13238c2ecf20Sopenharmony_ci case NETLBL_NLTYPE_CALIPSO: 13248c2ecf20Sopenharmony_ci ret_val = calipso_skbuff_setattr(skb, entry->calipso, 13258c2ecf20Sopenharmony_ci secattr); 13268c2ecf20Sopenharmony_ci break; 13278c2ecf20Sopenharmony_ci case NETLBL_NLTYPE_UNLABELED: 13288c2ecf20Sopenharmony_ci /* just delete the protocols we support for right now 13298c2ecf20Sopenharmony_ci * but we could remove other protocols if needed */ 13308c2ecf20Sopenharmony_ci ret_val = calipso_skbuff_delattr(skb); 13318c2ecf20Sopenharmony_ci break; 13328c2ecf20Sopenharmony_ci default: 13338c2ecf20Sopenharmony_ci ret_val = -ENOENT; 13348c2ecf20Sopenharmony_ci } 13358c2ecf20Sopenharmony_ci break; 13368c2ecf20Sopenharmony_ci#endif /* IPv6 */ 13378c2ecf20Sopenharmony_ci default: 13388c2ecf20Sopenharmony_ci ret_val = -EPROTONOSUPPORT; 13398c2ecf20Sopenharmony_ci } 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ciskbuff_setattr_return: 13428c2ecf20Sopenharmony_ci rcu_read_unlock(); 13438c2ecf20Sopenharmony_ci return ret_val; 13448c2ecf20Sopenharmony_ci} 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci/** 13478c2ecf20Sopenharmony_ci * netlbl_skbuff_getattr - Determine the security attributes of a packet 13488c2ecf20Sopenharmony_ci * @skb: the packet 13498c2ecf20Sopenharmony_ci * @family: protocol family 13508c2ecf20Sopenharmony_ci * @secattr: the security attributes 13518c2ecf20Sopenharmony_ci * 13528c2ecf20Sopenharmony_ci * Description: 13538c2ecf20Sopenharmony_ci * Examines the given packet to see if a recognized form of packet labeling 13548c2ecf20Sopenharmony_ci * is present, if so it parses the packet label and returns the security 13558c2ecf20Sopenharmony_ci * attributes in @secattr. Returns zero on success, negative values on 13568c2ecf20Sopenharmony_ci * failure. 13578c2ecf20Sopenharmony_ci * 13588c2ecf20Sopenharmony_ci */ 13598c2ecf20Sopenharmony_ciint netlbl_skbuff_getattr(const struct sk_buff *skb, 13608c2ecf20Sopenharmony_ci u16 family, 13618c2ecf20Sopenharmony_ci struct netlbl_lsm_secattr *secattr) 13628c2ecf20Sopenharmony_ci{ 13638c2ecf20Sopenharmony_ci unsigned char *ptr; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci switch (family) { 13668c2ecf20Sopenharmony_ci case AF_INET: 13678c2ecf20Sopenharmony_ci ptr = cipso_v4_optptr(skb); 13688c2ecf20Sopenharmony_ci if (ptr && cipso_v4_getattr(ptr, secattr) == 0) 13698c2ecf20Sopenharmony_ci return 0; 13708c2ecf20Sopenharmony_ci break; 13718c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 13728c2ecf20Sopenharmony_ci case AF_INET6: 13738c2ecf20Sopenharmony_ci ptr = calipso_optptr(skb); 13748c2ecf20Sopenharmony_ci if (ptr && calipso_getattr(ptr, secattr) == 0) 13758c2ecf20Sopenharmony_ci return 0; 13768c2ecf20Sopenharmony_ci break; 13778c2ecf20Sopenharmony_ci#endif /* IPv6 */ 13788c2ecf20Sopenharmony_ci } 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci return netlbl_unlabel_getattr(skb, family, secattr); 13818c2ecf20Sopenharmony_ci} 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci/** 13848c2ecf20Sopenharmony_ci * netlbl_skbuff_err - Handle a LSM error on a sk_buff 13858c2ecf20Sopenharmony_ci * @skb: the packet 13868c2ecf20Sopenharmony_ci * @family: the family 13878c2ecf20Sopenharmony_ci * @error: the error code 13888c2ecf20Sopenharmony_ci * @gateway: true if host is acting as a gateway, false otherwise 13898c2ecf20Sopenharmony_ci * 13908c2ecf20Sopenharmony_ci * Description: 13918c2ecf20Sopenharmony_ci * Deal with a LSM problem when handling the packet in @skb, typically this is 13928c2ecf20Sopenharmony_ci * a permission denied problem (-EACCES). The correct action is determined 13938c2ecf20Sopenharmony_ci * according to the packet's labeling protocol. 13948c2ecf20Sopenharmony_ci * 13958c2ecf20Sopenharmony_ci */ 13968c2ecf20Sopenharmony_civoid netlbl_skbuff_err(struct sk_buff *skb, u16 family, int error, int gateway) 13978c2ecf20Sopenharmony_ci{ 13988c2ecf20Sopenharmony_ci switch (family) { 13998c2ecf20Sopenharmony_ci case AF_INET: 14008c2ecf20Sopenharmony_ci if (cipso_v4_optptr(skb)) 14018c2ecf20Sopenharmony_ci cipso_v4_error(skb, error, gateway); 14028c2ecf20Sopenharmony_ci break; 14038c2ecf20Sopenharmony_ci } 14048c2ecf20Sopenharmony_ci} 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci/** 14078c2ecf20Sopenharmony_ci * netlbl_cache_invalidate - Invalidate all of the NetLabel protocol caches 14088c2ecf20Sopenharmony_ci * 14098c2ecf20Sopenharmony_ci * Description: 14108c2ecf20Sopenharmony_ci * For all of the NetLabel protocols that support some form of label mapping 14118c2ecf20Sopenharmony_ci * cache, invalidate the cache. Returns zero on success, negative values on 14128c2ecf20Sopenharmony_ci * error. 14138c2ecf20Sopenharmony_ci * 14148c2ecf20Sopenharmony_ci */ 14158c2ecf20Sopenharmony_civoid netlbl_cache_invalidate(void) 14168c2ecf20Sopenharmony_ci{ 14178c2ecf20Sopenharmony_ci cipso_v4_cache_invalidate(); 14188c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 14198c2ecf20Sopenharmony_ci calipso_cache_invalidate(); 14208c2ecf20Sopenharmony_ci#endif /* IPv6 */ 14218c2ecf20Sopenharmony_ci} 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci/** 14248c2ecf20Sopenharmony_ci * netlbl_cache_add - Add an entry to a NetLabel protocol cache 14258c2ecf20Sopenharmony_ci * @skb: the packet 14268c2ecf20Sopenharmony_ci * @family: the family 14278c2ecf20Sopenharmony_ci * @secattr: the packet's security attributes 14288c2ecf20Sopenharmony_ci * 14298c2ecf20Sopenharmony_ci * Description: 14308c2ecf20Sopenharmony_ci * Add the LSM security attributes for the given packet to the underlying 14318c2ecf20Sopenharmony_ci * NetLabel protocol's label mapping cache. Returns zero on success, negative 14328c2ecf20Sopenharmony_ci * values on error. 14338c2ecf20Sopenharmony_ci * 14348c2ecf20Sopenharmony_ci */ 14358c2ecf20Sopenharmony_ciint netlbl_cache_add(const struct sk_buff *skb, u16 family, 14368c2ecf20Sopenharmony_ci const struct netlbl_lsm_secattr *secattr) 14378c2ecf20Sopenharmony_ci{ 14388c2ecf20Sopenharmony_ci unsigned char *ptr; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci if ((secattr->flags & NETLBL_SECATTR_CACHE) == 0) 14418c2ecf20Sopenharmony_ci return -ENOMSG; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci switch (family) { 14448c2ecf20Sopenharmony_ci case AF_INET: 14458c2ecf20Sopenharmony_ci ptr = cipso_v4_optptr(skb); 14468c2ecf20Sopenharmony_ci if (ptr) 14478c2ecf20Sopenharmony_ci return cipso_v4_cache_add(ptr, secattr); 14488c2ecf20Sopenharmony_ci break; 14498c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 14508c2ecf20Sopenharmony_ci case AF_INET6: 14518c2ecf20Sopenharmony_ci ptr = calipso_optptr(skb); 14528c2ecf20Sopenharmony_ci if (ptr) 14538c2ecf20Sopenharmony_ci return calipso_cache_add(ptr, secattr); 14548c2ecf20Sopenharmony_ci break; 14558c2ecf20Sopenharmony_ci#endif /* IPv6 */ 14568c2ecf20Sopenharmony_ci } 14578c2ecf20Sopenharmony_ci return -ENOMSG; 14588c2ecf20Sopenharmony_ci} 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci/* 14618c2ecf20Sopenharmony_ci * Protocol Engine Functions 14628c2ecf20Sopenharmony_ci */ 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci/** 14658c2ecf20Sopenharmony_ci * netlbl_audit_start - Start an audit message 14668c2ecf20Sopenharmony_ci * @type: audit message type 14678c2ecf20Sopenharmony_ci * @audit_info: NetLabel audit information 14688c2ecf20Sopenharmony_ci * 14698c2ecf20Sopenharmony_ci * Description: 14708c2ecf20Sopenharmony_ci * Start an audit message using the type specified in @type and fill the audit 14718c2ecf20Sopenharmony_ci * message with some fields common to all NetLabel audit messages. This 14728c2ecf20Sopenharmony_ci * function should only be used by protocol engines, not LSMs. Returns a 14738c2ecf20Sopenharmony_ci * pointer to the audit buffer on success, NULL on failure. 14748c2ecf20Sopenharmony_ci * 14758c2ecf20Sopenharmony_ci */ 14768c2ecf20Sopenharmony_cistruct audit_buffer *netlbl_audit_start(int type, 14778c2ecf20Sopenharmony_ci struct netlbl_audit *audit_info) 14788c2ecf20Sopenharmony_ci{ 14798c2ecf20Sopenharmony_ci return netlbl_audit_start_common(type, audit_info); 14808c2ecf20Sopenharmony_ci} 14818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(netlbl_audit_start); 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci/* 14848c2ecf20Sopenharmony_ci * Setup Functions 14858c2ecf20Sopenharmony_ci */ 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci/** 14888c2ecf20Sopenharmony_ci * netlbl_init - Initialize NetLabel 14898c2ecf20Sopenharmony_ci * 14908c2ecf20Sopenharmony_ci * Description: 14918c2ecf20Sopenharmony_ci * Perform the required NetLabel initialization before first use. 14928c2ecf20Sopenharmony_ci * 14938c2ecf20Sopenharmony_ci */ 14948c2ecf20Sopenharmony_cistatic int __init netlbl_init(void) 14958c2ecf20Sopenharmony_ci{ 14968c2ecf20Sopenharmony_ci int ret_val; 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci printk(KERN_INFO "NetLabel: Initializing\n"); 14998c2ecf20Sopenharmony_ci printk(KERN_INFO "NetLabel: domain hash size = %u\n", 15008c2ecf20Sopenharmony_ci (1 << NETLBL_DOMHSH_BITSIZE)); 15018c2ecf20Sopenharmony_ci printk(KERN_INFO "NetLabel: protocols = UNLABELED CIPSOv4 CALIPSO\n"); 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci ret_val = netlbl_domhsh_init(NETLBL_DOMHSH_BITSIZE); 15048c2ecf20Sopenharmony_ci if (ret_val != 0) 15058c2ecf20Sopenharmony_ci goto init_failure; 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci ret_val = netlbl_unlabel_init(NETLBL_UNLHSH_BITSIZE); 15088c2ecf20Sopenharmony_ci if (ret_val != 0) 15098c2ecf20Sopenharmony_ci goto init_failure; 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci ret_val = netlbl_netlink_init(); 15128c2ecf20Sopenharmony_ci if (ret_val != 0) 15138c2ecf20Sopenharmony_ci goto init_failure; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci ret_val = netlbl_unlabel_defconf(); 15168c2ecf20Sopenharmony_ci if (ret_val != 0) 15178c2ecf20Sopenharmony_ci goto init_failure; 15188c2ecf20Sopenharmony_ci printk(KERN_INFO "NetLabel: unlabeled traffic allowed by default\n"); 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci return 0; 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ciinit_failure: 15238c2ecf20Sopenharmony_ci panic("NetLabel: failed to initialize properly (%d)\n", ret_val); 15248c2ecf20Sopenharmony_ci} 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_cisubsys_initcall(netlbl_init); 1527