18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * NetLabel Unlabeled Support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This file defines functions for dealing with unlabeled packets for the 68c2ecf20Sopenharmony_ci * NetLabel system. The NetLabel system manages static and dynamic label 78c2ecf20Sopenharmony_ci * mappings for network protocols such 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/types.h> 178c2ecf20Sopenharmony_ci#include <linux/rcupdate.h> 188c2ecf20Sopenharmony_ci#include <linux/list.h> 198c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 208c2ecf20Sopenharmony_ci#include <linux/socket.h> 218c2ecf20Sopenharmony_ci#include <linux/string.h> 228c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 238c2ecf20Sopenharmony_ci#include <linux/audit.h> 248c2ecf20Sopenharmony_ci#include <linux/in.h> 258c2ecf20Sopenharmony_ci#include <linux/in6.h> 268c2ecf20Sopenharmony_ci#include <linux/ip.h> 278c2ecf20Sopenharmony_ci#include <linux/ipv6.h> 288c2ecf20Sopenharmony_ci#include <linux/notifier.h> 298c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 308c2ecf20Sopenharmony_ci#include <linux/security.h> 318c2ecf20Sopenharmony_ci#include <linux/slab.h> 328c2ecf20Sopenharmony_ci#include <net/sock.h> 338c2ecf20Sopenharmony_ci#include <net/netlink.h> 348c2ecf20Sopenharmony_ci#include <net/genetlink.h> 358c2ecf20Sopenharmony_ci#include <net/ip.h> 368c2ecf20Sopenharmony_ci#include <net/ipv6.h> 378c2ecf20Sopenharmony_ci#include <net/net_namespace.h> 388c2ecf20Sopenharmony_ci#include <net/netlabel.h> 398c2ecf20Sopenharmony_ci#include <asm/bug.h> 408c2ecf20Sopenharmony_ci#include <linux/atomic.h> 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#include "netlabel_user.h" 438c2ecf20Sopenharmony_ci#include "netlabel_addrlist.h" 448c2ecf20Sopenharmony_ci#include "netlabel_domainhash.h" 458c2ecf20Sopenharmony_ci#include "netlabel_unlabeled.h" 468c2ecf20Sopenharmony_ci#include "netlabel_mgmt.h" 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* NOTE: at present we always use init's network namespace since we don't 498c2ecf20Sopenharmony_ci * presently support different namespaces even though the majority of 508c2ecf20Sopenharmony_ci * the functions in this file are "namespace safe" */ 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* The unlabeled connection hash table which we use to map network interfaces 538c2ecf20Sopenharmony_ci * and addresses of unlabeled packets to a user specified secid value for the 548c2ecf20Sopenharmony_ci * LSM. The hash table is used to lookup the network interface entry 558c2ecf20Sopenharmony_ci * (struct netlbl_unlhsh_iface) and then the interface entry is used to 568c2ecf20Sopenharmony_ci * lookup an IP address match from an ordered list. If a network interface 578c2ecf20Sopenharmony_ci * match can not be found in the hash table then the default entry 588c2ecf20Sopenharmony_ci * (netlbl_unlhsh_def) is used. The IP address entry list 598c2ecf20Sopenharmony_ci * (struct netlbl_unlhsh_addr) is ordered such that the entries with a 608c2ecf20Sopenharmony_ci * larger netmask come first. 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_cistruct netlbl_unlhsh_tbl { 638c2ecf20Sopenharmony_ci struct list_head *tbl; 648c2ecf20Sopenharmony_ci u32 size; 658c2ecf20Sopenharmony_ci}; 668c2ecf20Sopenharmony_ci#define netlbl_unlhsh_addr4_entry(iter) \ 678c2ecf20Sopenharmony_ci container_of(iter, struct netlbl_unlhsh_addr4, list) 688c2ecf20Sopenharmony_cistruct netlbl_unlhsh_addr4 { 698c2ecf20Sopenharmony_ci u32 secid; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci struct netlbl_af4list list; 728c2ecf20Sopenharmony_ci struct rcu_head rcu; 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci#define netlbl_unlhsh_addr6_entry(iter) \ 758c2ecf20Sopenharmony_ci container_of(iter, struct netlbl_unlhsh_addr6, list) 768c2ecf20Sopenharmony_cistruct netlbl_unlhsh_addr6 { 778c2ecf20Sopenharmony_ci u32 secid; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci struct netlbl_af6list list; 808c2ecf20Sopenharmony_ci struct rcu_head rcu; 818c2ecf20Sopenharmony_ci}; 828c2ecf20Sopenharmony_cistruct netlbl_unlhsh_iface { 838c2ecf20Sopenharmony_ci int ifindex; 848c2ecf20Sopenharmony_ci struct list_head addr4_list; 858c2ecf20Sopenharmony_ci struct list_head addr6_list; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci u32 valid; 888c2ecf20Sopenharmony_ci struct list_head list; 898c2ecf20Sopenharmony_ci struct rcu_head rcu; 908c2ecf20Sopenharmony_ci}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* Argument struct for netlbl_unlhsh_walk() */ 938c2ecf20Sopenharmony_cistruct netlbl_unlhsh_walk_arg { 948c2ecf20Sopenharmony_ci struct netlink_callback *nl_cb; 958c2ecf20Sopenharmony_ci struct sk_buff *skb; 968c2ecf20Sopenharmony_ci u32 seq; 978c2ecf20Sopenharmony_ci}; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* Unlabeled connection hash table */ 1008c2ecf20Sopenharmony_ci/* updates should be so rare that having one spinlock for the entire 1018c2ecf20Sopenharmony_ci * hash table should be okay */ 1028c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(netlbl_unlhsh_lock); 1038c2ecf20Sopenharmony_ci#define netlbl_unlhsh_rcu_deref(p) \ 1048c2ecf20Sopenharmony_ci rcu_dereference_check(p, lockdep_is_held(&netlbl_unlhsh_lock)) 1058c2ecf20Sopenharmony_cistatic struct netlbl_unlhsh_tbl __rcu *netlbl_unlhsh; 1068c2ecf20Sopenharmony_cistatic struct netlbl_unlhsh_iface __rcu *netlbl_unlhsh_def; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci/* Accept unlabeled packets flag */ 1098c2ecf20Sopenharmony_cistatic u8 netlabel_unlabel_acceptflg; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci/* NetLabel Generic NETLINK unlabeled family */ 1128c2ecf20Sopenharmony_cistatic struct genl_family netlbl_unlabel_gnl_family; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/* NetLabel Netlink attribute policy */ 1158c2ecf20Sopenharmony_cistatic const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = { 1168c2ecf20Sopenharmony_ci [NLBL_UNLABEL_A_ACPTFLG] = { .type = NLA_U8 }, 1178c2ecf20Sopenharmony_ci [NLBL_UNLABEL_A_IPV6ADDR] = { .type = NLA_BINARY, 1188c2ecf20Sopenharmony_ci .len = sizeof(struct in6_addr) }, 1198c2ecf20Sopenharmony_ci [NLBL_UNLABEL_A_IPV6MASK] = { .type = NLA_BINARY, 1208c2ecf20Sopenharmony_ci .len = sizeof(struct in6_addr) }, 1218c2ecf20Sopenharmony_ci [NLBL_UNLABEL_A_IPV4ADDR] = { .type = NLA_BINARY, 1228c2ecf20Sopenharmony_ci .len = sizeof(struct in_addr) }, 1238c2ecf20Sopenharmony_ci [NLBL_UNLABEL_A_IPV4MASK] = { .type = NLA_BINARY, 1248c2ecf20Sopenharmony_ci .len = sizeof(struct in_addr) }, 1258c2ecf20Sopenharmony_ci [NLBL_UNLABEL_A_IFACE] = { .type = NLA_NUL_STRING, 1268c2ecf20Sopenharmony_ci .len = IFNAMSIZ - 1 }, 1278c2ecf20Sopenharmony_ci [NLBL_UNLABEL_A_SECCTX] = { .type = NLA_BINARY } 1288c2ecf20Sopenharmony_ci}; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* 1318c2ecf20Sopenharmony_ci * Unlabeled Connection Hash Table Functions 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci/** 1358c2ecf20Sopenharmony_ci * netlbl_unlhsh_free_iface - Frees an interface entry from the hash table 1368c2ecf20Sopenharmony_ci * @entry: the entry's RCU field 1378c2ecf20Sopenharmony_ci * 1388c2ecf20Sopenharmony_ci * Description: 1398c2ecf20Sopenharmony_ci * This function is designed to be used as a callback to the call_rcu() 1408c2ecf20Sopenharmony_ci * function so that memory allocated to a hash table interface entry can be 1418c2ecf20Sopenharmony_ci * released safely. It is important to note that this function does not free 1428c2ecf20Sopenharmony_ci * the IPv4 and IPv6 address lists contained as part of an interface entry. It 1438c2ecf20Sopenharmony_ci * is up to the rest of the code to make sure an interface entry is only freed 1448c2ecf20Sopenharmony_ci * once it's address lists are empty. 1458c2ecf20Sopenharmony_ci * 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_cistatic void netlbl_unlhsh_free_iface(struct rcu_head *entry) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct netlbl_unlhsh_iface *iface; 1508c2ecf20Sopenharmony_ci struct netlbl_af4list *iter4; 1518c2ecf20Sopenharmony_ci struct netlbl_af4list *tmp4; 1528c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 1538c2ecf20Sopenharmony_ci struct netlbl_af6list *iter6; 1548c2ecf20Sopenharmony_ci struct netlbl_af6list *tmp6; 1558c2ecf20Sopenharmony_ci#endif /* IPv6 */ 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci iface = container_of(entry, struct netlbl_unlhsh_iface, rcu); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* no need for locks here since we are the only one with access to this 1608c2ecf20Sopenharmony_ci * structure */ 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci netlbl_af4list_foreach_safe(iter4, tmp4, &iface->addr4_list) { 1638c2ecf20Sopenharmony_ci netlbl_af4list_remove_entry(iter4); 1648c2ecf20Sopenharmony_ci kfree(netlbl_unlhsh_addr4_entry(iter4)); 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 1678c2ecf20Sopenharmony_ci netlbl_af6list_foreach_safe(iter6, tmp6, &iface->addr6_list) { 1688c2ecf20Sopenharmony_ci netlbl_af6list_remove_entry(iter6); 1698c2ecf20Sopenharmony_ci kfree(netlbl_unlhsh_addr6_entry(iter6)); 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci#endif /* IPv6 */ 1728c2ecf20Sopenharmony_ci kfree(iface); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/** 1768c2ecf20Sopenharmony_ci * netlbl_unlhsh_hash - Hashing function for the hash table 1778c2ecf20Sopenharmony_ci * @ifindex: the network interface/device to hash 1788c2ecf20Sopenharmony_ci * 1798c2ecf20Sopenharmony_ci * Description: 1808c2ecf20Sopenharmony_ci * This is the hashing function for the unlabeled hash table, it returns the 1818c2ecf20Sopenharmony_ci * bucket number for the given device/interface. The caller is responsible for 1828c2ecf20Sopenharmony_ci * ensuring that the hash table is protected with either a RCU read lock or 1838c2ecf20Sopenharmony_ci * the hash table lock. 1848c2ecf20Sopenharmony_ci * 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_cistatic u32 netlbl_unlhsh_hash(int ifindex) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci return ifindex & (netlbl_unlhsh_rcu_deref(netlbl_unlhsh)->size - 1); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci/** 1928c2ecf20Sopenharmony_ci * netlbl_unlhsh_search_iface - Search for a matching interface entry 1938c2ecf20Sopenharmony_ci * @ifindex: the network interface 1948c2ecf20Sopenharmony_ci * 1958c2ecf20Sopenharmony_ci * Description: 1968c2ecf20Sopenharmony_ci * Searches the unlabeled connection hash table and returns a pointer to the 1978c2ecf20Sopenharmony_ci * interface entry which matches @ifindex, otherwise NULL is returned. The 1988c2ecf20Sopenharmony_ci * caller is responsible for ensuring that the hash table is protected with 1998c2ecf20Sopenharmony_ci * either a RCU read lock or the hash table lock. 2008c2ecf20Sopenharmony_ci * 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_cistatic struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci u32 bkt; 2058c2ecf20Sopenharmony_ci struct list_head *bkt_list; 2068c2ecf20Sopenharmony_ci struct netlbl_unlhsh_iface *iter; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci bkt = netlbl_unlhsh_hash(ifindex); 2098c2ecf20Sopenharmony_ci bkt_list = &netlbl_unlhsh_rcu_deref(netlbl_unlhsh)->tbl[bkt]; 2108c2ecf20Sopenharmony_ci list_for_each_entry_rcu(iter, bkt_list, list, 2118c2ecf20Sopenharmony_ci lockdep_is_held(&netlbl_unlhsh_lock)) 2128c2ecf20Sopenharmony_ci if (iter->valid && iter->ifindex == ifindex) 2138c2ecf20Sopenharmony_ci return iter; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci return NULL; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci/** 2198c2ecf20Sopenharmony_ci * netlbl_unlhsh_add_addr4 - Add a new IPv4 address entry to the hash table 2208c2ecf20Sopenharmony_ci * @iface: the associated interface entry 2218c2ecf20Sopenharmony_ci * @addr: IPv4 address in network byte order 2228c2ecf20Sopenharmony_ci * @mask: IPv4 address mask in network byte order 2238c2ecf20Sopenharmony_ci * @secid: LSM secid value for entry 2248c2ecf20Sopenharmony_ci * 2258c2ecf20Sopenharmony_ci * Description: 2268c2ecf20Sopenharmony_ci * Add a new address entry into the unlabeled connection hash table using the 2278c2ecf20Sopenharmony_ci * interface entry specified by @iface. On success zero is returned, otherwise 2288c2ecf20Sopenharmony_ci * a negative value is returned. 2298c2ecf20Sopenharmony_ci * 2308c2ecf20Sopenharmony_ci */ 2318c2ecf20Sopenharmony_cistatic int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface, 2328c2ecf20Sopenharmony_ci const struct in_addr *addr, 2338c2ecf20Sopenharmony_ci const struct in_addr *mask, 2348c2ecf20Sopenharmony_ci u32 secid) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci int ret_val; 2378c2ecf20Sopenharmony_ci struct netlbl_unlhsh_addr4 *entry; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 2408c2ecf20Sopenharmony_ci if (entry == NULL) 2418c2ecf20Sopenharmony_ci return -ENOMEM; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci entry->list.addr = addr->s_addr & mask->s_addr; 2448c2ecf20Sopenharmony_ci entry->list.mask = mask->s_addr; 2458c2ecf20Sopenharmony_ci entry->list.valid = 1; 2468c2ecf20Sopenharmony_ci entry->secid = secid; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci spin_lock(&netlbl_unlhsh_lock); 2498c2ecf20Sopenharmony_ci ret_val = netlbl_af4list_add(&entry->list, &iface->addr4_list); 2508c2ecf20Sopenharmony_ci spin_unlock(&netlbl_unlhsh_lock); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci if (ret_val != 0) 2538c2ecf20Sopenharmony_ci kfree(entry); 2548c2ecf20Sopenharmony_ci return ret_val; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 2588c2ecf20Sopenharmony_ci/** 2598c2ecf20Sopenharmony_ci * netlbl_unlhsh_add_addr6 - Add a new IPv6 address entry to the hash table 2608c2ecf20Sopenharmony_ci * @iface: the associated interface entry 2618c2ecf20Sopenharmony_ci * @addr: IPv6 address in network byte order 2628c2ecf20Sopenharmony_ci * @mask: IPv6 address mask in network byte order 2638c2ecf20Sopenharmony_ci * @secid: LSM secid value for entry 2648c2ecf20Sopenharmony_ci * 2658c2ecf20Sopenharmony_ci * Description: 2668c2ecf20Sopenharmony_ci * Add a new address entry into the unlabeled connection hash table using the 2678c2ecf20Sopenharmony_ci * interface entry specified by @iface. On success zero is returned, otherwise 2688c2ecf20Sopenharmony_ci * a negative value is returned. 2698c2ecf20Sopenharmony_ci * 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_cistatic int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface, 2728c2ecf20Sopenharmony_ci const struct in6_addr *addr, 2738c2ecf20Sopenharmony_ci const struct in6_addr *mask, 2748c2ecf20Sopenharmony_ci u32 secid) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci int ret_val; 2778c2ecf20Sopenharmony_ci struct netlbl_unlhsh_addr6 *entry; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 2808c2ecf20Sopenharmony_ci if (entry == NULL) 2818c2ecf20Sopenharmony_ci return -ENOMEM; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci entry->list.addr = *addr; 2848c2ecf20Sopenharmony_ci entry->list.addr.s6_addr32[0] &= mask->s6_addr32[0]; 2858c2ecf20Sopenharmony_ci entry->list.addr.s6_addr32[1] &= mask->s6_addr32[1]; 2868c2ecf20Sopenharmony_ci entry->list.addr.s6_addr32[2] &= mask->s6_addr32[2]; 2878c2ecf20Sopenharmony_ci entry->list.addr.s6_addr32[3] &= mask->s6_addr32[3]; 2888c2ecf20Sopenharmony_ci entry->list.mask = *mask; 2898c2ecf20Sopenharmony_ci entry->list.valid = 1; 2908c2ecf20Sopenharmony_ci entry->secid = secid; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci spin_lock(&netlbl_unlhsh_lock); 2938c2ecf20Sopenharmony_ci ret_val = netlbl_af6list_add(&entry->list, &iface->addr6_list); 2948c2ecf20Sopenharmony_ci spin_unlock(&netlbl_unlhsh_lock); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (ret_val != 0) 2978c2ecf20Sopenharmony_ci kfree(entry); 2988c2ecf20Sopenharmony_ci return 0; 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci#endif /* IPv6 */ 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci/** 3038c2ecf20Sopenharmony_ci * netlbl_unlhsh_add_iface - Adds a new interface entry to the hash table 3048c2ecf20Sopenharmony_ci * @ifindex: network interface 3058c2ecf20Sopenharmony_ci * 3068c2ecf20Sopenharmony_ci * Description: 3078c2ecf20Sopenharmony_ci * Add a new, empty, interface entry into the unlabeled connection hash table. 3088c2ecf20Sopenharmony_ci * On success a pointer to the new interface entry is returned, on failure NULL 3098c2ecf20Sopenharmony_ci * is returned. 3108c2ecf20Sopenharmony_ci * 3118c2ecf20Sopenharmony_ci */ 3128c2ecf20Sopenharmony_cistatic struct netlbl_unlhsh_iface *netlbl_unlhsh_add_iface(int ifindex) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci u32 bkt; 3158c2ecf20Sopenharmony_ci struct netlbl_unlhsh_iface *iface; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci iface = kzalloc(sizeof(*iface), GFP_ATOMIC); 3188c2ecf20Sopenharmony_ci if (iface == NULL) 3198c2ecf20Sopenharmony_ci return NULL; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci iface->ifindex = ifindex; 3228c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&iface->addr4_list); 3238c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&iface->addr6_list); 3248c2ecf20Sopenharmony_ci iface->valid = 1; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci spin_lock(&netlbl_unlhsh_lock); 3278c2ecf20Sopenharmony_ci if (ifindex > 0) { 3288c2ecf20Sopenharmony_ci bkt = netlbl_unlhsh_hash(ifindex); 3298c2ecf20Sopenharmony_ci if (netlbl_unlhsh_search_iface(ifindex) != NULL) 3308c2ecf20Sopenharmony_ci goto add_iface_failure; 3318c2ecf20Sopenharmony_ci list_add_tail_rcu(&iface->list, 3328c2ecf20Sopenharmony_ci &netlbl_unlhsh_rcu_deref(netlbl_unlhsh)->tbl[bkt]); 3338c2ecf20Sopenharmony_ci } else { 3348c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&iface->list); 3358c2ecf20Sopenharmony_ci if (netlbl_unlhsh_rcu_deref(netlbl_unlhsh_def) != NULL) 3368c2ecf20Sopenharmony_ci goto add_iface_failure; 3378c2ecf20Sopenharmony_ci rcu_assign_pointer(netlbl_unlhsh_def, iface); 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci spin_unlock(&netlbl_unlhsh_lock); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci return iface; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ciadd_iface_failure: 3448c2ecf20Sopenharmony_ci spin_unlock(&netlbl_unlhsh_lock); 3458c2ecf20Sopenharmony_ci kfree(iface); 3468c2ecf20Sopenharmony_ci return NULL; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci/** 3508c2ecf20Sopenharmony_ci * netlbl_unlhsh_add - Adds a new entry to the unlabeled connection hash table 3518c2ecf20Sopenharmony_ci * @net: network namespace 3528c2ecf20Sopenharmony_ci * @dev_name: interface name 3538c2ecf20Sopenharmony_ci * @addr: IP address in network byte order 3548c2ecf20Sopenharmony_ci * @mask: address mask in network byte order 3558c2ecf20Sopenharmony_ci * @addr_len: length of address/mask (4 for IPv4, 16 for IPv6) 3568c2ecf20Sopenharmony_ci * @secid: LSM secid value for the entry 3578c2ecf20Sopenharmony_ci * @audit_info: NetLabel audit information 3588c2ecf20Sopenharmony_ci * 3598c2ecf20Sopenharmony_ci * Description: 3608c2ecf20Sopenharmony_ci * Adds a new entry to the unlabeled connection hash table. Returns zero on 3618c2ecf20Sopenharmony_ci * success, negative values on failure. 3628c2ecf20Sopenharmony_ci * 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_ciint netlbl_unlhsh_add(struct net *net, 3658c2ecf20Sopenharmony_ci const char *dev_name, 3668c2ecf20Sopenharmony_ci const void *addr, 3678c2ecf20Sopenharmony_ci const void *mask, 3688c2ecf20Sopenharmony_ci u32 addr_len, 3698c2ecf20Sopenharmony_ci u32 secid, 3708c2ecf20Sopenharmony_ci struct netlbl_audit *audit_info) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci int ret_val; 3738c2ecf20Sopenharmony_ci int ifindex; 3748c2ecf20Sopenharmony_ci struct net_device *dev; 3758c2ecf20Sopenharmony_ci struct netlbl_unlhsh_iface *iface; 3768c2ecf20Sopenharmony_ci struct audit_buffer *audit_buf = NULL; 3778c2ecf20Sopenharmony_ci char *secctx = NULL; 3788c2ecf20Sopenharmony_ci u32 secctx_len; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if (addr_len != sizeof(struct in_addr) && 3818c2ecf20Sopenharmony_ci addr_len != sizeof(struct in6_addr)) 3828c2ecf20Sopenharmony_ci return -EINVAL; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci rcu_read_lock(); 3858c2ecf20Sopenharmony_ci if (dev_name != NULL) { 3868c2ecf20Sopenharmony_ci dev = dev_get_by_name_rcu(net, dev_name); 3878c2ecf20Sopenharmony_ci if (dev == NULL) { 3888c2ecf20Sopenharmony_ci ret_val = -ENODEV; 3898c2ecf20Sopenharmony_ci goto unlhsh_add_return; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci ifindex = dev->ifindex; 3928c2ecf20Sopenharmony_ci iface = netlbl_unlhsh_search_iface(ifindex); 3938c2ecf20Sopenharmony_ci } else { 3948c2ecf20Sopenharmony_ci ifindex = 0; 3958c2ecf20Sopenharmony_ci iface = rcu_dereference(netlbl_unlhsh_def); 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci if (iface == NULL) { 3988c2ecf20Sopenharmony_ci iface = netlbl_unlhsh_add_iface(ifindex); 3998c2ecf20Sopenharmony_ci if (iface == NULL) { 4008c2ecf20Sopenharmony_ci ret_val = -ENOMEM; 4018c2ecf20Sopenharmony_ci goto unlhsh_add_return; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCADD, 4058c2ecf20Sopenharmony_ci audit_info); 4068c2ecf20Sopenharmony_ci switch (addr_len) { 4078c2ecf20Sopenharmony_ci case sizeof(struct in_addr): { 4088c2ecf20Sopenharmony_ci const struct in_addr *addr4 = addr; 4098c2ecf20Sopenharmony_ci const struct in_addr *mask4 = mask; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci ret_val = netlbl_unlhsh_add_addr4(iface, addr4, mask4, secid); 4128c2ecf20Sopenharmony_ci if (audit_buf != NULL) 4138c2ecf20Sopenharmony_ci netlbl_af4list_audit_addr(audit_buf, 1, 4148c2ecf20Sopenharmony_ci dev_name, 4158c2ecf20Sopenharmony_ci addr4->s_addr, 4168c2ecf20Sopenharmony_ci mask4->s_addr); 4178c2ecf20Sopenharmony_ci break; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 4208c2ecf20Sopenharmony_ci case sizeof(struct in6_addr): { 4218c2ecf20Sopenharmony_ci const struct in6_addr *addr6 = addr; 4228c2ecf20Sopenharmony_ci const struct in6_addr *mask6 = mask; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci ret_val = netlbl_unlhsh_add_addr6(iface, addr6, mask6, secid); 4258c2ecf20Sopenharmony_ci if (audit_buf != NULL) 4268c2ecf20Sopenharmony_ci netlbl_af6list_audit_addr(audit_buf, 1, 4278c2ecf20Sopenharmony_ci dev_name, 4288c2ecf20Sopenharmony_ci addr6, mask6); 4298c2ecf20Sopenharmony_ci break; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci#endif /* IPv6 */ 4328c2ecf20Sopenharmony_ci default: 4338c2ecf20Sopenharmony_ci ret_val = -EINVAL; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci if (ret_val == 0) 4368c2ecf20Sopenharmony_ci atomic_inc(&netlabel_mgmt_protocount); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ciunlhsh_add_return: 4398c2ecf20Sopenharmony_ci rcu_read_unlock(); 4408c2ecf20Sopenharmony_ci if (audit_buf != NULL) { 4418c2ecf20Sopenharmony_ci if (security_secid_to_secctx(secid, 4428c2ecf20Sopenharmony_ci &secctx, 4438c2ecf20Sopenharmony_ci &secctx_len) == 0) { 4448c2ecf20Sopenharmony_ci audit_log_format(audit_buf, " sec_obj=%s", secctx); 4458c2ecf20Sopenharmony_ci security_release_secctx(secctx, secctx_len); 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0); 4488c2ecf20Sopenharmony_ci audit_log_end(audit_buf); 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci return ret_val; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci/** 4548c2ecf20Sopenharmony_ci * netlbl_unlhsh_remove_addr4 - Remove an IPv4 address entry 4558c2ecf20Sopenharmony_ci * @net: network namespace 4568c2ecf20Sopenharmony_ci * @iface: interface entry 4578c2ecf20Sopenharmony_ci * @addr: IP address 4588c2ecf20Sopenharmony_ci * @mask: IP address mask 4598c2ecf20Sopenharmony_ci * @audit_info: NetLabel audit information 4608c2ecf20Sopenharmony_ci * 4618c2ecf20Sopenharmony_ci * Description: 4628c2ecf20Sopenharmony_ci * Remove an IP address entry from the unlabeled connection hash table. 4638c2ecf20Sopenharmony_ci * Returns zero on success, negative values on failure. 4648c2ecf20Sopenharmony_ci * 4658c2ecf20Sopenharmony_ci */ 4668c2ecf20Sopenharmony_cistatic int netlbl_unlhsh_remove_addr4(struct net *net, 4678c2ecf20Sopenharmony_ci struct netlbl_unlhsh_iface *iface, 4688c2ecf20Sopenharmony_ci const struct in_addr *addr, 4698c2ecf20Sopenharmony_ci const struct in_addr *mask, 4708c2ecf20Sopenharmony_ci struct netlbl_audit *audit_info) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci struct netlbl_af4list *list_entry; 4738c2ecf20Sopenharmony_ci struct netlbl_unlhsh_addr4 *entry; 4748c2ecf20Sopenharmony_ci struct audit_buffer *audit_buf; 4758c2ecf20Sopenharmony_ci struct net_device *dev; 4768c2ecf20Sopenharmony_ci char *secctx; 4778c2ecf20Sopenharmony_ci u32 secctx_len; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci spin_lock(&netlbl_unlhsh_lock); 4808c2ecf20Sopenharmony_ci list_entry = netlbl_af4list_remove(addr->s_addr, mask->s_addr, 4818c2ecf20Sopenharmony_ci &iface->addr4_list); 4828c2ecf20Sopenharmony_ci spin_unlock(&netlbl_unlhsh_lock); 4838c2ecf20Sopenharmony_ci if (list_entry != NULL) 4848c2ecf20Sopenharmony_ci entry = netlbl_unlhsh_addr4_entry(list_entry); 4858c2ecf20Sopenharmony_ci else 4868c2ecf20Sopenharmony_ci entry = NULL; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL, 4898c2ecf20Sopenharmony_ci audit_info); 4908c2ecf20Sopenharmony_ci if (audit_buf != NULL) { 4918c2ecf20Sopenharmony_ci dev = dev_get_by_index(net, iface->ifindex); 4928c2ecf20Sopenharmony_ci netlbl_af4list_audit_addr(audit_buf, 1, 4938c2ecf20Sopenharmony_ci (dev != NULL ? dev->name : NULL), 4948c2ecf20Sopenharmony_ci addr->s_addr, mask->s_addr); 4958c2ecf20Sopenharmony_ci if (dev != NULL) 4968c2ecf20Sopenharmony_ci dev_put(dev); 4978c2ecf20Sopenharmony_ci if (entry != NULL && 4988c2ecf20Sopenharmony_ci security_secid_to_secctx(entry->secid, 4998c2ecf20Sopenharmony_ci &secctx, &secctx_len) == 0) { 5008c2ecf20Sopenharmony_ci audit_log_format(audit_buf, " sec_obj=%s", secctx); 5018c2ecf20Sopenharmony_ci security_release_secctx(secctx, secctx_len); 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci audit_log_format(audit_buf, " res=%u", entry != NULL ? 1 : 0); 5048c2ecf20Sopenharmony_ci audit_log_end(audit_buf); 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (entry == NULL) 5088c2ecf20Sopenharmony_ci return -ENOENT; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci kfree_rcu(entry, rcu); 5118c2ecf20Sopenharmony_ci return 0; 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 5158c2ecf20Sopenharmony_ci/** 5168c2ecf20Sopenharmony_ci * netlbl_unlhsh_remove_addr6 - Remove an IPv6 address entry 5178c2ecf20Sopenharmony_ci * @net: network namespace 5188c2ecf20Sopenharmony_ci * @iface: interface entry 5198c2ecf20Sopenharmony_ci * @addr: IP address 5208c2ecf20Sopenharmony_ci * @mask: IP address mask 5218c2ecf20Sopenharmony_ci * @audit_info: NetLabel audit information 5228c2ecf20Sopenharmony_ci * 5238c2ecf20Sopenharmony_ci * Description: 5248c2ecf20Sopenharmony_ci * Remove an IP address entry from the unlabeled connection hash table. 5258c2ecf20Sopenharmony_ci * Returns zero on success, negative values on failure. 5268c2ecf20Sopenharmony_ci * 5278c2ecf20Sopenharmony_ci */ 5288c2ecf20Sopenharmony_cistatic int netlbl_unlhsh_remove_addr6(struct net *net, 5298c2ecf20Sopenharmony_ci struct netlbl_unlhsh_iface *iface, 5308c2ecf20Sopenharmony_ci const struct in6_addr *addr, 5318c2ecf20Sopenharmony_ci const struct in6_addr *mask, 5328c2ecf20Sopenharmony_ci struct netlbl_audit *audit_info) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci struct netlbl_af6list *list_entry; 5358c2ecf20Sopenharmony_ci struct netlbl_unlhsh_addr6 *entry; 5368c2ecf20Sopenharmony_ci struct audit_buffer *audit_buf; 5378c2ecf20Sopenharmony_ci struct net_device *dev; 5388c2ecf20Sopenharmony_ci char *secctx; 5398c2ecf20Sopenharmony_ci u32 secctx_len; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci spin_lock(&netlbl_unlhsh_lock); 5428c2ecf20Sopenharmony_ci list_entry = netlbl_af6list_remove(addr, mask, &iface->addr6_list); 5438c2ecf20Sopenharmony_ci spin_unlock(&netlbl_unlhsh_lock); 5448c2ecf20Sopenharmony_ci if (list_entry != NULL) 5458c2ecf20Sopenharmony_ci entry = netlbl_unlhsh_addr6_entry(list_entry); 5468c2ecf20Sopenharmony_ci else 5478c2ecf20Sopenharmony_ci entry = NULL; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL, 5508c2ecf20Sopenharmony_ci audit_info); 5518c2ecf20Sopenharmony_ci if (audit_buf != NULL) { 5528c2ecf20Sopenharmony_ci dev = dev_get_by_index(net, iface->ifindex); 5538c2ecf20Sopenharmony_ci netlbl_af6list_audit_addr(audit_buf, 1, 5548c2ecf20Sopenharmony_ci (dev != NULL ? dev->name : NULL), 5558c2ecf20Sopenharmony_ci addr, mask); 5568c2ecf20Sopenharmony_ci if (dev != NULL) 5578c2ecf20Sopenharmony_ci dev_put(dev); 5588c2ecf20Sopenharmony_ci if (entry != NULL && 5598c2ecf20Sopenharmony_ci security_secid_to_secctx(entry->secid, 5608c2ecf20Sopenharmony_ci &secctx, &secctx_len) == 0) { 5618c2ecf20Sopenharmony_ci audit_log_format(audit_buf, " sec_obj=%s", secctx); 5628c2ecf20Sopenharmony_ci security_release_secctx(secctx, secctx_len); 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci audit_log_format(audit_buf, " res=%u", entry != NULL ? 1 : 0); 5658c2ecf20Sopenharmony_ci audit_log_end(audit_buf); 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci if (entry == NULL) 5698c2ecf20Sopenharmony_ci return -ENOENT; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci kfree_rcu(entry, rcu); 5728c2ecf20Sopenharmony_ci return 0; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci#endif /* IPv6 */ 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci/** 5778c2ecf20Sopenharmony_ci * netlbl_unlhsh_condremove_iface - Remove an interface entry 5788c2ecf20Sopenharmony_ci * @iface: the interface entry 5798c2ecf20Sopenharmony_ci * 5808c2ecf20Sopenharmony_ci * Description: 5818c2ecf20Sopenharmony_ci * Remove an interface entry from the unlabeled connection hash table if it is 5828c2ecf20Sopenharmony_ci * empty. An interface entry is considered to be empty if there are no 5838c2ecf20Sopenharmony_ci * address entries assigned to it. 5848c2ecf20Sopenharmony_ci * 5858c2ecf20Sopenharmony_ci */ 5868c2ecf20Sopenharmony_cistatic void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci struct netlbl_af4list *iter4; 5898c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 5908c2ecf20Sopenharmony_ci struct netlbl_af6list *iter6; 5918c2ecf20Sopenharmony_ci#endif /* IPv6 */ 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci spin_lock(&netlbl_unlhsh_lock); 5948c2ecf20Sopenharmony_ci netlbl_af4list_foreach_rcu(iter4, &iface->addr4_list) 5958c2ecf20Sopenharmony_ci goto unlhsh_condremove_failure; 5968c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 5978c2ecf20Sopenharmony_ci netlbl_af6list_foreach_rcu(iter6, &iface->addr6_list) 5988c2ecf20Sopenharmony_ci goto unlhsh_condremove_failure; 5998c2ecf20Sopenharmony_ci#endif /* IPv6 */ 6008c2ecf20Sopenharmony_ci iface->valid = 0; 6018c2ecf20Sopenharmony_ci if (iface->ifindex > 0) 6028c2ecf20Sopenharmony_ci list_del_rcu(&iface->list); 6038c2ecf20Sopenharmony_ci else 6048c2ecf20Sopenharmony_ci RCU_INIT_POINTER(netlbl_unlhsh_def, NULL); 6058c2ecf20Sopenharmony_ci spin_unlock(&netlbl_unlhsh_lock); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci call_rcu(&iface->rcu, netlbl_unlhsh_free_iface); 6088c2ecf20Sopenharmony_ci return; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ciunlhsh_condremove_failure: 6118c2ecf20Sopenharmony_ci spin_unlock(&netlbl_unlhsh_lock); 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci/** 6158c2ecf20Sopenharmony_ci * netlbl_unlhsh_remove - Remove an entry from the unlabeled hash table 6168c2ecf20Sopenharmony_ci * @net: network namespace 6178c2ecf20Sopenharmony_ci * @dev_name: interface name 6188c2ecf20Sopenharmony_ci * @addr: IP address in network byte order 6198c2ecf20Sopenharmony_ci * @mask: address mask in network byte order 6208c2ecf20Sopenharmony_ci * @addr_len: length of address/mask (4 for IPv4, 16 for IPv6) 6218c2ecf20Sopenharmony_ci * @audit_info: NetLabel audit information 6228c2ecf20Sopenharmony_ci * 6238c2ecf20Sopenharmony_ci * Description: 6248c2ecf20Sopenharmony_ci * Removes and existing entry from the unlabeled connection hash table. 6258c2ecf20Sopenharmony_ci * Returns zero on success, negative values on failure. 6268c2ecf20Sopenharmony_ci * 6278c2ecf20Sopenharmony_ci */ 6288c2ecf20Sopenharmony_ciint netlbl_unlhsh_remove(struct net *net, 6298c2ecf20Sopenharmony_ci const char *dev_name, 6308c2ecf20Sopenharmony_ci const void *addr, 6318c2ecf20Sopenharmony_ci const void *mask, 6328c2ecf20Sopenharmony_ci u32 addr_len, 6338c2ecf20Sopenharmony_ci struct netlbl_audit *audit_info) 6348c2ecf20Sopenharmony_ci{ 6358c2ecf20Sopenharmony_ci int ret_val; 6368c2ecf20Sopenharmony_ci struct net_device *dev; 6378c2ecf20Sopenharmony_ci struct netlbl_unlhsh_iface *iface; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci if (addr_len != sizeof(struct in_addr) && 6408c2ecf20Sopenharmony_ci addr_len != sizeof(struct in6_addr)) 6418c2ecf20Sopenharmony_ci return -EINVAL; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci rcu_read_lock(); 6448c2ecf20Sopenharmony_ci if (dev_name != NULL) { 6458c2ecf20Sopenharmony_ci dev = dev_get_by_name_rcu(net, dev_name); 6468c2ecf20Sopenharmony_ci if (dev == NULL) { 6478c2ecf20Sopenharmony_ci ret_val = -ENODEV; 6488c2ecf20Sopenharmony_ci goto unlhsh_remove_return; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci iface = netlbl_unlhsh_search_iface(dev->ifindex); 6518c2ecf20Sopenharmony_ci } else 6528c2ecf20Sopenharmony_ci iface = rcu_dereference(netlbl_unlhsh_def); 6538c2ecf20Sopenharmony_ci if (iface == NULL) { 6548c2ecf20Sopenharmony_ci ret_val = -ENOENT; 6558c2ecf20Sopenharmony_ci goto unlhsh_remove_return; 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci switch (addr_len) { 6588c2ecf20Sopenharmony_ci case sizeof(struct in_addr): 6598c2ecf20Sopenharmony_ci ret_val = netlbl_unlhsh_remove_addr4(net, 6608c2ecf20Sopenharmony_ci iface, addr, mask, 6618c2ecf20Sopenharmony_ci audit_info); 6628c2ecf20Sopenharmony_ci break; 6638c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 6648c2ecf20Sopenharmony_ci case sizeof(struct in6_addr): 6658c2ecf20Sopenharmony_ci ret_val = netlbl_unlhsh_remove_addr6(net, 6668c2ecf20Sopenharmony_ci iface, addr, mask, 6678c2ecf20Sopenharmony_ci audit_info); 6688c2ecf20Sopenharmony_ci break; 6698c2ecf20Sopenharmony_ci#endif /* IPv6 */ 6708c2ecf20Sopenharmony_ci default: 6718c2ecf20Sopenharmony_ci ret_val = -EINVAL; 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci if (ret_val == 0) { 6748c2ecf20Sopenharmony_ci netlbl_unlhsh_condremove_iface(iface); 6758c2ecf20Sopenharmony_ci atomic_dec(&netlabel_mgmt_protocount); 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ciunlhsh_remove_return: 6798c2ecf20Sopenharmony_ci rcu_read_unlock(); 6808c2ecf20Sopenharmony_ci return ret_val; 6818c2ecf20Sopenharmony_ci} 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci/* 6848c2ecf20Sopenharmony_ci * General Helper Functions 6858c2ecf20Sopenharmony_ci */ 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci/** 6888c2ecf20Sopenharmony_ci * netlbl_unlhsh_netdev_handler - Network device notification handler 6898c2ecf20Sopenharmony_ci * @this: notifier block 6908c2ecf20Sopenharmony_ci * @event: the event 6918c2ecf20Sopenharmony_ci * @ptr: the netdevice notifier info (cast to void) 6928c2ecf20Sopenharmony_ci * 6938c2ecf20Sopenharmony_ci * Description: 6948c2ecf20Sopenharmony_ci * Handle network device events, although at present all we care about is a 6958c2ecf20Sopenharmony_ci * network device going away. In the case of a device going away we clear any 6968c2ecf20Sopenharmony_ci * related entries from the unlabeled connection hash table. 6978c2ecf20Sopenharmony_ci * 6988c2ecf20Sopenharmony_ci */ 6998c2ecf20Sopenharmony_cistatic int netlbl_unlhsh_netdev_handler(struct notifier_block *this, 7008c2ecf20Sopenharmony_ci unsigned long event, void *ptr) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci struct net_device *dev = netdev_notifier_info_to_dev(ptr); 7038c2ecf20Sopenharmony_ci struct netlbl_unlhsh_iface *iface = NULL; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci if (!net_eq(dev_net(dev), &init_net)) 7068c2ecf20Sopenharmony_ci return NOTIFY_DONE; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci /* XXX - should this be a check for NETDEV_DOWN or _UNREGISTER? */ 7098c2ecf20Sopenharmony_ci if (event == NETDEV_DOWN) { 7108c2ecf20Sopenharmony_ci spin_lock(&netlbl_unlhsh_lock); 7118c2ecf20Sopenharmony_ci iface = netlbl_unlhsh_search_iface(dev->ifindex); 7128c2ecf20Sopenharmony_ci if (iface != NULL && iface->valid) { 7138c2ecf20Sopenharmony_ci iface->valid = 0; 7148c2ecf20Sopenharmony_ci list_del_rcu(&iface->list); 7158c2ecf20Sopenharmony_ci } else 7168c2ecf20Sopenharmony_ci iface = NULL; 7178c2ecf20Sopenharmony_ci spin_unlock(&netlbl_unlhsh_lock); 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci if (iface != NULL) 7218c2ecf20Sopenharmony_ci call_rcu(&iface->rcu, netlbl_unlhsh_free_iface); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci return NOTIFY_DONE; 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci/** 7278c2ecf20Sopenharmony_ci * netlbl_unlabel_acceptflg_set - Set the unlabeled accept flag 7288c2ecf20Sopenharmony_ci * @value: desired value 7298c2ecf20Sopenharmony_ci * @audit_info: NetLabel audit information 7308c2ecf20Sopenharmony_ci * 7318c2ecf20Sopenharmony_ci * Description: 7328c2ecf20Sopenharmony_ci * Set the value of the unlabeled accept flag to @value. 7338c2ecf20Sopenharmony_ci * 7348c2ecf20Sopenharmony_ci */ 7358c2ecf20Sopenharmony_cistatic void netlbl_unlabel_acceptflg_set(u8 value, 7368c2ecf20Sopenharmony_ci struct netlbl_audit *audit_info) 7378c2ecf20Sopenharmony_ci{ 7388c2ecf20Sopenharmony_ci struct audit_buffer *audit_buf; 7398c2ecf20Sopenharmony_ci u8 old_val; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci old_val = netlabel_unlabel_acceptflg; 7428c2ecf20Sopenharmony_ci netlabel_unlabel_acceptflg = value; 7438c2ecf20Sopenharmony_ci audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_ALLOW, 7448c2ecf20Sopenharmony_ci audit_info); 7458c2ecf20Sopenharmony_ci if (audit_buf != NULL) { 7468c2ecf20Sopenharmony_ci audit_log_format(audit_buf, 7478c2ecf20Sopenharmony_ci " unlbl_accept=%u old=%u", value, old_val); 7488c2ecf20Sopenharmony_ci audit_log_end(audit_buf); 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci} 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci/** 7538c2ecf20Sopenharmony_ci * netlbl_unlabel_addrinfo_get - Get the IPv4/6 address information 7548c2ecf20Sopenharmony_ci * @info: the Generic NETLINK info block 7558c2ecf20Sopenharmony_ci * @addr: the IP address 7568c2ecf20Sopenharmony_ci * @mask: the IP address mask 7578c2ecf20Sopenharmony_ci * @len: the address length 7588c2ecf20Sopenharmony_ci * 7598c2ecf20Sopenharmony_ci * Description: 7608c2ecf20Sopenharmony_ci * Examine the Generic NETLINK message and extract the IP address information. 7618c2ecf20Sopenharmony_ci * Returns zero on success, negative values on failure. 7628c2ecf20Sopenharmony_ci * 7638c2ecf20Sopenharmony_ci */ 7648c2ecf20Sopenharmony_cistatic int netlbl_unlabel_addrinfo_get(struct genl_info *info, 7658c2ecf20Sopenharmony_ci void **addr, 7668c2ecf20Sopenharmony_ci void **mask, 7678c2ecf20Sopenharmony_ci u32 *len) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci u32 addr_len; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci if (info->attrs[NLBL_UNLABEL_A_IPV4ADDR] && 7728c2ecf20Sopenharmony_ci info->attrs[NLBL_UNLABEL_A_IPV4MASK]) { 7738c2ecf20Sopenharmony_ci addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]); 7748c2ecf20Sopenharmony_ci if (addr_len != sizeof(struct in_addr) && 7758c2ecf20Sopenharmony_ci addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV4MASK])) 7768c2ecf20Sopenharmony_ci return -EINVAL; 7778c2ecf20Sopenharmony_ci *len = addr_len; 7788c2ecf20Sopenharmony_ci *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]); 7798c2ecf20Sopenharmony_ci *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4MASK]); 7808c2ecf20Sopenharmony_ci return 0; 7818c2ecf20Sopenharmony_ci } else if (info->attrs[NLBL_UNLABEL_A_IPV6ADDR]) { 7828c2ecf20Sopenharmony_ci addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]); 7838c2ecf20Sopenharmony_ci if (addr_len != sizeof(struct in6_addr) && 7848c2ecf20Sopenharmony_ci addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV6MASK])) 7858c2ecf20Sopenharmony_ci return -EINVAL; 7868c2ecf20Sopenharmony_ci *len = addr_len; 7878c2ecf20Sopenharmony_ci *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]); 7888c2ecf20Sopenharmony_ci *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6MASK]); 7898c2ecf20Sopenharmony_ci return 0; 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci return -EINVAL; 7938c2ecf20Sopenharmony_ci} 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci/* 7968c2ecf20Sopenharmony_ci * NetLabel Command Handlers 7978c2ecf20Sopenharmony_ci */ 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci/** 8008c2ecf20Sopenharmony_ci * netlbl_unlabel_accept - Handle an ACCEPT message 8018c2ecf20Sopenharmony_ci * @skb: the NETLINK buffer 8028c2ecf20Sopenharmony_ci * @info: the Generic NETLINK info block 8038c2ecf20Sopenharmony_ci * 8048c2ecf20Sopenharmony_ci * Description: 8058c2ecf20Sopenharmony_ci * Process a user generated ACCEPT message and set the accept flag accordingly. 8068c2ecf20Sopenharmony_ci * Returns zero on success, negative values on failure. 8078c2ecf20Sopenharmony_ci * 8088c2ecf20Sopenharmony_ci */ 8098c2ecf20Sopenharmony_cistatic int netlbl_unlabel_accept(struct sk_buff *skb, struct genl_info *info) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci u8 value; 8128c2ecf20Sopenharmony_ci struct netlbl_audit audit_info; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci if (info->attrs[NLBL_UNLABEL_A_ACPTFLG]) { 8158c2ecf20Sopenharmony_ci value = nla_get_u8(info->attrs[NLBL_UNLABEL_A_ACPTFLG]); 8168c2ecf20Sopenharmony_ci if (value == 1 || value == 0) { 8178c2ecf20Sopenharmony_ci netlbl_netlink_auditinfo(&audit_info); 8188c2ecf20Sopenharmony_ci netlbl_unlabel_acceptflg_set(value, &audit_info); 8198c2ecf20Sopenharmony_ci return 0; 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci return -EINVAL; 8248c2ecf20Sopenharmony_ci} 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci/** 8278c2ecf20Sopenharmony_ci * netlbl_unlabel_list - Handle a LIST message 8288c2ecf20Sopenharmony_ci * @skb: the NETLINK buffer 8298c2ecf20Sopenharmony_ci * @info: the Generic NETLINK info block 8308c2ecf20Sopenharmony_ci * 8318c2ecf20Sopenharmony_ci * Description: 8328c2ecf20Sopenharmony_ci * Process a user generated LIST message and respond with the current status. 8338c2ecf20Sopenharmony_ci * Returns zero on success, negative values on failure. 8348c2ecf20Sopenharmony_ci * 8358c2ecf20Sopenharmony_ci */ 8368c2ecf20Sopenharmony_cistatic int netlbl_unlabel_list(struct sk_buff *skb, struct genl_info *info) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci int ret_val = -EINVAL; 8398c2ecf20Sopenharmony_ci struct sk_buff *ans_skb; 8408c2ecf20Sopenharmony_ci void *data; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 8438c2ecf20Sopenharmony_ci if (ans_skb == NULL) 8448c2ecf20Sopenharmony_ci goto list_failure; 8458c2ecf20Sopenharmony_ci data = genlmsg_put_reply(ans_skb, info, &netlbl_unlabel_gnl_family, 8468c2ecf20Sopenharmony_ci 0, NLBL_UNLABEL_C_LIST); 8478c2ecf20Sopenharmony_ci if (data == NULL) { 8488c2ecf20Sopenharmony_ci ret_val = -ENOMEM; 8498c2ecf20Sopenharmony_ci goto list_failure; 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci ret_val = nla_put_u8(ans_skb, 8538c2ecf20Sopenharmony_ci NLBL_UNLABEL_A_ACPTFLG, 8548c2ecf20Sopenharmony_ci netlabel_unlabel_acceptflg); 8558c2ecf20Sopenharmony_ci if (ret_val != 0) 8568c2ecf20Sopenharmony_ci goto list_failure; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci genlmsg_end(ans_skb, data); 8598c2ecf20Sopenharmony_ci return genlmsg_reply(ans_skb, info); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_cilist_failure: 8628c2ecf20Sopenharmony_ci kfree_skb(ans_skb); 8638c2ecf20Sopenharmony_ci return ret_val; 8648c2ecf20Sopenharmony_ci} 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci/** 8678c2ecf20Sopenharmony_ci * netlbl_unlabel_staticadd - Handle a STATICADD message 8688c2ecf20Sopenharmony_ci * @skb: the NETLINK buffer 8698c2ecf20Sopenharmony_ci * @info: the Generic NETLINK info block 8708c2ecf20Sopenharmony_ci * 8718c2ecf20Sopenharmony_ci * Description: 8728c2ecf20Sopenharmony_ci * Process a user generated STATICADD message and add a new unlabeled 8738c2ecf20Sopenharmony_ci * connection entry to the hash table. Returns zero on success, negative 8748c2ecf20Sopenharmony_ci * values on failure. 8758c2ecf20Sopenharmony_ci * 8768c2ecf20Sopenharmony_ci */ 8778c2ecf20Sopenharmony_cistatic int netlbl_unlabel_staticadd(struct sk_buff *skb, 8788c2ecf20Sopenharmony_ci struct genl_info *info) 8798c2ecf20Sopenharmony_ci{ 8808c2ecf20Sopenharmony_ci int ret_val; 8818c2ecf20Sopenharmony_ci char *dev_name; 8828c2ecf20Sopenharmony_ci void *addr; 8838c2ecf20Sopenharmony_ci void *mask; 8848c2ecf20Sopenharmony_ci u32 addr_len; 8858c2ecf20Sopenharmony_ci u32 secid; 8868c2ecf20Sopenharmony_ci struct netlbl_audit audit_info; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci /* Don't allow users to add both IPv4 and IPv6 addresses for a 8898c2ecf20Sopenharmony_ci * single entry. However, allow users to create two entries, one each 8908c2ecf20Sopenharmony_ci * for IPv4 and IPv4, with the same LSM security context which should 8918c2ecf20Sopenharmony_ci * achieve the same result. */ 8928c2ecf20Sopenharmony_ci if (!info->attrs[NLBL_UNLABEL_A_SECCTX] || 8938c2ecf20Sopenharmony_ci !info->attrs[NLBL_UNLABEL_A_IFACE] || 8948c2ecf20Sopenharmony_ci !((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] || 8958c2ecf20Sopenharmony_ci !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^ 8968c2ecf20Sopenharmony_ci (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] || 8978c2ecf20Sopenharmony_ci !info->attrs[NLBL_UNLABEL_A_IPV6MASK]))) 8988c2ecf20Sopenharmony_ci return -EINVAL; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci netlbl_netlink_auditinfo(&audit_info); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len); 9038c2ecf20Sopenharmony_ci if (ret_val != 0) 9048c2ecf20Sopenharmony_ci return ret_val; 9058c2ecf20Sopenharmony_ci dev_name = nla_data(info->attrs[NLBL_UNLABEL_A_IFACE]); 9068c2ecf20Sopenharmony_ci ret_val = security_secctx_to_secid( 9078c2ecf20Sopenharmony_ci nla_data(info->attrs[NLBL_UNLABEL_A_SECCTX]), 9088c2ecf20Sopenharmony_ci nla_len(info->attrs[NLBL_UNLABEL_A_SECCTX]), 9098c2ecf20Sopenharmony_ci &secid); 9108c2ecf20Sopenharmony_ci if (ret_val != 0) 9118c2ecf20Sopenharmony_ci return ret_val; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci return netlbl_unlhsh_add(&init_net, 9148c2ecf20Sopenharmony_ci dev_name, addr, mask, addr_len, secid, 9158c2ecf20Sopenharmony_ci &audit_info); 9168c2ecf20Sopenharmony_ci} 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci/** 9198c2ecf20Sopenharmony_ci * netlbl_unlabel_staticadddef - Handle a STATICADDDEF message 9208c2ecf20Sopenharmony_ci * @skb: the NETLINK buffer 9218c2ecf20Sopenharmony_ci * @info: the Generic NETLINK info block 9228c2ecf20Sopenharmony_ci * 9238c2ecf20Sopenharmony_ci * Description: 9248c2ecf20Sopenharmony_ci * Process a user generated STATICADDDEF message and add a new default 9258c2ecf20Sopenharmony_ci * unlabeled connection entry. Returns zero on success, negative values on 9268c2ecf20Sopenharmony_ci * failure. 9278c2ecf20Sopenharmony_ci * 9288c2ecf20Sopenharmony_ci */ 9298c2ecf20Sopenharmony_cistatic int netlbl_unlabel_staticadddef(struct sk_buff *skb, 9308c2ecf20Sopenharmony_ci struct genl_info *info) 9318c2ecf20Sopenharmony_ci{ 9328c2ecf20Sopenharmony_ci int ret_val; 9338c2ecf20Sopenharmony_ci void *addr; 9348c2ecf20Sopenharmony_ci void *mask; 9358c2ecf20Sopenharmony_ci u32 addr_len; 9368c2ecf20Sopenharmony_ci u32 secid; 9378c2ecf20Sopenharmony_ci struct netlbl_audit audit_info; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci /* Don't allow users to add both IPv4 and IPv6 addresses for a 9408c2ecf20Sopenharmony_ci * single entry. However, allow users to create two entries, one each 9418c2ecf20Sopenharmony_ci * for IPv4 and IPv6, with the same LSM security context which should 9428c2ecf20Sopenharmony_ci * achieve the same result. */ 9438c2ecf20Sopenharmony_ci if (!info->attrs[NLBL_UNLABEL_A_SECCTX] || 9448c2ecf20Sopenharmony_ci !((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] || 9458c2ecf20Sopenharmony_ci !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^ 9468c2ecf20Sopenharmony_ci (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] || 9478c2ecf20Sopenharmony_ci !info->attrs[NLBL_UNLABEL_A_IPV6MASK]))) 9488c2ecf20Sopenharmony_ci return -EINVAL; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci netlbl_netlink_auditinfo(&audit_info); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len); 9538c2ecf20Sopenharmony_ci if (ret_val != 0) 9548c2ecf20Sopenharmony_ci return ret_val; 9558c2ecf20Sopenharmony_ci ret_val = security_secctx_to_secid( 9568c2ecf20Sopenharmony_ci nla_data(info->attrs[NLBL_UNLABEL_A_SECCTX]), 9578c2ecf20Sopenharmony_ci nla_len(info->attrs[NLBL_UNLABEL_A_SECCTX]), 9588c2ecf20Sopenharmony_ci &secid); 9598c2ecf20Sopenharmony_ci if (ret_val != 0) 9608c2ecf20Sopenharmony_ci return ret_val; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci return netlbl_unlhsh_add(&init_net, 9638c2ecf20Sopenharmony_ci NULL, addr, mask, addr_len, secid, 9648c2ecf20Sopenharmony_ci &audit_info); 9658c2ecf20Sopenharmony_ci} 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci/** 9688c2ecf20Sopenharmony_ci * netlbl_unlabel_staticremove - Handle a STATICREMOVE message 9698c2ecf20Sopenharmony_ci * @skb: the NETLINK buffer 9708c2ecf20Sopenharmony_ci * @info: the Generic NETLINK info block 9718c2ecf20Sopenharmony_ci * 9728c2ecf20Sopenharmony_ci * Description: 9738c2ecf20Sopenharmony_ci * Process a user generated STATICREMOVE message and remove the specified 9748c2ecf20Sopenharmony_ci * unlabeled connection entry. Returns zero on success, negative values on 9758c2ecf20Sopenharmony_ci * failure. 9768c2ecf20Sopenharmony_ci * 9778c2ecf20Sopenharmony_ci */ 9788c2ecf20Sopenharmony_cistatic int netlbl_unlabel_staticremove(struct sk_buff *skb, 9798c2ecf20Sopenharmony_ci struct genl_info *info) 9808c2ecf20Sopenharmony_ci{ 9818c2ecf20Sopenharmony_ci int ret_val; 9828c2ecf20Sopenharmony_ci char *dev_name; 9838c2ecf20Sopenharmony_ci void *addr; 9848c2ecf20Sopenharmony_ci void *mask; 9858c2ecf20Sopenharmony_ci u32 addr_len; 9868c2ecf20Sopenharmony_ci struct netlbl_audit audit_info; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci /* See the note in netlbl_unlabel_staticadd() about not allowing both 9898c2ecf20Sopenharmony_ci * IPv4 and IPv6 in the same entry. */ 9908c2ecf20Sopenharmony_ci if (!info->attrs[NLBL_UNLABEL_A_IFACE] || 9918c2ecf20Sopenharmony_ci !((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] || 9928c2ecf20Sopenharmony_ci !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^ 9938c2ecf20Sopenharmony_ci (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] || 9948c2ecf20Sopenharmony_ci !info->attrs[NLBL_UNLABEL_A_IPV6MASK]))) 9958c2ecf20Sopenharmony_ci return -EINVAL; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci netlbl_netlink_auditinfo(&audit_info); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len); 10008c2ecf20Sopenharmony_ci if (ret_val != 0) 10018c2ecf20Sopenharmony_ci return ret_val; 10028c2ecf20Sopenharmony_ci dev_name = nla_data(info->attrs[NLBL_UNLABEL_A_IFACE]); 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci return netlbl_unlhsh_remove(&init_net, 10058c2ecf20Sopenharmony_ci dev_name, addr, mask, addr_len, 10068c2ecf20Sopenharmony_ci &audit_info); 10078c2ecf20Sopenharmony_ci} 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci/** 10108c2ecf20Sopenharmony_ci * netlbl_unlabel_staticremovedef - Handle a STATICREMOVEDEF message 10118c2ecf20Sopenharmony_ci * @skb: the NETLINK buffer 10128c2ecf20Sopenharmony_ci * @info: the Generic NETLINK info block 10138c2ecf20Sopenharmony_ci * 10148c2ecf20Sopenharmony_ci * Description: 10158c2ecf20Sopenharmony_ci * Process a user generated STATICREMOVEDEF message and remove the default 10168c2ecf20Sopenharmony_ci * unlabeled connection entry. Returns zero on success, negative values on 10178c2ecf20Sopenharmony_ci * failure. 10188c2ecf20Sopenharmony_ci * 10198c2ecf20Sopenharmony_ci */ 10208c2ecf20Sopenharmony_cistatic int netlbl_unlabel_staticremovedef(struct sk_buff *skb, 10218c2ecf20Sopenharmony_ci struct genl_info *info) 10228c2ecf20Sopenharmony_ci{ 10238c2ecf20Sopenharmony_ci int ret_val; 10248c2ecf20Sopenharmony_ci void *addr; 10258c2ecf20Sopenharmony_ci void *mask; 10268c2ecf20Sopenharmony_ci u32 addr_len; 10278c2ecf20Sopenharmony_ci struct netlbl_audit audit_info; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci /* See the note in netlbl_unlabel_staticadd() about not allowing both 10308c2ecf20Sopenharmony_ci * IPv4 and IPv6 in the same entry. */ 10318c2ecf20Sopenharmony_ci if (!((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] || 10328c2ecf20Sopenharmony_ci !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^ 10338c2ecf20Sopenharmony_ci (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] || 10348c2ecf20Sopenharmony_ci !info->attrs[NLBL_UNLABEL_A_IPV6MASK]))) 10358c2ecf20Sopenharmony_ci return -EINVAL; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci netlbl_netlink_auditinfo(&audit_info); 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len); 10408c2ecf20Sopenharmony_ci if (ret_val != 0) 10418c2ecf20Sopenharmony_ci return ret_val; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci return netlbl_unlhsh_remove(&init_net, 10448c2ecf20Sopenharmony_ci NULL, addr, mask, addr_len, 10458c2ecf20Sopenharmony_ci &audit_info); 10468c2ecf20Sopenharmony_ci} 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci/** 10508c2ecf20Sopenharmony_ci * netlbl_unlabel_staticlist_gen - Generate messages for STATICLIST[DEF] 10518c2ecf20Sopenharmony_ci * @cmd: command/message 10528c2ecf20Sopenharmony_ci * @iface: the interface entry 10538c2ecf20Sopenharmony_ci * @addr4: the IPv4 address entry 10548c2ecf20Sopenharmony_ci * @addr6: the IPv6 address entry 10558c2ecf20Sopenharmony_ci * @arg: the netlbl_unlhsh_walk_arg structure 10568c2ecf20Sopenharmony_ci * 10578c2ecf20Sopenharmony_ci * Description: 10588c2ecf20Sopenharmony_ci * This function is designed to be used to generate a response for a 10598c2ecf20Sopenharmony_ci * STATICLIST or STATICLISTDEF message. When called either @addr4 or @addr6 10608c2ecf20Sopenharmony_ci * can be specified, not both, the other unspecified entry should be set to 10618c2ecf20Sopenharmony_ci * NULL by the caller. Returns the size of the message on success, negative 10628c2ecf20Sopenharmony_ci * values on failure. 10638c2ecf20Sopenharmony_ci * 10648c2ecf20Sopenharmony_ci */ 10658c2ecf20Sopenharmony_cistatic int netlbl_unlabel_staticlist_gen(u32 cmd, 10668c2ecf20Sopenharmony_ci const struct netlbl_unlhsh_iface *iface, 10678c2ecf20Sopenharmony_ci const struct netlbl_unlhsh_addr4 *addr4, 10688c2ecf20Sopenharmony_ci const struct netlbl_unlhsh_addr6 *addr6, 10698c2ecf20Sopenharmony_ci void *arg) 10708c2ecf20Sopenharmony_ci{ 10718c2ecf20Sopenharmony_ci int ret_val = -ENOMEM; 10728c2ecf20Sopenharmony_ci struct netlbl_unlhsh_walk_arg *cb_arg = arg; 10738c2ecf20Sopenharmony_ci struct net_device *dev; 10748c2ecf20Sopenharmony_ci void *data; 10758c2ecf20Sopenharmony_ci u32 secid; 10768c2ecf20Sopenharmony_ci char *secctx; 10778c2ecf20Sopenharmony_ci u32 secctx_len; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid, 10808c2ecf20Sopenharmony_ci cb_arg->seq, &netlbl_unlabel_gnl_family, 10818c2ecf20Sopenharmony_ci NLM_F_MULTI, cmd); 10828c2ecf20Sopenharmony_ci if (data == NULL) 10838c2ecf20Sopenharmony_ci goto list_cb_failure; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci if (iface->ifindex > 0) { 10868c2ecf20Sopenharmony_ci dev = dev_get_by_index(&init_net, iface->ifindex); 10878c2ecf20Sopenharmony_ci if (!dev) { 10888c2ecf20Sopenharmony_ci ret_val = -ENODEV; 10898c2ecf20Sopenharmony_ci goto list_cb_failure; 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ci ret_val = nla_put_string(cb_arg->skb, 10928c2ecf20Sopenharmony_ci NLBL_UNLABEL_A_IFACE, dev->name); 10938c2ecf20Sopenharmony_ci dev_put(dev); 10948c2ecf20Sopenharmony_ci if (ret_val != 0) 10958c2ecf20Sopenharmony_ci goto list_cb_failure; 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci if (addr4) { 10998c2ecf20Sopenharmony_ci struct in_addr addr_struct; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci addr_struct.s_addr = addr4->list.addr; 11028c2ecf20Sopenharmony_ci ret_val = nla_put_in_addr(cb_arg->skb, 11038c2ecf20Sopenharmony_ci NLBL_UNLABEL_A_IPV4ADDR, 11048c2ecf20Sopenharmony_ci addr_struct.s_addr); 11058c2ecf20Sopenharmony_ci if (ret_val != 0) 11068c2ecf20Sopenharmony_ci goto list_cb_failure; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci addr_struct.s_addr = addr4->list.mask; 11098c2ecf20Sopenharmony_ci ret_val = nla_put_in_addr(cb_arg->skb, 11108c2ecf20Sopenharmony_ci NLBL_UNLABEL_A_IPV4MASK, 11118c2ecf20Sopenharmony_ci addr_struct.s_addr); 11128c2ecf20Sopenharmony_ci if (ret_val != 0) 11138c2ecf20Sopenharmony_ci goto list_cb_failure; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci secid = addr4->secid; 11168c2ecf20Sopenharmony_ci } else { 11178c2ecf20Sopenharmony_ci ret_val = nla_put_in6_addr(cb_arg->skb, 11188c2ecf20Sopenharmony_ci NLBL_UNLABEL_A_IPV6ADDR, 11198c2ecf20Sopenharmony_ci &addr6->list.addr); 11208c2ecf20Sopenharmony_ci if (ret_val != 0) 11218c2ecf20Sopenharmony_ci goto list_cb_failure; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci ret_val = nla_put_in6_addr(cb_arg->skb, 11248c2ecf20Sopenharmony_ci NLBL_UNLABEL_A_IPV6MASK, 11258c2ecf20Sopenharmony_ci &addr6->list.mask); 11268c2ecf20Sopenharmony_ci if (ret_val != 0) 11278c2ecf20Sopenharmony_ci goto list_cb_failure; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci secid = addr6->secid; 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci ret_val = security_secid_to_secctx(secid, &secctx, &secctx_len); 11338c2ecf20Sopenharmony_ci if (ret_val != 0) 11348c2ecf20Sopenharmony_ci goto list_cb_failure; 11358c2ecf20Sopenharmony_ci ret_val = nla_put(cb_arg->skb, 11368c2ecf20Sopenharmony_ci NLBL_UNLABEL_A_SECCTX, 11378c2ecf20Sopenharmony_ci secctx_len, 11388c2ecf20Sopenharmony_ci secctx); 11398c2ecf20Sopenharmony_ci security_release_secctx(secctx, secctx_len); 11408c2ecf20Sopenharmony_ci if (ret_val != 0) 11418c2ecf20Sopenharmony_ci goto list_cb_failure; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci cb_arg->seq++; 11448c2ecf20Sopenharmony_ci genlmsg_end(cb_arg->skb, data); 11458c2ecf20Sopenharmony_ci return 0; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_cilist_cb_failure: 11488c2ecf20Sopenharmony_ci genlmsg_cancel(cb_arg->skb, data); 11498c2ecf20Sopenharmony_ci return ret_val; 11508c2ecf20Sopenharmony_ci} 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci/** 11538c2ecf20Sopenharmony_ci * netlbl_unlabel_staticlist - Handle a STATICLIST message 11548c2ecf20Sopenharmony_ci * @skb: the NETLINK buffer 11558c2ecf20Sopenharmony_ci * @cb: the NETLINK callback 11568c2ecf20Sopenharmony_ci * 11578c2ecf20Sopenharmony_ci * Description: 11588c2ecf20Sopenharmony_ci * Process a user generated STATICLIST message and dump the unlabeled 11598c2ecf20Sopenharmony_ci * connection hash table in a form suitable for use in a kernel generated 11608c2ecf20Sopenharmony_ci * STATICLIST message. Returns the length of @skb. 11618c2ecf20Sopenharmony_ci * 11628c2ecf20Sopenharmony_ci */ 11638c2ecf20Sopenharmony_cistatic int netlbl_unlabel_staticlist(struct sk_buff *skb, 11648c2ecf20Sopenharmony_ci struct netlink_callback *cb) 11658c2ecf20Sopenharmony_ci{ 11668c2ecf20Sopenharmony_ci struct netlbl_unlhsh_walk_arg cb_arg; 11678c2ecf20Sopenharmony_ci u32 skip_bkt = cb->args[0]; 11688c2ecf20Sopenharmony_ci u32 skip_chain = cb->args[1]; 11698c2ecf20Sopenharmony_ci u32 skip_addr4 = cb->args[2]; 11708c2ecf20Sopenharmony_ci u32 iter_bkt, iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0; 11718c2ecf20Sopenharmony_ci struct netlbl_unlhsh_iface *iface; 11728c2ecf20Sopenharmony_ci struct list_head *iter_list; 11738c2ecf20Sopenharmony_ci struct netlbl_af4list *addr4; 11748c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 11758c2ecf20Sopenharmony_ci u32 skip_addr6 = cb->args[3]; 11768c2ecf20Sopenharmony_ci struct netlbl_af6list *addr6; 11778c2ecf20Sopenharmony_ci#endif 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci cb_arg.nl_cb = cb; 11808c2ecf20Sopenharmony_ci cb_arg.skb = skb; 11818c2ecf20Sopenharmony_ci cb_arg.seq = cb->nlh->nlmsg_seq; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci rcu_read_lock(); 11848c2ecf20Sopenharmony_ci for (iter_bkt = skip_bkt; 11858c2ecf20Sopenharmony_ci iter_bkt < rcu_dereference(netlbl_unlhsh)->size; 11868c2ecf20Sopenharmony_ci iter_bkt++) { 11878c2ecf20Sopenharmony_ci iter_list = &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt]; 11888c2ecf20Sopenharmony_ci list_for_each_entry_rcu(iface, iter_list, list) { 11898c2ecf20Sopenharmony_ci if (!iface->valid || 11908c2ecf20Sopenharmony_ci iter_chain++ < skip_chain) 11918c2ecf20Sopenharmony_ci continue; 11928c2ecf20Sopenharmony_ci netlbl_af4list_foreach_rcu(addr4, 11938c2ecf20Sopenharmony_ci &iface->addr4_list) { 11948c2ecf20Sopenharmony_ci if (iter_addr4++ < skip_addr4) 11958c2ecf20Sopenharmony_ci continue; 11968c2ecf20Sopenharmony_ci if (netlbl_unlabel_staticlist_gen( 11978c2ecf20Sopenharmony_ci NLBL_UNLABEL_C_STATICLIST, 11988c2ecf20Sopenharmony_ci iface, 11998c2ecf20Sopenharmony_ci netlbl_unlhsh_addr4_entry(addr4), 12008c2ecf20Sopenharmony_ci NULL, 12018c2ecf20Sopenharmony_ci &cb_arg) < 0) { 12028c2ecf20Sopenharmony_ci iter_addr4--; 12038c2ecf20Sopenharmony_ci iter_chain--; 12048c2ecf20Sopenharmony_ci goto unlabel_staticlist_return; 12058c2ecf20Sopenharmony_ci } 12068c2ecf20Sopenharmony_ci } 12078c2ecf20Sopenharmony_ci iter_addr4 = 0; 12088c2ecf20Sopenharmony_ci skip_addr4 = 0; 12098c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 12108c2ecf20Sopenharmony_ci netlbl_af6list_foreach_rcu(addr6, 12118c2ecf20Sopenharmony_ci &iface->addr6_list) { 12128c2ecf20Sopenharmony_ci if (iter_addr6++ < skip_addr6) 12138c2ecf20Sopenharmony_ci continue; 12148c2ecf20Sopenharmony_ci if (netlbl_unlabel_staticlist_gen( 12158c2ecf20Sopenharmony_ci NLBL_UNLABEL_C_STATICLIST, 12168c2ecf20Sopenharmony_ci iface, 12178c2ecf20Sopenharmony_ci NULL, 12188c2ecf20Sopenharmony_ci netlbl_unlhsh_addr6_entry(addr6), 12198c2ecf20Sopenharmony_ci &cb_arg) < 0) { 12208c2ecf20Sopenharmony_ci iter_addr6--; 12218c2ecf20Sopenharmony_ci iter_chain--; 12228c2ecf20Sopenharmony_ci goto unlabel_staticlist_return; 12238c2ecf20Sopenharmony_ci } 12248c2ecf20Sopenharmony_ci } 12258c2ecf20Sopenharmony_ci iter_addr6 = 0; 12268c2ecf20Sopenharmony_ci skip_addr6 = 0; 12278c2ecf20Sopenharmony_ci#endif /* IPv6 */ 12288c2ecf20Sopenharmony_ci } 12298c2ecf20Sopenharmony_ci iter_chain = 0; 12308c2ecf20Sopenharmony_ci skip_chain = 0; 12318c2ecf20Sopenharmony_ci } 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ciunlabel_staticlist_return: 12348c2ecf20Sopenharmony_ci rcu_read_unlock(); 12358c2ecf20Sopenharmony_ci cb->args[0] = iter_bkt; 12368c2ecf20Sopenharmony_ci cb->args[1] = iter_chain; 12378c2ecf20Sopenharmony_ci cb->args[2] = iter_addr4; 12388c2ecf20Sopenharmony_ci cb->args[3] = iter_addr6; 12398c2ecf20Sopenharmony_ci return skb->len; 12408c2ecf20Sopenharmony_ci} 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci/** 12438c2ecf20Sopenharmony_ci * netlbl_unlabel_staticlistdef - Handle a STATICLISTDEF message 12448c2ecf20Sopenharmony_ci * @skb: the NETLINK buffer 12458c2ecf20Sopenharmony_ci * @cb: the NETLINK callback 12468c2ecf20Sopenharmony_ci * 12478c2ecf20Sopenharmony_ci * Description: 12488c2ecf20Sopenharmony_ci * Process a user generated STATICLISTDEF message and dump the default 12498c2ecf20Sopenharmony_ci * unlabeled connection entry in a form suitable for use in a kernel generated 12508c2ecf20Sopenharmony_ci * STATICLISTDEF message. Returns the length of @skb. 12518c2ecf20Sopenharmony_ci * 12528c2ecf20Sopenharmony_ci */ 12538c2ecf20Sopenharmony_cistatic int netlbl_unlabel_staticlistdef(struct sk_buff *skb, 12548c2ecf20Sopenharmony_ci struct netlink_callback *cb) 12558c2ecf20Sopenharmony_ci{ 12568c2ecf20Sopenharmony_ci struct netlbl_unlhsh_walk_arg cb_arg; 12578c2ecf20Sopenharmony_ci struct netlbl_unlhsh_iface *iface; 12588c2ecf20Sopenharmony_ci u32 iter_addr4 = 0, iter_addr6 = 0; 12598c2ecf20Sopenharmony_ci struct netlbl_af4list *addr4; 12608c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 12618c2ecf20Sopenharmony_ci struct netlbl_af6list *addr6; 12628c2ecf20Sopenharmony_ci#endif 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci cb_arg.nl_cb = cb; 12658c2ecf20Sopenharmony_ci cb_arg.skb = skb; 12668c2ecf20Sopenharmony_ci cb_arg.seq = cb->nlh->nlmsg_seq; 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci rcu_read_lock(); 12698c2ecf20Sopenharmony_ci iface = rcu_dereference(netlbl_unlhsh_def); 12708c2ecf20Sopenharmony_ci if (iface == NULL || !iface->valid) 12718c2ecf20Sopenharmony_ci goto unlabel_staticlistdef_return; 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci netlbl_af4list_foreach_rcu(addr4, &iface->addr4_list) { 12748c2ecf20Sopenharmony_ci if (iter_addr4++ < cb->args[0]) 12758c2ecf20Sopenharmony_ci continue; 12768c2ecf20Sopenharmony_ci if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF, 12778c2ecf20Sopenharmony_ci iface, 12788c2ecf20Sopenharmony_ci netlbl_unlhsh_addr4_entry(addr4), 12798c2ecf20Sopenharmony_ci NULL, 12808c2ecf20Sopenharmony_ci &cb_arg) < 0) { 12818c2ecf20Sopenharmony_ci iter_addr4--; 12828c2ecf20Sopenharmony_ci goto unlabel_staticlistdef_return; 12838c2ecf20Sopenharmony_ci } 12848c2ecf20Sopenharmony_ci } 12858c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 12868c2ecf20Sopenharmony_ci netlbl_af6list_foreach_rcu(addr6, &iface->addr6_list) { 12878c2ecf20Sopenharmony_ci if (iter_addr6++ < cb->args[1]) 12888c2ecf20Sopenharmony_ci continue; 12898c2ecf20Sopenharmony_ci if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF, 12908c2ecf20Sopenharmony_ci iface, 12918c2ecf20Sopenharmony_ci NULL, 12928c2ecf20Sopenharmony_ci netlbl_unlhsh_addr6_entry(addr6), 12938c2ecf20Sopenharmony_ci &cb_arg) < 0) { 12948c2ecf20Sopenharmony_ci iter_addr6--; 12958c2ecf20Sopenharmony_ci goto unlabel_staticlistdef_return; 12968c2ecf20Sopenharmony_ci } 12978c2ecf20Sopenharmony_ci } 12988c2ecf20Sopenharmony_ci#endif /* IPv6 */ 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ciunlabel_staticlistdef_return: 13018c2ecf20Sopenharmony_ci rcu_read_unlock(); 13028c2ecf20Sopenharmony_ci cb->args[0] = iter_addr4; 13038c2ecf20Sopenharmony_ci cb->args[1] = iter_addr6; 13048c2ecf20Sopenharmony_ci return skb->len; 13058c2ecf20Sopenharmony_ci} 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci/* 13088c2ecf20Sopenharmony_ci * NetLabel Generic NETLINK Command Definitions 13098c2ecf20Sopenharmony_ci */ 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_cistatic const struct genl_small_ops netlbl_unlabel_genl_ops[] = { 13128c2ecf20Sopenharmony_ci { 13138c2ecf20Sopenharmony_ci .cmd = NLBL_UNLABEL_C_STATICADD, 13148c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 13158c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 13168c2ecf20Sopenharmony_ci .doit = netlbl_unlabel_staticadd, 13178c2ecf20Sopenharmony_ci .dumpit = NULL, 13188c2ecf20Sopenharmony_ci }, 13198c2ecf20Sopenharmony_ci { 13208c2ecf20Sopenharmony_ci .cmd = NLBL_UNLABEL_C_STATICREMOVE, 13218c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 13228c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 13238c2ecf20Sopenharmony_ci .doit = netlbl_unlabel_staticremove, 13248c2ecf20Sopenharmony_ci .dumpit = NULL, 13258c2ecf20Sopenharmony_ci }, 13268c2ecf20Sopenharmony_ci { 13278c2ecf20Sopenharmony_ci .cmd = NLBL_UNLABEL_C_STATICLIST, 13288c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 13298c2ecf20Sopenharmony_ci .flags = 0, 13308c2ecf20Sopenharmony_ci .doit = NULL, 13318c2ecf20Sopenharmony_ci .dumpit = netlbl_unlabel_staticlist, 13328c2ecf20Sopenharmony_ci }, 13338c2ecf20Sopenharmony_ci { 13348c2ecf20Sopenharmony_ci .cmd = NLBL_UNLABEL_C_STATICADDDEF, 13358c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 13368c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 13378c2ecf20Sopenharmony_ci .doit = netlbl_unlabel_staticadddef, 13388c2ecf20Sopenharmony_ci .dumpit = NULL, 13398c2ecf20Sopenharmony_ci }, 13408c2ecf20Sopenharmony_ci { 13418c2ecf20Sopenharmony_ci .cmd = NLBL_UNLABEL_C_STATICREMOVEDEF, 13428c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 13438c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 13448c2ecf20Sopenharmony_ci .doit = netlbl_unlabel_staticremovedef, 13458c2ecf20Sopenharmony_ci .dumpit = NULL, 13468c2ecf20Sopenharmony_ci }, 13478c2ecf20Sopenharmony_ci { 13488c2ecf20Sopenharmony_ci .cmd = NLBL_UNLABEL_C_STATICLISTDEF, 13498c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 13508c2ecf20Sopenharmony_ci .flags = 0, 13518c2ecf20Sopenharmony_ci .doit = NULL, 13528c2ecf20Sopenharmony_ci .dumpit = netlbl_unlabel_staticlistdef, 13538c2ecf20Sopenharmony_ci }, 13548c2ecf20Sopenharmony_ci { 13558c2ecf20Sopenharmony_ci .cmd = NLBL_UNLABEL_C_ACCEPT, 13568c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 13578c2ecf20Sopenharmony_ci .flags = GENL_ADMIN_PERM, 13588c2ecf20Sopenharmony_ci .doit = netlbl_unlabel_accept, 13598c2ecf20Sopenharmony_ci .dumpit = NULL, 13608c2ecf20Sopenharmony_ci }, 13618c2ecf20Sopenharmony_ci { 13628c2ecf20Sopenharmony_ci .cmd = NLBL_UNLABEL_C_LIST, 13638c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 13648c2ecf20Sopenharmony_ci .flags = 0, 13658c2ecf20Sopenharmony_ci .doit = netlbl_unlabel_list, 13668c2ecf20Sopenharmony_ci .dumpit = NULL, 13678c2ecf20Sopenharmony_ci }, 13688c2ecf20Sopenharmony_ci}; 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_cistatic struct genl_family netlbl_unlabel_gnl_family __ro_after_init = { 13718c2ecf20Sopenharmony_ci .hdrsize = 0, 13728c2ecf20Sopenharmony_ci .name = NETLBL_NLTYPE_UNLABELED_NAME, 13738c2ecf20Sopenharmony_ci .version = NETLBL_PROTO_VERSION, 13748c2ecf20Sopenharmony_ci .maxattr = NLBL_UNLABEL_A_MAX, 13758c2ecf20Sopenharmony_ci .policy = netlbl_unlabel_genl_policy, 13768c2ecf20Sopenharmony_ci .module = THIS_MODULE, 13778c2ecf20Sopenharmony_ci .small_ops = netlbl_unlabel_genl_ops, 13788c2ecf20Sopenharmony_ci .n_small_ops = ARRAY_SIZE(netlbl_unlabel_genl_ops), 13798c2ecf20Sopenharmony_ci}; 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci/* 13828c2ecf20Sopenharmony_ci * NetLabel Generic NETLINK Protocol Functions 13838c2ecf20Sopenharmony_ci */ 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci/** 13868c2ecf20Sopenharmony_ci * netlbl_unlabel_genl_init - Register the Unlabeled NetLabel component 13878c2ecf20Sopenharmony_ci * 13888c2ecf20Sopenharmony_ci * Description: 13898c2ecf20Sopenharmony_ci * Register the unlabeled packet NetLabel component with the Generic NETLINK 13908c2ecf20Sopenharmony_ci * mechanism. Returns zero on success, negative values on failure. 13918c2ecf20Sopenharmony_ci * 13928c2ecf20Sopenharmony_ci */ 13938c2ecf20Sopenharmony_ciint __init netlbl_unlabel_genl_init(void) 13948c2ecf20Sopenharmony_ci{ 13958c2ecf20Sopenharmony_ci return genl_register_family(&netlbl_unlabel_gnl_family); 13968c2ecf20Sopenharmony_ci} 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci/* 13998c2ecf20Sopenharmony_ci * NetLabel KAPI Hooks 14008c2ecf20Sopenharmony_ci */ 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_cistatic struct notifier_block netlbl_unlhsh_netdev_notifier = { 14038c2ecf20Sopenharmony_ci .notifier_call = netlbl_unlhsh_netdev_handler, 14048c2ecf20Sopenharmony_ci}; 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci/** 14078c2ecf20Sopenharmony_ci * netlbl_unlabel_init - Initialize the unlabeled connection hash table 14088c2ecf20Sopenharmony_ci * @size: the number of bits to use for the hash buckets 14098c2ecf20Sopenharmony_ci * 14108c2ecf20Sopenharmony_ci * Description: 14118c2ecf20Sopenharmony_ci * Initializes the unlabeled connection hash table and registers a network 14128c2ecf20Sopenharmony_ci * device notification handler. This function should only be called by the 14138c2ecf20Sopenharmony_ci * NetLabel subsystem itself during initialization. Returns zero on success, 14148c2ecf20Sopenharmony_ci * non-zero values on error. 14158c2ecf20Sopenharmony_ci * 14168c2ecf20Sopenharmony_ci */ 14178c2ecf20Sopenharmony_ciint __init netlbl_unlabel_init(u32 size) 14188c2ecf20Sopenharmony_ci{ 14198c2ecf20Sopenharmony_ci u32 iter; 14208c2ecf20Sopenharmony_ci struct netlbl_unlhsh_tbl *hsh_tbl; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci if (size == 0) 14238c2ecf20Sopenharmony_ci return -EINVAL; 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci hsh_tbl = kmalloc(sizeof(*hsh_tbl), GFP_KERNEL); 14268c2ecf20Sopenharmony_ci if (hsh_tbl == NULL) 14278c2ecf20Sopenharmony_ci return -ENOMEM; 14288c2ecf20Sopenharmony_ci hsh_tbl->size = 1 << size; 14298c2ecf20Sopenharmony_ci hsh_tbl->tbl = kcalloc(hsh_tbl->size, 14308c2ecf20Sopenharmony_ci sizeof(struct list_head), 14318c2ecf20Sopenharmony_ci GFP_KERNEL); 14328c2ecf20Sopenharmony_ci if (hsh_tbl->tbl == NULL) { 14338c2ecf20Sopenharmony_ci kfree(hsh_tbl); 14348c2ecf20Sopenharmony_ci return -ENOMEM; 14358c2ecf20Sopenharmony_ci } 14368c2ecf20Sopenharmony_ci for (iter = 0; iter < hsh_tbl->size; iter++) 14378c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&hsh_tbl->tbl[iter]); 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci spin_lock(&netlbl_unlhsh_lock); 14408c2ecf20Sopenharmony_ci rcu_assign_pointer(netlbl_unlhsh, hsh_tbl); 14418c2ecf20Sopenharmony_ci spin_unlock(&netlbl_unlhsh_lock); 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci register_netdevice_notifier(&netlbl_unlhsh_netdev_notifier); 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci return 0; 14468c2ecf20Sopenharmony_ci} 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci/** 14498c2ecf20Sopenharmony_ci * netlbl_unlabel_getattr - Get the security attributes for an unlabled packet 14508c2ecf20Sopenharmony_ci * @skb: the packet 14518c2ecf20Sopenharmony_ci * @family: protocol family 14528c2ecf20Sopenharmony_ci * @secattr: the security attributes 14538c2ecf20Sopenharmony_ci * 14548c2ecf20Sopenharmony_ci * Description: 14558c2ecf20Sopenharmony_ci * Determine the security attributes, if any, for an unlabled packet and return 14568c2ecf20Sopenharmony_ci * them in @secattr. Returns zero on success and negative values on failure. 14578c2ecf20Sopenharmony_ci * 14588c2ecf20Sopenharmony_ci */ 14598c2ecf20Sopenharmony_ciint netlbl_unlabel_getattr(const struct sk_buff *skb, 14608c2ecf20Sopenharmony_ci u16 family, 14618c2ecf20Sopenharmony_ci struct netlbl_lsm_secattr *secattr) 14628c2ecf20Sopenharmony_ci{ 14638c2ecf20Sopenharmony_ci struct netlbl_unlhsh_iface *iface; 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci rcu_read_lock(); 14668c2ecf20Sopenharmony_ci iface = netlbl_unlhsh_search_iface(skb->skb_iif); 14678c2ecf20Sopenharmony_ci if (iface == NULL) 14688c2ecf20Sopenharmony_ci iface = rcu_dereference(netlbl_unlhsh_def); 14698c2ecf20Sopenharmony_ci if (iface == NULL || !iface->valid) 14708c2ecf20Sopenharmony_ci goto unlabel_getattr_nolabel; 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 14738c2ecf20Sopenharmony_ci /* When resolving a fallback label, check the sk_buff version as 14748c2ecf20Sopenharmony_ci * it is possible (e.g. SCTP) to have family = PF_INET6 while 14758c2ecf20Sopenharmony_ci * receiving ip_hdr(skb)->version = 4. 14768c2ecf20Sopenharmony_ci */ 14778c2ecf20Sopenharmony_ci if (family == PF_INET6 && ip_hdr(skb)->version == 4) 14788c2ecf20Sopenharmony_ci family = PF_INET; 14798c2ecf20Sopenharmony_ci#endif /* IPv6 */ 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci switch (family) { 14828c2ecf20Sopenharmony_ci case PF_INET: { 14838c2ecf20Sopenharmony_ci struct iphdr *hdr4; 14848c2ecf20Sopenharmony_ci struct netlbl_af4list *addr4; 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci hdr4 = ip_hdr(skb); 14878c2ecf20Sopenharmony_ci addr4 = netlbl_af4list_search(hdr4->saddr, 14888c2ecf20Sopenharmony_ci &iface->addr4_list); 14898c2ecf20Sopenharmony_ci if (addr4 == NULL) 14908c2ecf20Sopenharmony_ci goto unlabel_getattr_nolabel; 14918c2ecf20Sopenharmony_ci secattr->attr.secid = netlbl_unlhsh_addr4_entry(addr4)->secid; 14928c2ecf20Sopenharmony_ci break; 14938c2ecf20Sopenharmony_ci } 14948c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 14958c2ecf20Sopenharmony_ci case PF_INET6: { 14968c2ecf20Sopenharmony_ci struct ipv6hdr *hdr6; 14978c2ecf20Sopenharmony_ci struct netlbl_af6list *addr6; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci hdr6 = ipv6_hdr(skb); 15008c2ecf20Sopenharmony_ci addr6 = netlbl_af6list_search(&hdr6->saddr, 15018c2ecf20Sopenharmony_ci &iface->addr6_list); 15028c2ecf20Sopenharmony_ci if (addr6 == NULL) 15038c2ecf20Sopenharmony_ci goto unlabel_getattr_nolabel; 15048c2ecf20Sopenharmony_ci secattr->attr.secid = netlbl_unlhsh_addr6_entry(addr6)->secid; 15058c2ecf20Sopenharmony_ci break; 15068c2ecf20Sopenharmony_ci } 15078c2ecf20Sopenharmony_ci#endif /* IPv6 */ 15088c2ecf20Sopenharmony_ci default: 15098c2ecf20Sopenharmony_ci goto unlabel_getattr_nolabel; 15108c2ecf20Sopenharmony_ci } 15118c2ecf20Sopenharmony_ci rcu_read_unlock(); 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci secattr->flags |= NETLBL_SECATTR_SECID; 15148c2ecf20Sopenharmony_ci secattr->type = NETLBL_NLTYPE_UNLABELED; 15158c2ecf20Sopenharmony_ci return 0; 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ciunlabel_getattr_nolabel: 15188c2ecf20Sopenharmony_ci rcu_read_unlock(); 15198c2ecf20Sopenharmony_ci if (netlabel_unlabel_acceptflg == 0) 15208c2ecf20Sopenharmony_ci return -ENOMSG; 15218c2ecf20Sopenharmony_ci secattr->type = NETLBL_NLTYPE_UNLABELED; 15228c2ecf20Sopenharmony_ci return 0; 15238c2ecf20Sopenharmony_ci} 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci/** 15268c2ecf20Sopenharmony_ci * netlbl_unlabel_defconf - Set the default config to allow unlabeled packets 15278c2ecf20Sopenharmony_ci * 15288c2ecf20Sopenharmony_ci * Description: 15298c2ecf20Sopenharmony_ci * Set the default NetLabel configuration to allow incoming unlabeled packets 15308c2ecf20Sopenharmony_ci * and to send unlabeled network traffic by default. 15318c2ecf20Sopenharmony_ci * 15328c2ecf20Sopenharmony_ci */ 15338c2ecf20Sopenharmony_ciint __init netlbl_unlabel_defconf(void) 15348c2ecf20Sopenharmony_ci{ 15358c2ecf20Sopenharmony_ci int ret_val; 15368c2ecf20Sopenharmony_ci struct netlbl_dom_map *entry; 15378c2ecf20Sopenharmony_ci struct netlbl_audit audit_info; 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci /* Only the kernel is allowed to call this function and the only time 15408c2ecf20Sopenharmony_ci * it is called is at bootup before the audit subsystem is reporting 15418c2ecf20Sopenharmony_ci * messages so don't worry to much about these values. */ 15428c2ecf20Sopenharmony_ci security_task_getsecid(current, &audit_info.secid); 15438c2ecf20Sopenharmony_ci audit_info.loginuid = GLOBAL_ROOT_UID; 15448c2ecf20Sopenharmony_ci audit_info.sessionid = 0; 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci entry = kzalloc(sizeof(*entry), GFP_KERNEL); 15478c2ecf20Sopenharmony_ci if (entry == NULL) 15488c2ecf20Sopenharmony_ci return -ENOMEM; 15498c2ecf20Sopenharmony_ci entry->family = AF_UNSPEC; 15508c2ecf20Sopenharmony_ci entry->def.type = NETLBL_NLTYPE_UNLABELED; 15518c2ecf20Sopenharmony_ci ret_val = netlbl_domhsh_add_default(entry, &audit_info); 15528c2ecf20Sopenharmony_ci if (ret_val != 0) 15538c2ecf20Sopenharmony_ci return ret_val; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci netlbl_unlabel_acceptflg_set(1, &audit_info); 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci return 0; 15588c2ecf20Sopenharmony_ci} 1559