cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

netlabel_unlabeled.c (42734B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * NetLabel Unlabeled Support
      4 *
      5 * This file defines functions for dealing with unlabeled packets for the
      6 * NetLabel system.  The NetLabel system manages static and dynamic label
      7 * mappings for network protocols such as CIPSO and RIPSO.
      8 *
      9 * Author: Paul Moore <paul@paul-moore.com>
     10 */
     11
     12/*
     13 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 2008
     14 */
     15
     16#include <linux/types.h>
     17#include <linux/rcupdate.h>
     18#include <linux/list.h>
     19#include <linux/spinlock.h>
     20#include <linux/socket.h>
     21#include <linux/string.h>
     22#include <linux/skbuff.h>
     23#include <linux/audit.h>
     24#include <linux/in.h>
     25#include <linux/in6.h>
     26#include <linux/ip.h>
     27#include <linux/ipv6.h>
     28#include <linux/notifier.h>
     29#include <linux/netdevice.h>
     30#include <linux/security.h>
     31#include <linux/slab.h>
     32#include <net/sock.h>
     33#include <net/netlink.h>
     34#include <net/genetlink.h>
     35#include <net/ip.h>
     36#include <net/ipv6.h>
     37#include <net/net_namespace.h>
     38#include <net/netlabel.h>
     39#include <asm/bug.h>
     40#include <linux/atomic.h>
     41
     42#include "netlabel_user.h"
     43#include "netlabel_addrlist.h"
     44#include "netlabel_domainhash.h"
     45#include "netlabel_unlabeled.h"
     46#include "netlabel_mgmt.h"
     47
     48/* NOTE: at present we always use init's network namespace since we don't
     49 *       presently support different namespaces even though the majority of
     50 *       the functions in this file are "namespace safe" */
     51
     52/* The unlabeled connection hash table which we use to map network interfaces
     53 * and addresses of unlabeled packets to a user specified secid value for the
     54 * LSM.  The hash table is used to lookup the network interface entry
     55 * (struct netlbl_unlhsh_iface) and then the interface entry is used to
     56 * lookup an IP address match from an ordered list.  If a network interface
     57 * match can not be found in the hash table then the default entry
     58 * (netlbl_unlhsh_def) is used.  The IP address entry list
     59 * (struct netlbl_unlhsh_addr) is ordered such that the entries with a
     60 * larger netmask come first.
     61 */
     62struct netlbl_unlhsh_tbl {
     63	struct list_head *tbl;
     64	u32 size;
     65};
     66#define netlbl_unlhsh_addr4_entry(iter) \
     67	container_of(iter, struct netlbl_unlhsh_addr4, list)
     68struct netlbl_unlhsh_addr4 {
     69	u32 secid;
     70
     71	struct netlbl_af4list list;
     72	struct rcu_head rcu;
     73};
     74#define netlbl_unlhsh_addr6_entry(iter) \
     75	container_of(iter, struct netlbl_unlhsh_addr6, list)
     76struct netlbl_unlhsh_addr6 {
     77	u32 secid;
     78
     79	struct netlbl_af6list list;
     80	struct rcu_head rcu;
     81};
     82struct netlbl_unlhsh_iface {
     83	int ifindex;
     84	struct list_head addr4_list;
     85	struct list_head addr6_list;
     86
     87	u32 valid;
     88	struct list_head list;
     89	struct rcu_head rcu;
     90};
     91
     92/* Argument struct for netlbl_unlhsh_walk() */
     93struct netlbl_unlhsh_walk_arg {
     94	struct netlink_callback *nl_cb;
     95	struct sk_buff *skb;
     96	u32 seq;
     97};
     98
     99/* Unlabeled connection hash table */
    100/* updates should be so rare that having one spinlock for the entire
    101 * hash table should be okay */
    102static DEFINE_SPINLOCK(netlbl_unlhsh_lock);
    103#define netlbl_unlhsh_rcu_deref(p) \
    104	rcu_dereference_check(p, lockdep_is_held(&netlbl_unlhsh_lock))
    105static struct netlbl_unlhsh_tbl __rcu *netlbl_unlhsh;
    106static struct netlbl_unlhsh_iface __rcu *netlbl_unlhsh_def;
    107
    108/* Accept unlabeled packets flag */
    109static u8 netlabel_unlabel_acceptflg;
    110
    111/* NetLabel Generic NETLINK unlabeled family */
    112static struct genl_family netlbl_unlabel_gnl_family;
    113
    114/* NetLabel Netlink attribute policy */
    115static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = {
    116	[NLBL_UNLABEL_A_ACPTFLG] = { .type = NLA_U8 },
    117	[NLBL_UNLABEL_A_IPV6ADDR] = { .type = NLA_BINARY,
    118				      .len = sizeof(struct in6_addr) },
    119	[NLBL_UNLABEL_A_IPV6MASK] = { .type = NLA_BINARY,
    120				      .len = sizeof(struct in6_addr) },
    121	[NLBL_UNLABEL_A_IPV4ADDR] = { .type = NLA_BINARY,
    122				      .len = sizeof(struct in_addr) },
    123	[NLBL_UNLABEL_A_IPV4MASK] = { .type = NLA_BINARY,
    124				      .len = sizeof(struct in_addr) },
    125	[NLBL_UNLABEL_A_IFACE] = { .type = NLA_NUL_STRING,
    126				   .len = IFNAMSIZ - 1 },
    127	[NLBL_UNLABEL_A_SECCTX] = { .type = NLA_BINARY }
    128};
    129
    130/*
    131 * Unlabeled Connection Hash Table Functions
    132 */
    133
    134/**
    135 * netlbl_unlhsh_free_iface - Frees an interface entry from the hash table
    136 * @entry: the entry's RCU field
    137 *
    138 * Description:
    139 * This function is designed to be used as a callback to the call_rcu()
    140 * function so that memory allocated to a hash table interface entry can be
    141 * released safely.  It is important to note that this function does not free
    142 * the IPv4 and IPv6 address lists contained as part of an interface entry.  It
    143 * is up to the rest of the code to make sure an interface entry is only freed
    144 * once it's address lists are empty.
    145 *
    146 */
    147static void netlbl_unlhsh_free_iface(struct rcu_head *entry)
    148{
    149	struct netlbl_unlhsh_iface *iface;
    150	struct netlbl_af4list *iter4;
    151	struct netlbl_af4list *tmp4;
    152#if IS_ENABLED(CONFIG_IPV6)
    153	struct netlbl_af6list *iter6;
    154	struct netlbl_af6list *tmp6;
    155#endif /* IPv6 */
    156
    157	iface = container_of(entry, struct netlbl_unlhsh_iface, rcu);
    158
    159	/* no need for locks here since we are the only one with access to this
    160	 * structure */
    161
    162	netlbl_af4list_foreach_safe(iter4, tmp4, &iface->addr4_list) {
    163		netlbl_af4list_remove_entry(iter4);
    164		kfree(netlbl_unlhsh_addr4_entry(iter4));
    165	}
    166#if IS_ENABLED(CONFIG_IPV6)
    167	netlbl_af6list_foreach_safe(iter6, tmp6, &iface->addr6_list) {
    168		netlbl_af6list_remove_entry(iter6);
    169		kfree(netlbl_unlhsh_addr6_entry(iter6));
    170	}
    171#endif /* IPv6 */
    172	kfree(iface);
    173}
    174
    175/**
    176 * netlbl_unlhsh_hash - Hashing function for the hash table
    177 * @ifindex: the network interface/device to hash
    178 *
    179 * Description:
    180 * This is the hashing function for the unlabeled hash table, it returns the
    181 * bucket number for the given device/interface.  The caller is responsible for
    182 * ensuring that the hash table is protected with either a RCU read lock or
    183 * the hash table lock.
    184 *
    185 */
    186static u32 netlbl_unlhsh_hash(int ifindex)
    187{
    188	return ifindex & (netlbl_unlhsh_rcu_deref(netlbl_unlhsh)->size - 1);
    189}
    190
    191/**
    192 * netlbl_unlhsh_search_iface - Search for a matching interface entry
    193 * @ifindex: the network interface
    194 *
    195 * Description:
    196 * Searches the unlabeled connection hash table and returns a pointer to the
    197 * interface entry which matches @ifindex, otherwise NULL is returned.  The
    198 * caller is responsible for ensuring that the hash table is protected with
    199 * either a RCU read lock or the hash table lock.
    200 *
    201 */
    202static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex)
    203{
    204	u32 bkt;
    205	struct list_head *bkt_list;
    206	struct netlbl_unlhsh_iface *iter;
    207
    208	bkt = netlbl_unlhsh_hash(ifindex);
    209	bkt_list = &netlbl_unlhsh_rcu_deref(netlbl_unlhsh)->tbl[bkt];
    210	list_for_each_entry_rcu(iter, bkt_list, list,
    211				lockdep_is_held(&netlbl_unlhsh_lock))
    212		if (iter->valid && iter->ifindex == ifindex)
    213			return iter;
    214
    215	return NULL;
    216}
    217
    218/**
    219 * netlbl_unlhsh_add_addr4 - Add a new IPv4 address entry to the hash table
    220 * @iface: the associated interface entry
    221 * @addr: IPv4 address in network byte order
    222 * @mask: IPv4 address mask in network byte order
    223 * @secid: LSM secid value for entry
    224 *
    225 * Description:
    226 * Add a new address entry into the unlabeled connection hash table using the
    227 * interface entry specified by @iface.  On success zero is returned, otherwise
    228 * a negative value is returned.
    229 *
    230 */
    231static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface,
    232				   const struct in_addr *addr,
    233				   const struct in_addr *mask,
    234				   u32 secid)
    235{
    236	int ret_val;
    237	struct netlbl_unlhsh_addr4 *entry;
    238
    239	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
    240	if (entry == NULL)
    241		return -ENOMEM;
    242
    243	entry->list.addr = addr->s_addr & mask->s_addr;
    244	entry->list.mask = mask->s_addr;
    245	entry->list.valid = 1;
    246	entry->secid = secid;
    247
    248	spin_lock(&netlbl_unlhsh_lock);
    249	ret_val = netlbl_af4list_add(&entry->list, &iface->addr4_list);
    250	spin_unlock(&netlbl_unlhsh_lock);
    251
    252	if (ret_val != 0)
    253		kfree(entry);
    254	return ret_val;
    255}
    256
    257#if IS_ENABLED(CONFIG_IPV6)
    258/**
    259 * netlbl_unlhsh_add_addr6 - Add a new IPv6 address entry to the hash table
    260 * @iface: the associated interface entry
    261 * @addr: IPv6 address in network byte order
    262 * @mask: IPv6 address mask in network byte order
    263 * @secid: LSM secid value for entry
    264 *
    265 * Description:
    266 * Add a new address entry into the unlabeled connection hash table using the
    267 * interface entry specified by @iface.  On success zero is returned, otherwise
    268 * a negative value is returned.
    269 *
    270 */
    271static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface,
    272				   const struct in6_addr *addr,
    273				   const struct in6_addr *mask,
    274				   u32 secid)
    275{
    276	int ret_val;
    277	struct netlbl_unlhsh_addr6 *entry;
    278
    279	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
    280	if (entry == NULL)
    281		return -ENOMEM;
    282
    283	entry->list.addr = *addr;
    284	entry->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
    285	entry->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
    286	entry->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
    287	entry->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
    288	entry->list.mask = *mask;
    289	entry->list.valid = 1;
    290	entry->secid = secid;
    291
    292	spin_lock(&netlbl_unlhsh_lock);
    293	ret_val = netlbl_af6list_add(&entry->list, &iface->addr6_list);
    294	spin_unlock(&netlbl_unlhsh_lock);
    295
    296	if (ret_val != 0)
    297		kfree(entry);
    298	return 0;
    299}
    300#endif /* IPv6 */
    301
    302/**
    303 * netlbl_unlhsh_add_iface - Adds a new interface entry to the hash table
    304 * @ifindex: network interface
    305 *
    306 * Description:
    307 * Add a new, empty, interface entry into the unlabeled connection hash table.
    308 * On success a pointer to the new interface entry is returned, on failure NULL
    309 * is returned.
    310 *
    311 */
    312static struct netlbl_unlhsh_iface *netlbl_unlhsh_add_iface(int ifindex)
    313{
    314	u32 bkt;
    315	struct netlbl_unlhsh_iface *iface;
    316
    317	iface = kzalloc(sizeof(*iface), GFP_ATOMIC);
    318	if (iface == NULL)
    319		return NULL;
    320
    321	iface->ifindex = ifindex;
    322	INIT_LIST_HEAD(&iface->addr4_list);
    323	INIT_LIST_HEAD(&iface->addr6_list);
    324	iface->valid = 1;
    325
    326	spin_lock(&netlbl_unlhsh_lock);
    327	if (ifindex > 0) {
    328		bkt = netlbl_unlhsh_hash(ifindex);
    329		if (netlbl_unlhsh_search_iface(ifindex) != NULL)
    330			goto add_iface_failure;
    331		list_add_tail_rcu(&iface->list,
    332			     &netlbl_unlhsh_rcu_deref(netlbl_unlhsh)->tbl[bkt]);
    333	} else {
    334		INIT_LIST_HEAD(&iface->list);
    335		if (netlbl_unlhsh_rcu_deref(netlbl_unlhsh_def) != NULL)
    336			goto add_iface_failure;
    337		rcu_assign_pointer(netlbl_unlhsh_def, iface);
    338	}
    339	spin_unlock(&netlbl_unlhsh_lock);
    340
    341	return iface;
    342
    343add_iface_failure:
    344	spin_unlock(&netlbl_unlhsh_lock);
    345	kfree(iface);
    346	return NULL;
    347}
    348
    349/**
    350 * netlbl_unlhsh_add - Adds a new entry to the unlabeled connection hash table
    351 * @net: network namespace
    352 * @dev_name: interface name
    353 * @addr: IP address in network byte order
    354 * @mask: address mask in network byte order
    355 * @addr_len: length of address/mask (4 for IPv4, 16 for IPv6)
    356 * @secid: LSM secid value for the entry
    357 * @audit_info: NetLabel audit information
    358 *
    359 * Description:
    360 * Adds a new entry to the unlabeled connection hash table.  Returns zero on
    361 * success, negative values on failure.
    362 *
    363 */
    364int netlbl_unlhsh_add(struct net *net,
    365		      const char *dev_name,
    366		      const void *addr,
    367		      const void *mask,
    368		      u32 addr_len,
    369		      u32 secid,
    370		      struct netlbl_audit *audit_info)
    371{
    372	int ret_val;
    373	int ifindex;
    374	struct net_device *dev;
    375	struct netlbl_unlhsh_iface *iface;
    376	struct audit_buffer *audit_buf = NULL;
    377	char *secctx = NULL;
    378	u32 secctx_len;
    379
    380	if (addr_len != sizeof(struct in_addr) &&
    381	    addr_len != sizeof(struct in6_addr))
    382		return -EINVAL;
    383
    384	rcu_read_lock();
    385	if (dev_name != NULL) {
    386		dev = dev_get_by_name_rcu(net, dev_name);
    387		if (dev == NULL) {
    388			ret_val = -ENODEV;
    389			goto unlhsh_add_return;
    390		}
    391		ifindex = dev->ifindex;
    392		iface = netlbl_unlhsh_search_iface(ifindex);
    393	} else {
    394		ifindex = 0;
    395		iface = rcu_dereference(netlbl_unlhsh_def);
    396	}
    397	if (iface == NULL) {
    398		iface = netlbl_unlhsh_add_iface(ifindex);
    399		if (iface == NULL) {
    400			ret_val = -ENOMEM;
    401			goto unlhsh_add_return;
    402		}
    403	}
    404	audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCADD,
    405					      audit_info);
    406	switch (addr_len) {
    407	case sizeof(struct in_addr): {
    408		const struct in_addr *addr4 = addr;
    409		const struct in_addr *mask4 = mask;
    410
    411		ret_val = netlbl_unlhsh_add_addr4(iface, addr4, mask4, secid);
    412		if (audit_buf != NULL)
    413			netlbl_af4list_audit_addr(audit_buf, 1,
    414						  dev_name,
    415						  addr4->s_addr,
    416						  mask4->s_addr);
    417		break;
    418	}
    419#if IS_ENABLED(CONFIG_IPV6)
    420	case sizeof(struct in6_addr): {
    421		const struct in6_addr *addr6 = addr;
    422		const struct in6_addr *mask6 = mask;
    423
    424		ret_val = netlbl_unlhsh_add_addr6(iface, addr6, mask6, secid);
    425		if (audit_buf != NULL)
    426			netlbl_af6list_audit_addr(audit_buf, 1,
    427						  dev_name,
    428						  addr6, mask6);
    429		break;
    430	}
    431#endif /* IPv6 */
    432	default:
    433		ret_val = -EINVAL;
    434	}
    435	if (ret_val == 0)
    436		atomic_inc(&netlabel_mgmt_protocount);
    437
    438unlhsh_add_return:
    439	rcu_read_unlock();
    440	if (audit_buf != NULL) {
    441		if (security_secid_to_secctx(secid,
    442					     &secctx,
    443					     &secctx_len) == 0) {
    444			audit_log_format(audit_buf, " sec_obj=%s", secctx);
    445			security_release_secctx(secctx, secctx_len);
    446		}
    447		audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
    448		audit_log_end(audit_buf);
    449	}
    450	return ret_val;
    451}
    452
    453/**
    454 * netlbl_unlhsh_remove_addr4 - Remove an IPv4 address entry
    455 * @net: network namespace
    456 * @iface: interface entry
    457 * @addr: IP address
    458 * @mask: IP address mask
    459 * @audit_info: NetLabel audit information
    460 *
    461 * Description:
    462 * Remove an IP address entry from the unlabeled connection hash table.
    463 * Returns zero on success, negative values on failure.
    464 *
    465 */
    466static int netlbl_unlhsh_remove_addr4(struct net *net,
    467				      struct netlbl_unlhsh_iface *iface,
    468				      const struct in_addr *addr,
    469				      const struct in_addr *mask,
    470				      struct netlbl_audit *audit_info)
    471{
    472	struct netlbl_af4list *list_entry;
    473	struct netlbl_unlhsh_addr4 *entry;
    474	struct audit_buffer *audit_buf;
    475	struct net_device *dev;
    476	char *secctx;
    477	u32 secctx_len;
    478
    479	spin_lock(&netlbl_unlhsh_lock);
    480	list_entry = netlbl_af4list_remove(addr->s_addr, mask->s_addr,
    481					   &iface->addr4_list);
    482	spin_unlock(&netlbl_unlhsh_lock);
    483	if (list_entry != NULL)
    484		entry = netlbl_unlhsh_addr4_entry(list_entry);
    485	else
    486		entry = NULL;
    487
    488	audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
    489					      audit_info);
    490	if (audit_buf != NULL) {
    491		dev = dev_get_by_index(net, iface->ifindex);
    492		netlbl_af4list_audit_addr(audit_buf, 1,
    493					  (dev != NULL ? dev->name : NULL),
    494					  addr->s_addr, mask->s_addr);
    495		dev_put(dev);
    496		if (entry != NULL &&
    497		    security_secid_to_secctx(entry->secid,
    498					     &secctx, &secctx_len) == 0) {
    499			audit_log_format(audit_buf, " sec_obj=%s", secctx);
    500			security_release_secctx(secctx, secctx_len);
    501		}
    502		audit_log_format(audit_buf, " res=%u", entry != NULL ? 1 : 0);
    503		audit_log_end(audit_buf);
    504	}
    505
    506	if (entry == NULL)
    507		return -ENOENT;
    508
    509	kfree_rcu(entry, rcu);
    510	return 0;
    511}
    512
    513#if IS_ENABLED(CONFIG_IPV6)
    514/**
    515 * netlbl_unlhsh_remove_addr6 - Remove an IPv6 address entry
    516 * @net: network namespace
    517 * @iface: interface entry
    518 * @addr: IP address
    519 * @mask: IP address mask
    520 * @audit_info: NetLabel audit information
    521 *
    522 * Description:
    523 * Remove an IP address entry from the unlabeled connection hash table.
    524 * Returns zero on success, negative values on failure.
    525 *
    526 */
    527static int netlbl_unlhsh_remove_addr6(struct net *net,
    528				      struct netlbl_unlhsh_iface *iface,
    529				      const struct in6_addr *addr,
    530				      const struct in6_addr *mask,
    531				      struct netlbl_audit *audit_info)
    532{
    533	struct netlbl_af6list *list_entry;
    534	struct netlbl_unlhsh_addr6 *entry;
    535	struct audit_buffer *audit_buf;
    536	struct net_device *dev;
    537	char *secctx;
    538	u32 secctx_len;
    539
    540	spin_lock(&netlbl_unlhsh_lock);
    541	list_entry = netlbl_af6list_remove(addr, mask, &iface->addr6_list);
    542	spin_unlock(&netlbl_unlhsh_lock);
    543	if (list_entry != NULL)
    544		entry = netlbl_unlhsh_addr6_entry(list_entry);
    545	else
    546		entry = NULL;
    547
    548	audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
    549					      audit_info);
    550	if (audit_buf != NULL) {
    551		dev = dev_get_by_index(net, iface->ifindex);
    552		netlbl_af6list_audit_addr(audit_buf, 1,
    553					  (dev != NULL ? dev->name : NULL),
    554					  addr, mask);
    555		dev_put(dev);
    556		if (entry != NULL &&
    557		    security_secid_to_secctx(entry->secid,
    558					     &secctx, &secctx_len) == 0) {
    559			audit_log_format(audit_buf, " sec_obj=%s", secctx);
    560			security_release_secctx(secctx, secctx_len);
    561		}
    562		audit_log_format(audit_buf, " res=%u", entry != NULL ? 1 : 0);
    563		audit_log_end(audit_buf);
    564	}
    565
    566	if (entry == NULL)
    567		return -ENOENT;
    568
    569	kfree_rcu(entry, rcu);
    570	return 0;
    571}
    572#endif /* IPv6 */
    573
    574/**
    575 * netlbl_unlhsh_condremove_iface - Remove an interface entry
    576 * @iface: the interface entry
    577 *
    578 * Description:
    579 * Remove an interface entry from the unlabeled connection hash table if it is
    580 * empty.  An interface entry is considered to be empty if there are no
    581 * address entries assigned to it.
    582 *
    583 */
    584static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface)
    585{
    586	struct netlbl_af4list *iter4;
    587#if IS_ENABLED(CONFIG_IPV6)
    588	struct netlbl_af6list *iter6;
    589#endif /* IPv6 */
    590
    591	spin_lock(&netlbl_unlhsh_lock);
    592	netlbl_af4list_foreach_rcu(iter4, &iface->addr4_list)
    593		goto unlhsh_condremove_failure;
    594#if IS_ENABLED(CONFIG_IPV6)
    595	netlbl_af6list_foreach_rcu(iter6, &iface->addr6_list)
    596		goto unlhsh_condremove_failure;
    597#endif /* IPv6 */
    598	iface->valid = 0;
    599	if (iface->ifindex > 0)
    600		list_del_rcu(&iface->list);
    601	else
    602		RCU_INIT_POINTER(netlbl_unlhsh_def, NULL);
    603	spin_unlock(&netlbl_unlhsh_lock);
    604
    605	call_rcu(&iface->rcu, netlbl_unlhsh_free_iface);
    606	return;
    607
    608unlhsh_condremove_failure:
    609	spin_unlock(&netlbl_unlhsh_lock);
    610}
    611
    612/**
    613 * netlbl_unlhsh_remove - Remove an entry from the unlabeled hash table
    614 * @net: network namespace
    615 * @dev_name: interface name
    616 * @addr: IP address in network byte order
    617 * @mask: address mask in network byte order
    618 * @addr_len: length of address/mask (4 for IPv4, 16 for IPv6)
    619 * @audit_info: NetLabel audit information
    620 *
    621 * Description:
    622 * Removes and existing entry from the unlabeled connection hash table.
    623 * Returns zero on success, negative values on failure.
    624 *
    625 */
    626int netlbl_unlhsh_remove(struct net *net,
    627			 const char *dev_name,
    628			 const void *addr,
    629			 const void *mask,
    630			 u32 addr_len,
    631			 struct netlbl_audit *audit_info)
    632{
    633	int ret_val;
    634	struct net_device *dev;
    635	struct netlbl_unlhsh_iface *iface;
    636
    637	if (addr_len != sizeof(struct in_addr) &&
    638	    addr_len != sizeof(struct in6_addr))
    639		return -EINVAL;
    640
    641	rcu_read_lock();
    642	if (dev_name != NULL) {
    643		dev = dev_get_by_name_rcu(net, dev_name);
    644		if (dev == NULL) {
    645			ret_val = -ENODEV;
    646			goto unlhsh_remove_return;
    647		}
    648		iface = netlbl_unlhsh_search_iface(dev->ifindex);
    649	} else
    650		iface = rcu_dereference(netlbl_unlhsh_def);
    651	if (iface == NULL) {
    652		ret_val = -ENOENT;
    653		goto unlhsh_remove_return;
    654	}
    655	switch (addr_len) {
    656	case sizeof(struct in_addr):
    657		ret_val = netlbl_unlhsh_remove_addr4(net,
    658						     iface, addr, mask,
    659						     audit_info);
    660		break;
    661#if IS_ENABLED(CONFIG_IPV6)
    662	case sizeof(struct in6_addr):
    663		ret_val = netlbl_unlhsh_remove_addr6(net,
    664						     iface, addr, mask,
    665						     audit_info);
    666		break;
    667#endif /* IPv6 */
    668	default:
    669		ret_val = -EINVAL;
    670	}
    671	if (ret_val == 0) {
    672		netlbl_unlhsh_condremove_iface(iface);
    673		atomic_dec(&netlabel_mgmt_protocount);
    674	}
    675
    676unlhsh_remove_return:
    677	rcu_read_unlock();
    678	return ret_val;
    679}
    680
    681/*
    682 * General Helper Functions
    683 */
    684
    685/**
    686 * netlbl_unlhsh_netdev_handler - Network device notification handler
    687 * @this: notifier block
    688 * @event: the event
    689 * @ptr: the netdevice notifier info (cast to void)
    690 *
    691 * Description:
    692 * Handle network device events, although at present all we care about is a
    693 * network device going away.  In the case of a device going away we clear any
    694 * related entries from the unlabeled connection hash table.
    695 *
    696 */
    697static int netlbl_unlhsh_netdev_handler(struct notifier_block *this,
    698					unsigned long event, void *ptr)
    699{
    700	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
    701	struct netlbl_unlhsh_iface *iface = NULL;
    702
    703	if (!net_eq(dev_net(dev), &init_net))
    704		return NOTIFY_DONE;
    705
    706	/* XXX - should this be a check for NETDEV_DOWN or _UNREGISTER? */
    707	if (event == NETDEV_DOWN) {
    708		spin_lock(&netlbl_unlhsh_lock);
    709		iface = netlbl_unlhsh_search_iface(dev->ifindex);
    710		if (iface != NULL && iface->valid) {
    711			iface->valid = 0;
    712			list_del_rcu(&iface->list);
    713		} else
    714			iface = NULL;
    715		spin_unlock(&netlbl_unlhsh_lock);
    716	}
    717
    718	if (iface != NULL)
    719		call_rcu(&iface->rcu, netlbl_unlhsh_free_iface);
    720
    721	return NOTIFY_DONE;
    722}
    723
    724/**
    725 * netlbl_unlabel_acceptflg_set - Set the unlabeled accept flag
    726 * @value: desired value
    727 * @audit_info: NetLabel audit information
    728 *
    729 * Description:
    730 * Set the value of the unlabeled accept flag to @value.
    731 *
    732 */
    733static void netlbl_unlabel_acceptflg_set(u8 value,
    734					 struct netlbl_audit *audit_info)
    735{
    736	struct audit_buffer *audit_buf;
    737	u8 old_val;
    738
    739	old_val = netlabel_unlabel_acceptflg;
    740	netlabel_unlabel_acceptflg = value;
    741	audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_ALLOW,
    742					      audit_info);
    743	if (audit_buf != NULL) {
    744		audit_log_format(audit_buf,
    745				 " unlbl_accept=%u old=%u", value, old_val);
    746		audit_log_end(audit_buf);
    747	}
    748}
    749
    750/**
    751 * netlbl_unlabel_addrinfo_get - Get the IPv4/6 address information
    752 * @info: the Generic NETLINK info block
    753 * @addr: the IP address
    754 * @mask: the IP address mask
    755 * @len: the address length
    756 *
    757 * Description:
    758 * Examine the Generic NETLINK message and extract the IP address information.
    759 * Returns zero on success, negative values on failure.
    760 *
    761 */
    762static int netlbl_unlabel_addrinfo_get(struct genl_info *info,
    763				       void **addr,
    764				       void **mask,
    765				       u32 *len)
    766{
    767	u32 addr_len;
    768
    769	if (info->attrs[NLBL_UNLABEL_A_IPV4ADDR] &&
    770	    info->attrs[NLBL_UNLABEL_A_IPV4MASK]) {
    771		addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]);
    772		if (addr_len != sizeof(struct in_addr) &&
    773		    addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV4MASK]))
    774			return -EINVAL;
    775		*len = addr_len;
    776		*addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]);
    777		*mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4MASK]);
    778		return 0;
    779	} else if (info->attrs[NLBL_UNLABEL_A_IPV6ADDR]) {
    780		addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]);
    781		if (addr_len != sizeof(struct in6_addr) &&
    782		    addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV6MASK]))
    783			return -EINVAL;
    784		*len = addr_len;
    785		*addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]);
    786		*mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6MASK]);
    787		return 0;
    788	}
    789
    790	return -EINVAL;
    791}
    792
    793/*
    794 * NetLabel Command Handlers
    795 */
    796
    797/**
    798 * netlbl_unlabel_accept - Handle an ACCEPT message
    799 * @skb: the NETLINK buffer
    800 * @info: the Generic NETLINK info block
    801 *
    802 * Description:
    803 * Process a user generated ACCEPT message and set the accept flag accordingly.
    804 * Returns zero on success, negative values on failure.
    805 *
    806 */
    807static int netlbl_unlabel_accept(struct sk_buff *skb, struct genl_info *info)
    808{
    809	u8 value;
    810	struct netlbl_audit audit_info;
    811
    812	if (info->attrs[NLBL_UNLABEL_A_ACPTFLG]) {
    813		value = nla_get_u8(info->attrs[NLBL_UNLABEL_A_ACPTFLG]);
    814		if (value == 1 || value == 0) {
    815			netlbl_netlink_auditinfo(&audit_info);
    816			netlbl_unlabel_acceptflg_set(value, &audit_info);
    817			return 0;
    818		}
    819	}
    820
    821	return -EINVAL;
    822}
    823
    824/**
    825 * netlbl_unlabel_list - Handle a LIST message
    826 * @skb: the NETLINK buffer
    827 * @info: the Generic NETLINK info block
    828 *
    829 * Description:
    830 * Process a user generated LIST message and respond with the current status.
    831 * Returns zero on success, negative values on failure.
    832 *
    833 */
    834static int netlbl_unlabel_list(struct sk_buff *skb, struct genl_info *info)
    835{
    836	int ret_val = -EINVAL;
    837	struct sk_buff *ans_skb;
    838	void *data;
    839
    840	ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
    841	if (ans_skb == NULL)
    842		goto list_failure;
    843	data = genlmsg_put_reply(ans_skb, info, &netlbl_unlabel_gnl_family,
    844				 0, NLBL_UNLABEL_C_LIST);
    845	if (data == NULL) {
    846		ret_val = -ENOMEM;
    847		goto list_failure;
    848	}
    849
    850	ret_val = nla_put_u8(ans_skb,
    851			     NLBL_UNLABEL_A_ACPTFLG,
    852			     netlabel_unlabel_acceptflg);
    853	if (ret_val != 0)
    854		goto list_failure;
    855
    856	genlmsg_end(ans_skb, data);
    857	return genlmsg_reply(ans_skb, info);
    858
    859list_failure:
    860	kfree_skb(ans_skb);
    861	return ret_val;
    862}
    863
    864/**
    865 * netlbl_unlabel_staticadd - Handle a STATICADD message
    866 * @skb: the NETLINK buffer
    867 * @info: the Generic NETLINK info block
    868 *
    869 * Description:
    870 * Process a user generated STATICADD message and add a new unlabeled
    871 * connection entry to the hash table.  Returns zero on success, negative
    872 * values on failure.
    873 *
    874 */
    875static int netlbl_unlabel_staticadd(struct sk_buff *skb,
    876				    struct genl_info *info)
    877{
    878	int ret_val;
    879	char *dev_name;
    880	void *addr;
    881	void *mask;
    882	u32 addr_len;
    883	u32 secid;
    884	struct netlbl_audit audit_info;
    885
    886	/* Don't allow users to add both IPv4 and IPv6 addresses for a
    887	 * single entry.  However, allow users to create two entries, one each
    888	 * for IPv4 and IPv4, with the same LSM security context which should
    889	 * achieve the same result. */
    890	if (!info->attrs[NLBL_UNLABEL_A_SECCTX] ||
    891	    !info->attrs[NLBL_UNLABEL_A_IFACE] ||
    892	    !((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
    893	       !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
    894	      (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
    895	       !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
    896		return -EINVAL;
    897
    898	netlbl_netlink_auditinfo(&audit_info);
    899
    900	ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
    901	if (ret_val != 0)
    902		return ret_val;
    903	dev_name = nla_data(info->attrs[NLBL_UNLABEL_A_IFACE]);
    904	ret_val = security_secctx_to_secid(
    905		                  nla_data(info->attrs[NLBL_UNLABEL_A_SECCTX]),
    906				  nla_len(info->attrs[NLBL_UNLABEL_A_SECCTX]),
    907				  &secid);
    908	if (ret_val != 0)
    909		return ret_val;
    910
    911	return netlbl_unlhsh_add(&init_net,
    912				 dev_name, addr, mask, addr_len, secid,
    913				 &audit_info);
    914}
    915
    916/**
    917 * netlbl_unlabel_staticadddef - Handle a STATICADDDEF message
    918 * @skb: the NETLINK buffer
    919 * @info: the Generic NETLINK info block
    920 *
    921 * Description:
    922 * Process a user generated STATICADDDEF message and add a new default
    923 * unlabeled connection entry.  Returns zero on success, negative values on
    924 * failure.
    925 *
    926 */
    927static int netlbl_unlabel_staticadddef(struct sk_buff *skb,
    928				       struct genl_info *info)
    929{
    930	int ret_val;
    931	void *addr;
    932	void *mask;
    933	u32 addr_len;
    934	u32 secid;
    935	struct netlbl_audit audit_info;
    936
    937	/* Don't allow users to add both IPv4 and IPv6 addresses for a
    938	 * single entry.  However, allow users to create two entries, one each
    939	 * for IPv4 and IPv6, with the same LSM security context which should
    940	 * achieve the same result. */
    941	if (!info->attrs[NLBL_UNLABEL_A_SECCTX] ||
    942	    !((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
    943	       !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
    944	      (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
    945	       !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
    946		return -EINVAL;
    947
    948	netlbl_netlink_auditinfo(&audit_info);
    949
    950	ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
    951	if (ret_val != 0)
    952		return ret_val;
    953	ret_val = security_secctx_to_secid(
    954		                  nla_data(info->attrs[NLBL_UNLABEL_A_SECCTX]),
    955				  nla_len(info->attrs[NLBL_UNLABEL_A_SECCTX]),
    956				  &secid);
    957	if (ret_val != 0)
    958		return ret_val;
    959
    960	return netlbl_unlhsh_add(&init_net,
    961				 NULL, addr, mask, addr_len, secid,
    962				 &audit_info);
    963}
    964
    965/**
    966 * netlbl_unlabel_staticremove - Handle a STATICREMOVE message
    967 * @skb: the NETLINK buffer
    968 * @info: the Generic NETLINK info block
    969 *
    970 * Description:
    971 * Process a user generated STATICREMOVE message and remove the specified
    972 * unlabeled connection entry.  Returns zero on success, negative values on
    973 * failure.
    974 *
    975 */
    976static int netlbl_unlabel_staticremove(struct sk_buff *skb,
    977				       struct genl_info *info)
    978{
    979	int ret_val;
    980	char *dev_name;
    981	void *addr;
    982	void *mask;
    983	u32 addr_len;
    984	struct netlbl_audit audit_info;
    985
    986	/* See the note in netlbl_unlabel_staticadd() about not allowing both
    987	 * IPv4 and IPv6 in the same entry. */
    988	if (!info->attrs[NLBL_UNLABEL_A_IFACE] ||
    989	    !((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
    990	       !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
    991	      (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
    992	       !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
    993		return -EINVAL;
    994
    995	netlbl_netlink_auditinfo(&audit_info);
    996
    997	ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
    998	if (ret_val != 0)
    999		return ret_val;
   1000	dev_name = nla_data(info->attrs[NLBL_UNLABEL_A_IFACE]);
   1001
   1002	return netlbl_unlhsh_remove(&init_net,
   1003				    dev_name, addr, mask, addr_len,
   1004				    &audit_info);
   1005}
   1006
   1007/**
   1008 * netlbl_unlabel_staticremovedef - Handle a STATICREMOVEDEF message
   1009 * @skb: the NETLINK buffer
   1010 * @info: the Generic NETLINK info block
   1011 *
   1012 * Description:
   1013 * Process a user generated STATICREMOVEDEF message and remove the default
   1014 * unlabeled connection entry.  Returns zero on success, negative values on
   1015 * failure.
   1016 *
   1017 */
   1018static int netlbl_unlabel_staticremovedef(struct sk_buff *skb,
   1019					  struct genl_info *info)
   1020{
   1021	int ret_val;
   1022	void *addr;
   1023	void *mask;
   1024	u32 addr_len;
   1025	struct netlbl_audit audit_info;
   1026
   1027	/* See the note in netlbl_unlabel_staticadd() about not allowing both
   1028	 * IPv4 and IPv6 in the same entry. */
   1029	if (!((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
   1030	       !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
   1031	      (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
   1032	       !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
   1033		return -EINVAL;
   1034
   1035	netlbl_netlink_auditinfo(&audit_info);
   1036
   1037	ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
   1038	if (ret_val != 0)
   1039		return ret_val;
   1040
   1041	return netlbl_unlhsh_remove(&init_net,
   1042				    NULL, addr, mask, addr_len,
   1043				    &audit_info);
   1044}
   1045
   1046
   1047/**
   1048 * netlbl_unlabel_staticlist_gen - Generate messages for STATICLIST[DEF]
   1049 * @cmd: command/message
   1050 * @iface: the interface entry
   1051 * @addr4: the IPv4 address entry
   1052 * @addr6: the IPv6 address entry
   1053 * @arg: the netlbl_unlhsh_walk_arg structure
   1054 *
   1055 * Description:
   1056 * This function is designed to be used to generate a response for a
   1057 * STATICLIST or STATICLISTDEF message.  When called either @addr4 or @addr6
   1058 * can be specified, not both, the other unspecified entry should be set to
   1059 * NULL by the caller.  Returns the size of the message on success, negative
   1060 * values on failure.
   1061 *
   1062 */
   1063static int netlbl_unlabel_staticlist_gen(u32 cmd,
   1064				       const struct netlbl_unlhsh_iface *iface,
   1065				       const struct netlbl_unlhsh_addr4 *addr4,
   1066				       const struct netlbl_unlhsh_addr6 *addr6,
   1067				       void *arg)
   1068{
   1069	int ret_val = -ENOMEM;
   1070	struct netlbl_unlhsh_walk_arg *cb_arg = arg;
   1071	struct net_device *dev;
   1072	void *data;
   1073	u32 secid;
   1074	char *secctx;
   1075	u32 secctx_len;
   1076
   1077	data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
   1078			   cb_arg->seq, &netlbl_unlabel_gnl_family,
   1079			   NLM_F_MULTI, cmd);
   1080	if (data == NULL)
   1081		goto list_cb_failure;
   1082
   1083	if (iface->ifindex > 0) {
   1084		dev = dev_get_by_index(&init_net, iface->ifindex);
   1085		if (!dev) {
   1086			ret_val = -ENODEV;
   1087			goto list_cb_failure;
   1088		}
   1089		ret_val = nla_put_string(cb_arg->skb,
   1090					 NLBL_UNLABEL_A_IFACE, dev->name);
   1091		dev_put(dev);
   1092		if (ret_val != 0)
   1093			goto list_cb_failure;
   1094	}
   1095
   1096	if (addr4) {
   1097		struct in_addr addr_struct;
   1098
   1099		addr_struct.s_addr = addr4->list.addr;
   1100		ret_val = nla_put_in_addr(cb_arg->skb,
   1101					  NLBL_UNLABEL_A_IPV4ADDR,
   1102					  addr_struct.s_addr);
   1103		if (ret_val != 0)
   1104			goto list_cb_failure;
   1105
   1106		addr_struct.s_addr = addr4->list.mask;
   1107		ret_val = nla_put_in_addr(cb_arg->skb,
   1108					  NLBL_UNLABEL_A_IPV4MASK,
   1109					  addr_struct.s_addr);
   1110		if (ret_val != 0)
   1111			goto list_cb_failure;
   1112
   1113		secid = addr4->secid;
   1114	} else {
   1115		ret_val = nla_put_in6_addr(cb_arg->skb,
   1116					   NLBL_UNLABEL_A_IPV6ADDR,
   1117					   &addr6->list.addr);
   1118		if (ret_val != 0)
   1119			goto list_cb_failure;
   1120
   1121		ret_val = nla_put_in6_addr(cb_arg->skb,
   1122					   NLBL_UNLABEL_A_IPV6MASK,
   1123					   &addr6->list.mask);
   1124		if (ret_val != 0)
   1125			goto list_cb_failure;
   1126
   1127		secid = addr6->secid;
   1128	}
   1129
   1130	ret_val = security_secid_to_secctx(secid, &secctx, &secctx_len);
   1131	if (ret_val != 0)
   1132		goto list_cb_failure;
   1133	ret_val = nla_put(cb_arg->skb,
   1134			  NLBL_UNLABEL_A_SECCTX,
   1135			  secctx_len,
   1136			  secctx);
   1137	security_release_secctx(secctx, secctx_len);
   1138	if (ret_val != 0)
   1139		goto list_cb_failure;
   1140
   1141	cb_arg->seq++;
   1142	genlmsg_end(cb_arg->skb, data);
   1143	return 0;
   1144
   1145list_cb_failure:
   1146	genlmsg_cancel(cb_arg->skb, data);
   1147	return ret_val;
   1148}
   1149
   1150/**
   1151 * netlbl_unlabel_staticlist - Handle a STATICLIST message
   1152 * @skb: the NETLINK buffer
   1153 * @cb: the NETLINK callback
   1154 *
   1155 * Description:
   1156 * Process a user generated STATICLIST message and dump the unlabeled
   1157 * connection hash table in a form suitable for use in a kernel generated
   1158 * STATICLIST message.  Returns the length of @skb.
   1159 *
   1160 */
   1161static int netlbl_unlabel_staticlist(struct sk_buff *skb,
   1162				     struct netlink_callback *cb)
   1163{
   1164	struct netlbl_unlhsh_walk_arg cb_arg;
   1165	u32 skip_bkt = cb->args[0];
   1166	u32 skip_chain = cb->args[1];
   1167	u32 skip_addr4 = cb->args[2];
   1168	u32 iter_bkt, iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0;
   1169	struct netlbl_unlhsh_iface *iface;
   1170	struct list_head *iter_list;
   1171	struct netlbl_af4list *addr4;
   1172#if IS_ENABLED(CONFIG_IPV6)
   1173	u32 skip_addr6 = cb->args[3];
   1174	struct netlbl_af6list *addr6;
   1175#endif
   1176
   1177	cb_arg.nl_cb = cb;
   1178	cb_arg.skb = skb;
   1179	cb_arg.seq = cb->nlh->nlmsg_seq;
   1180
   1181	rcu_read_lock();
   1182	for (iter_bkt = skip_bkt;
   1183	     iter_bkt < rcu_dereference(netlbl_unlhsh)->size;
   1184	     iter_bkt++) {
   1185		iter_list = &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt];
   1186		list_for_each_entry_rcu(iface, iter_list, list) {
   1187			if (!iface->valid ||
   1188			    iter_chain++ < skip_chain)
   1189				continue;
   1190			netlbl_af4list_foreach_rcu(addr4,
   1191						   &iface->addr4_list) {
   1192				if (iter_addr4++ < skip_addr4)
   1193					continue;
   1194				if (netlbl_unlabel_staticlist_gen(
   1195					      NLBL_UNLABEL_C_STATICLIST,
   1196					      iface,
   1197					      netlbl_unlhsh_addr4_entry(addr4),
   1198					      NULL,
   1199					      &cb_arg) < 0) {
   1200					iter_addr4--;
   1201					iter_chain--;
   1202					goto unlabel_staticlist_return;
   1203				}
   1204			}
   1205			iter_addr4 = 0;
   1206			skip_addr4 = 0;
   1207#if IS_ENABLED(CONFIG_IPV6)
   1208			netlbl_af6list_foreach_rcu(addr6,
   1209						   &iface->addr6_list) {
   1210				if (iter_addr6++ < skip_addr6)
   1211					continue;
   1212				if (netlbl_unlabel_staticlist_gen(
   1213					      NLBL_UNLABEL_C_STATICLIST,
   1214					      iface,
   1215					      NULL,
   1216					      netlbl_unlhsh_addr6_entry(addr6),
   1217					      &cb_arg) < 0) {
   1218					iter_addr6--;
   1219					iter_chain--;
   1220					goto unlabel_staticlist_return;
   1221				}
   1222			}
   1223			iter_addr6 = 0;
   1224			skip_addr6 = 0;
   1225#endif /* IPv6 */
   1226		}
   1227		iter_chain = 0;
   1228		skip_chain = 0;
   1229	}
   1230
   1231unlabel_staticlist_return:
   1232	rcu_read_unlock();
   1233	cb->args[0] = iter_bkt;
   1234	cb->args[1] = iter_chain;
   1235	cb->args[2] = iter_addr4;
   1236	cb->args[3] = iter_addr6;
   1237	return skb->len;
   1238}
   1239
   1240/**
   1241 * netlbl_unlabel_staticlistdef - Handle a STATICLISTDEF message
   1242 * @skb: the NETLINK buffer
   1243 * @cb: the NETLINK callback
   1244 *
   1245 * Description:
   1246 * Process a user generated STATICLISTDEF message and dump the default
   1247 * unlabeled connection entry in a form suitable for use in a kernel generated
   1248 * STATICLISTDEF message.  Returns the length of @skb.
   1249 *
   1250 */
   1251static int netlbl_unlabel_staticlistdef(struct sk_buff *skb,
   1252					struct netlink_callback *cb)
   1253{
   1254	struct netlbl_unlhsh_walk_arg cb_arg;
   1255	struct netlbl_unlhsh_iface *iface;
   1256	u32 iter_addr4 = 0, iter_addr6 = 0;
   1257	struct netlbl_af4list *addr4;
   1258#if IS_ENABLED(CONFIG_IPV6)
   1259	struct netlbl_af6list *addr6;
   1260#endif
   1261
   1262	cb_arg.nl_cb = cb;
   1263	cb_arg.skb = skb;
   1264	cb_arg.seq = cb->nlh->nlmsg_seq;
   1265
   1266	rcu_read_lock();
   1267	iface = rcu_dereference(netlbl_unlhsh_def);
   1268	if (iface == NULL || !iface->valid)
   1269		goto unlabel_staticlistdef_return;
   1270
   1271	netlbl_af4list_foreach_rcu(addr4, &iface->addr4_list) {
   1272		if (iter_addr4++ < cb->args[0])
   1273			continue;
   1274		if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
   1275					      iface,
   1276					      netlbl_unlhsh_addr4_entry(addr4),
   1277					      NULL,
   1278					      &cb_arg) < 0) {
   1279			iter_addr4--;
   1280			goto unlabel_staticlistdef_return;
   1281		}
   1282	}
   1283#if IS_ENABLED(CONFIG_IPV6)
   1284	netlbl_af6list_foreach_rcu(addr6, &iface->addr6_list) {
   1285		if (iter_addr6++ < cb->args[1])
   1286			continue;
   1287		if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
   1288					      iface,
   1289					      NULL,
   1290					      netlbl_unlhsh_addr6_entry(addr6),
   1291					      &cb_arg) < 0) {
   1292			iter_addr6--;
   1293			goto unlabel_staticlistdef_return;
   1294		}
   1295	}
   1296#endif /* IPv6 */
   1297
   1298unlabel_staticlistdef_return:
   1299	rcu_read_unlock();
   1300	cb->args[0] = iter_addr4;
   1301	cb->args[1] = iter_addr6;
   1302	return skb->len;
   1303}
   1304
   1305/*
   1306 * NetLabel Generic NETLINK Command Definitions
   1307 */
   1308
   1309static const struct genl_small_ops netlbl_unlabel_genl_ops[] = {
   1310	{
   1311	.cmd = NLBL_UNLABEL_C_STATICADD,
   1312	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   1313	.flags = GENL_ADMIN_PERM,
   1314	.doit = netlbl_unlabel_staticadd,
   1315	.dumpit = NULL,
   1316	},
   1317	{
   1318	.cmd = NLBL_UNLABEL_C_STATICREMOVE,
   1319	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   1320	.flags = GENL_ADMIN_PERM,
   1321	.doit = netlbl_unlabel_staticremove,
   1322	.dumpit = NULL,
   1323	},
   1324	{
   1325	.cmd = NLBL_UNLABEL_C_STATICLIST,
   1326	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   1327	.flags = 0,
   1328	.doit = NULL,
   1329	.dumpit = netlbl_unlabel_staticlist,
   1330	},
   1331	{
   1332	.cmd = NLBL_UNLABEL_C_STATICADDDEF,
   1333	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   1334	.flags = GENL_ADMIN_PERM,
   1335	.doit = netlbl_unlabel_staticadddef,
   1336	.dumpit = NULL,
   1337	},
   1338	{
   1339	.cmd = NLBL_UNLABEL_C_STATICREMOVEDEF,
   1340	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   1341	.flags = GENL_ADMIN_PERM,
   1342	.doit = netlbl_unlabel_staticremovedef,
   1343	.dumpit = NULL,
   1344	},
   1345	{
   1346	.cmd = NLBL_UNLABEL_C_STATICLISTDEF,
   1347	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   1348	.flags = 0,
   1349	.doit = NULL,
   1350	.dumpit = netlbl_unlabel_staticlistdef,
   1351	},
   1352	{
   1353	.cmd = NLBL_UNLABEL_C_ACCEPT,
   1354	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   1355	.flags = GENL_ADMIN_PERM,
   1356	.doit = netlbl_unlabel_accept,
   1357	.dumpit = NULL,
   1358	},
   1359	{
   1360	.cmd = NLBL_UNLABEL_C_LIST,
   1361	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
   1362	.flags = 0,
   1363	.doit = netlbl_unlabel_list,
   1364	.dumpit = NULL,
   1365	},
   1366};
   1367
   1368static struct genl_family netlbl_unlabel_gnl_family __ro_after_init = {
   1369	.hdrsize = 0,
   1370	.name = NETLBL_NLTYPE_UNLABELED_NAME,
   1371	.version = NETLBL_PROTO_VERSION,
   1372	.maxattr = NLBL_UNLABEL_A_MAX,
   1373	.policy = netlbl_unlabel_genl_policy,
   1374	.module = THIS_MODULE,
   1375	.small_ops = netlbl_unlabel_genl_ops,
   1376	.n_small_ops = ARRAY_SIZE(netlbl_unlabel_genl_ops),
   1377};
   1378
   1379/*
   1380 * NetLabel Generic NETLINK Protocol Functions
   1381 */
   1382
   1383/**
   1384 * netlbl_unlabel_genl_init - Register the Unlabeled NetLabel component
   1385 *
   1386 * Description:
   1387 * Register the unlabeled packet NetLabel component with the Generic NETLINK
   1388 * mechanism.  Returns zero on success, negative values on failure.
   1389 *
   1390 */
   1391int __init netlbl_unlabel_genl_init(void)
   1392{
   1393	return genl_register_family(&netlbl_unlabel_gnl_family);
   1394}
   1395
   1396/*
   1397 * NetLabel KAPI Hooks
   1398 */
   1399
   1400static struct notifier_block netlbl_unlhsh_netdev_notifier = {
   1401	.notifier_call = netlbl_unlhsh_netdev_handler,
   1402};
   1403
   1404/**
   1405 * netlbl_unlabel_init - Initialize the unlabeled connection hash table
   1406 * @size: the number of bits to use for the hash buckets
   1407 *
   1408 * Description:
   1409 * Initializes the unlabeled connection hash table and registers a network
   1410 * device notification handler.  This function should only be called by the
   1411 * NetLabel subsystem itself during initialization.  Returns zero on success,
   1412 * non-zero values on error.
   1413 *
   1414 */
   1415int __init netlbl_unlabel_init(u32 size)
   1416{
   1417	u32 iter;
   1418	struct netlbl_unlhsh_tbl *hsh_tbl;
   1419
   1420	if (size == 0)
   1421		return -EINVAL;
   1422
   1423	hsh_tbl = kmalloc(sizeof(*hsh_tbl), GFP_KERNEL);
   1424	if (hsh_tbl == NULL)
   1425		return -ENOMEM;
   1426	hsh_tbl->size = 1 << size;
   1427	hsh_tbl->tbl = kcalloc(hsh_tbl->size,
   1428			       sizeof(struct list_head),
   1429			       GFP_KERNEL);
   1430	if (hsh_tbl->tbl == NULL) {
   1431		kfree(hsh_tbl);
   1432		return -ENOMEM;
   1433	}
   1434	for (iter = 0; iter < hsh_tbl->size; iter++)
   1435		INIT_LIST_HEAD(&hsh_tbl->tbl[iter]);
   1436
   1437	spin_lock(&netlbl_unlhsh_lock);
   1438	rcu_assign_pointer(netlbl_unlhsh, hsh_tbl);
   1439	spin_unlock(&netlbl_unlhsh_lock);
   1440
   1441	register_netdevice_notifier(&netlbl_unlhsh_netdev_notifier);
   1442
   1443	return 0;
   1444}
   1445
   1446/**
   1447 * netlbl_unlabel_getattr - Get the security attributes for an unlabled packet
   1448 * @skb: the packet
   1449 * @family: protocol family
   1450 * @secattr: the security attributes
   1451 *
   1452 * Description:
   1453 * Determine the security attributes, if any, for an unlabled packet and return
   1454 * them in @secattr.  Returns zero on success and negative values on failure.
   1455 *
   1456 */
   1457int netlbl_unlabel_getattr(const struct sk_buff *skb,
   1458			   u16 family,
   1459			   struct netlbl_lsm_secattr *secattr)
   1460{
   1461	struct netlbl_unlhsh_iface *iface;
   1462
   1463	rcu_read_lock();
   1464	iface = netlbl_unlhsh_search_iface(skb->skb_iif);
   1465	if (iface == NULL)
   1466		iface = rcu_dereference(netlbl_unlhsh_def);
   1467	if (iface == NULL || !iface->valid)
   1468		goto unlabel_getattr_nolabel;
   1469
   1470#if IS_ENABLED(CONFIG_IPV6)
   1471	/* When resolving a fallback label, check the sk_buff version as
   1472	 * it is possible (e.g. SCTP) to have family = PF_INET6 while
   1473	 * receiving ip_hdr(skb)->version = 4.
   1474	 */
   1475	if (family == PF_INET6 && ip_hdr(skb)->version == 4)
   1476		family = PF_INET;
   1477#endif /* IPv6 */
   1478
   1479	switch (family) {
   1480	case PF_INET: {
   1481		struct iphdr *hdr4;
   1482		struct netlbl_af4list *addr4;
   1483
   1484		hdr4 = ip_hdr(skb);
   1485		addr4 = netlbl_af4list_search(hdr4->saddr,
   1486					      &iface->addr4_list);
   1487		if (addr4 == NULL)
   1488			goto unlabel_getattr_nolabel;
   1489		secattr->attr.secid = netlbl_unlhsh_addr4_entry(addr4)->secid;
   1490		break;
   1491	}
   1492#if IS_ENABLED(CONFIG_IPV6)
   1493	case PF_INET6: {
   1494		struct ipv6hdr *hdr6;
   1495		struct netlbl_af6list *addr6;
   1496
   1497		hdr6 = ipv6_hdr(skb);
   1498		addr6 = netlbl_af6list_search(&hdr6->saddr,
   1499					      &iface->addr6_list);
   1500		if (addr6 == NULL)
   1501			goto unlabel_getattr_nolabel;
   1502		secattr->attr.secid = netlbl_unlhsh_addr6_entry(addr6)->secid;
   1503		break;
   1504	}
   1505#endif /* IPv6 */
   1506	default:
   1507		goto unlabel_getattr_nolabel;
   1508	}
   1509	rcu_read_unlock();
   1510
   1511	secattr->flags |= NETLBL_SECATTR_SECID;
   1512	secattr->type = NETLBL_NLTYPE_UNLABELED;
   1513	return 0;
   1514
   1515unlabel_getattr_nolabel:
   1516	rcu_read_unlock();
   1517	if (netlabel_unlabel_acceptflg == 0)
   1518		return -ENOMSG;
   1519	secattr->type = NETLBL_NLTYPE_UNLABELED;
   1520	return 0;
   1521}
   1522
   1523/**
   1524 * netlbl_unlabel_defconf - Set the default config to allow unlabeled packets
   1525 *
   1526 * Description:
   1527 * Set the default NetLabel configuration to allow incoming unlabeled packets
   1528 * and to send unlabeled network traffic by default.
   1529 *
   1530 */
   1531int __init netlbl_unlabel_defconf(void)
   1532{
   1533	int ret_val;
   1534	struct netlbl_dom_map *entry;
   1535	struct netlbl_audit audit_info;
   1536
   1537	/* Only the kernel is allowed to call this function and the only time
   1538	 * it is called is at bootup before the audit subsystem is reporting
   1539	 * messages so don't worry to much about these values. */
   1540	security_current_getsecid_subj(&audit_info.secid);
   1541	audit_info.loginuid = GLOBAL_ROOT_UID;
   1542	audit_info.sessionid = 0;
   1543
   1544	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
   1545	if (entry == NULL)
   1546		return -ENOMEM;
   1547	entry->family = AF_UNSPEC;
   1548	entry->def.type = NETLBL_NLTYPE_UNLABELED;
   1549	ret_val = netlbl_domhsh_add_default(entry, &audit_info);
   1550	if (ret_val != 0)
   1551		return ret_val;
   1552
   1553	netlbl_unlabel_acceptflg_set(1, &audit_info);
   1554
   1555	return 0;
   1556}