File Index
Files and directories
Sign in
FILE

netlabel_unlabeled.c

File preview with syntax highlighting.

linux-6.19.14/net/netlabel/netlabel_unlabeled.c C
   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	struct lsm_context ctx;
 378
 379	if (addr_len != sizeof(struct in_addr) &&
 380	    addr_len != sizeof(struct in6_addr))
 381		return -EINVAL;
 382
 383	rcu_read_lock();
 384	if (dev_name != NULL) {
 385		dev = dev_get_by_name_rcu(net, dev_name);
 386		if (dev == NULL) {
 387			ret_val = -ENODEV;
 388			goto unlhsh_add_return;
 389		}
 390		ifindex = dev->ifindex;
 391		iface = netlbl_unlhsh_search_iface(ifindex);
 392	} else {
 393		ifindex = 0;
 394		iface = rcu_dereference(netlbl_unlhsh_def);
 395	}
 396	if (iface == NULL) {
 397		iface = netlbl_unlhsh_add_iface(ifindex);
 398		if (iface == NULL) {
 399			ret_val = -ENOMEM;
 400			goto unlhsh_add_return;
 401		}
 402	}
 403	audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCADD,
 404					      audit_info);
 405	switch (addr_len) {
 406	case sizeof(struct in_addr): {
 407		const struct in_addr *addr4 = addr;
 408		const struct in_addr *mask4 = mask;
 409
 410		ret_val = netlbl_unlhsh_add_addr4(iface, addr4, mask4, secid);
 411		if (audit_buf != NULL)
 412			netlbl_af4list_audit_addr(audit_buf, 1,
 413						  dev_name,
 414						  addr4->s_addr,
 415						  mask4->s_addr);
 416		break;
 417	}
 418#if IS_ENABLED(CONFIG_IPV6)
 419	case sizeof(struct in6_addr): {
 420		const struct in6_addr *addr6 = addr;
 421		const struct in6_addr *mask6 = mask;
 422
 423		ret_val = netlbl_unlhsh_add_addr6(iface, addr6, mask6, secid);
 424		if (audit_buf != NULL)
 425			netlbl_af6list_audit_addr(audit_buf, 1,
 426						  dev_name,
 427						  addr6, mask6);
 428		break;
 429	}
 430#endif /* IPv6 */
 431	default:
 432		ret_val = -EINVAL;
 433	}
 434	if (ret_val == 0)
 435		atomic_inc(&netlabel_mgmt_protocount);
 436
 437unlhsh_add_return:
 438	rcu_read_unlock();
 439	if (audit_buf != NULL) {
 440		if (security_secid_to_secctx(secid, &ctx) >= 0) {
 441			audit_log_format(audit_buf, " sec_obj=%s", ctx.context);
 442			security_release_secctx(&ctx);
 443		}
 444		audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
 445		audit_log_end(audit_buf);
 446	}
 447	return ret_val;
 448}
 449
 450/**
 451 * netlbl_unlhsh_remove_addr4 - Remove an IPv4 address entry
 452 * @net: network namespace
 453 * @iface: interface entry
 454 * @addr: IP address
 455 * @mask: IP address mask
 456 * @audit_info: NetLabel audit information
 457 *
 458 * Description:
 459 * Remove an IP address entry from the unlabeled connection hash table.
 460 * Returns zero on success, negative values on failure.
 461 *
 462 */
 463static int netlbl_unlhsh_remove_addr4(struct net *net,
 464				      struct netlbl_unlhsh_iface *iface,
 465				      const struct in_addr *addr,
 466				      const struct in_addr *mask,
 467				      struct netlbl_audit *audit_info)
 468{
 469	struct netlbl_af4list *list_entry;
 470	struct netlbl_unlhsh_addr4 *entry;
 471	struct audit_buffer *audit_buf;
 472	struct net_device *dev;
 473	struct lsm_context ctx;
 474
 475	spin_lock(&netlbl_unlhsh_lock);
 476	list_entry = netlbl_af4list_remove(addr->s_addr, mask->s_addr,
 477					   &iface->addr4_list);
 478	spin_unlock(&netlbl_unlhsh_lock);
 479	if (list_entry != NULL)
 480		entry = netlbl_unlhsh_addr4_entry(list_entry);
 481	else
 482		entry = NULL;
 483
 484	audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
 485					      audit_info);
 486	if (audit_buf != NULL) {
 487		dev = dev_get_by_index(net, iface->ifindex);
 488		netlbl_af4list_audit_addr(audit_buf, 1,
 489					  (dev != NULL ? dev->name : NULL),
 490					  addr->s_addr, mask->s_addr);
 491		dev_put(dev);
 492		if (entry != NULL &&
 493		    security_secid_to_secctx(entry->secid, &ctx) >= 0) {
 494			audit_log_format(audit_buf, " sec_obj=%s", ctx.context);
 495			security_release_secctx(&ctx);
 496		}
 497		audit_log_format(audit_buf, " res=%u", entry != NULL ? 1 : 0);
 498		audit_log_end(audit_buf);
 499	}
 500
 501	if (entry == NULL)
 502		return -ENOENT;
 503
 504	kfree_rcu(entry, rcu);
 505	return 0;
 506}
 507
 508#if IS_ENABLED(CONFIG_IPV6)
 509/**
 510 * netlbl_unlhsh_remove_addr6 - Remove an IPv6 address entry
 511 * @net: network namespace
 512 * @iface: interface entry
 513 * @addr: IP address
 514 * @mask: IP address mask
 515 * @audit_info: NetLabel audit information
 516 *
 517 * Description:
 518 * Remove an IP address entry from the unlabeled connection hash table.
 519 * Returns zero on success, negative values on failure.
 520 *
 521 */
 522static int netlbl_unlhsh_remove_addr6(struct net *net,
 523				      struct netlbl_unlhsh_iface *iface,
 524				      const struct in6_addr *addr,
 525				      const struct in6_addr *mask,
 526				      struct netlbl_audit *audit_info)
 527{
 528	struct netlbl_af6list *list_entry;
 529	struct netlbl_unlhsh_addr6 *entry;
 530	struct audit_buffer *audit_buf;
 531	struct net_device *dev;
 532	struct lsm_context ctx;
 533
 534	spin_lock(&netlbl_unlhsh_lock);
 535	list_entry = netlbl_af6list_remove(addr, mask, &iface->addr6_list);
 536	spin_unlock(&netlbl_unlhsh_lock);
 537	if (list_entry != NULL)
 538		entry = netlbl_unlhsh_addr6_entry(list_entry);
 539	else
 540		entry = NULL;
 541
 542	audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
 543					      audit_info);
 544	if (audit_buf != NULL) {
 545		dev = dev_get_by_index(net, iface->ifindex);
 546		netlbl_af6list_audit_addr(audit_buf, 1,
 547					  (dev != NULL ? dev->name : NULL),
 548					  addr, mask);
 549		dev_put(dev);
 550		if (entry != NULL &&
 551		    security_secid_to_secctx(entry->secid, &ctx) >= 0) {
 552			audit_log_format(audit_buf, " sec_obj=%s", ctx.context);
 553			security_release_secctx(&ctx);
 554		}
 555		audit_log_format(audit_buf, " res=%u", entry != NULL ? 1 : 0);
 556		audit_log_end(audit_buf);
 557	}
 558
 559	if (entry == NULL)
 560		return -ENOENT;
 561
 562	kfree_rcu(entry, rcu);
 563	return 0;
 564}
 565#endif /* IPv6 */
 566
 567/**
 568 * netlbl_unlhsh_condremove_iface - Remove an interface entry
 569 * @iface: the interface entry
 570 *
 571 * Description:
 572 * Remove an interface entry from the unlabeled connection hash table if it is
 573 * empty.  An interface entry is considered to be empty if there are no
 574 * address entries assigned to it.
 575 *
 576 */
 577static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface)
 578{
 579	struct netlbl_af4list *iter4;
 580#if IS_ENABLED(CONFIG_IPV6)
 581	struct netlbl_af6list *iter6;
 582#endif /* IPv6 */
 583
 584	spin_lock(&netlbl_unlhsh_lock);
 585	netlbl_af4list_foreach_rcu(iter4, &iface->addr4_list)
 586		goto unlhsh_condremove_failure;
 587#if IS_ENABLED(CONFIG_IPV6)
 588	netlbl_af6list_foreach_rcu(iter6, &iface->addr6_list)
 589		goto unlhsh_condremove_failure;
 590#endif /* IPv6 */
 591	iface->valid = 0;
 592	if (iface->ifindex > 0)
 593		list_del_rcu(&iface->list);
 594	else
 595		RCU_INIT_POINTER(netlbl_unlhsh_def, NULL);
 596	spin_unlock(&netlbl_unlhsh_lock);
 597
 598	call_rcu(&iface->rcu, netlbl_unlhsh_free_iface);
 599	return;
 600
 601unlhsh_condremove_failure:
 602	spin_unlock(&netlbl_unlhsh_lock);
 603}
 604
 605/**
 606 * netlbl_unlhsh_remove - Remove an entry from the unlabeled hash table
 607 * @net: network namespace
 608 * @dev_name: interface name
 609 * @addr: IP address in network byte order
 610 * @mask: address mask in network byte order
 611 * @addr_len: length of address/mask (4 for IPv4, 16 for IPv6)
 612 * @audit_info: NetLabel audit information
 613 *
 614 * Description:
 615 * Removes and existing entry from the unlabeled connection hash table.
 616 * Returns zero on success, negative values on failure.
 617 *
 618 */
 619int netlbl_unlhsh_remove(struct net *net,
 620			 const char *dev_name,
 621			 const void *addr,
 622			 const void *mask,
 623			 u32 addr_len,
 624			 struct netlbl_audit *audit_info)
 625{
 626	int ret_val;
 627	struct net_device *dev;
 628	struct netlbl_unlhsh_iface *iface;
 629
 630	if (addr_len != sizeof(struct in_addr) &&
 631	    addr_len != sizeof(struct in6_addr))
 632		return -EINVAL;
 633
 634	rcu_read_lock();
 635	if (dev_name != NULL) {
 636		dev = dev_get_by_name_rcu(net, dev_name);
 637		if (dev == NULL) {
 638			ret_val = -ENODEV;
 639			goto unlhsh_remove_return;
 640		}
 641		iface = netlbl_unlhsh_search_iface(dev->ifindex);
 642	} else
 643		iface = rcu_dereference(netlbl_unlhsh_def);
 644	if (iface == NULL) {
 645		ret_val = -ENOENT;
 646		goto unlhsh_remove_return;
 647	}
 648	switch (addr_len) {
 649	case sizeof(struct in_addr):
 650		ret_val = netlbl_unlhsh_remove_addr4(net,
 651						     iface, addr, mask,
 652						     audit_info);
 653		break;
 654#if IS_ENABLED(CONFIG_IPV6)
 655	case sizeof(struct in6_addr):
 656		ret_val = netlbl_unlhsh_remove_addr6(net,
 657						     iface, addr, mask,
 658						     audit_info);
 659		break;
 660#endif /* IPv6 */
 661	default:
 662		ret_val = -EINVAL;
 663	}
 664	if (ret_val == 0) {
 665		netlbl_unlhsh_condremove_iface(iface);
 666		atomic_dec(&netlabel_mgmt_protocount);
 667	}
 668
 669unlhsh_remove_return:
 670	rcu_read_unlock();
 671	return ret_val;
 672}
 673
 674/*
 675 * General Helper Functions
 676 */
 677
 678/**
 679 * netlbl_unlhsh_netdev_handler - Network device notification handler
 680 * @this: notifier block
 681 * @event: the event
 682 * @ptr: the netdevice notifier info (cast to void)
 683 *
 684 * Description:
 685 * Handle network device events, although at present all we care about is a
 686 * network device going away.  In the case of a device going away we clear any
 687 * related entries from the unlabeled connection hash table.
 688 *
 689 */
 690static int netlbl_unlhsh_netdev_handler(struct notifier_block *this,
 691					unsigned long event, void *ptr)
 692{
 693	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
 694	struct netlbl_unlhsh_iface *iface = NULL;
 695
 696	if (!net_eq(dev_net(dev), &init_net))
 697		return NOTIFY_DONE;
 698
 699	/* XXX - should this be a check for NETDEV_DOWN or _UNREGISTER? */
 700	if (event == NETDEV_DOWN) {
 701		spin_lock(&netlbl_unlhsh_lock);
 702		iface = netlbl_unlhsh_search_iface(dev->ifindex);
 703		if (iface != NULL && iface->valid) {
 704			iface->valid = 0;
 705			list_del_rcu(&iface->list);
 706		} else
 707			iface = NULL;
 708		spin_unlock(&netlbl_unlhsh_lock);
 709	}
 710
 711	if (iface != NULL)
 712		call_rcu(&iface->rcu, netlbl_unlhsh_free_iface);
 713
 714	return NOTIFY_DONE;
 715}
 716
 717/**
 718 * netlbl_unlabel_acceptflg_set - Set the unlabeled accept flag
 719 * @value: desired value
 720 * @audit_info: NetLabel audit information
 721 *
 722 * Description:
 723 * Set the value of the unlabeled accept flag to @value.
 724 *
 725 */
 726static void netlbl_unlabel_acceptflg_set(u8 value,
 727					 struct netlbl_audit *audit_info)
 728{
 729	struct audit_buffer *audit_buf;
 730	u8 old_val;
 731
 732	old_val = netlabel_unlabel_acceptflg;
 733	netlabel_unlabel_acceptflg = value;
 734	audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_ALLOW,
 735					      audit_info);
 736	if (audit_buf != NULL) {
 737		audit_log_format(audit_buf,
 738				 " unlbl_accept=%u old=%u", value, old_val);
 739		audit_log_end(audit_buf);
 740	}
 741}
 742
 743/**
 744 * netlbl_unlabel_addrinfo_get - Get the IPv4/6 address information
 745 * @info: the Generic NETLINK info block
 746 * @addr: the IP address
 747 * @mask: the IP address mask
 748 * @len: the address length
 749 *
 750 * Description:
 751 * Examine the Generic NETLINK message and extract the IP address information.
 752 * Returns zero on success, negative values on failure.
 753 *
 754 */
 755static int netlbl_unlabel_addrinfo_get(struct genl_info *info,
 756				       void **addr,
 757				       void **mask,
 758				       u32 *len)
 759{
 760	u32 addr_len;
 761
 762	if (info->attrs[NLBL_UNLABEL_A_IPV4ADDR] &&
 763	    info->attrs[NLBL_UNLABEL_A_IPV4MASK]) {
 764		addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]);
 765		if (addr_len != sizeof(struct in_addr) &&
 766		    addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV4MASK]))
 767			return -EINVAL;
 768		*len = addr_len;
 769		*addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]);
 770		*mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4MASK]);
 771		return 0;
 772	} else if (info->attrs[NLBL_UNLABEL_A_IPV6ADDR]) {
 773		addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]);
 774		if (addr_len != sizeof(struct in6_addr) &&
 775		    addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV6MASK]))
 776			return -EINVAL;
 777		*len = addr_len;
 778		*addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]);
 779		*mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6MASK]);
 780		return 0;
 781	}
 782
 783	return -EINVAL;
 784}
 785
 786/*
 787 * NetLabel Command Handlers
 788 */
 789
 790/**
 791 * netlbl_unlabel_accept - Handle an ACCEPT message
 792 * @skb: the NETLINK buffer
 793 * @info: the Generic NETLINK info block
 794 *
 795 * Description:
 796 * Process a user generated ACCEPT message and set the accept flag accordingly.
 797 * Returns zero on success, negative values on failure.
 798 *
 799 */
 800static int netlbl_unlabel_accept(struct sk_buff *skb, struct genl_info *info)
 801{
 802	u8 value;
 803	struct netlbl_audit audit_info;
 804
 805	if (info->attrs[NLBL_UNLABEL_A_ACPTFLG]) {
 806		value = nla_get_u8(info->attrs[NLBL_UNLABEL_A_ACPTFLG]);
 807		if (value == 1 || value == 0) {
 808			netlbl_netlink_auditinfo(&audit_info);
 809			netlbl_unlabel_acceptflg_set(value, &audit_info);
 810			return 0;
 811		}
 812	}
 813
 814	return -EINVAL;
 815}
 816
 817/**
 818 * netlbl_unlabel_list - Handle a LIST message
 819 * @skb: the NETLINK buffer
 820 * @info: the Generic NETLINK info block
 821 *
 822 * Description:
 823 * Process a user generated LIST message and respond with the current status.
 824 * Returns zero on success, negative values on failure.
 825 *
 826 */
 827static int netlbl_unlabel_list(struct sk_buff *skb, struct genl_info *info)
 828{
 829	int ret_val = -EINVAL;
 830	struct sk_buff *ans_skb;
 831	void *data;
 832
 833	ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 834	if (ans_skb == NULL)
 835		goto list_failure;
 836	data = genlmsg_put_reply(ans_skb, info, &netlbl_unlabel_gnl_family,
 837				 0, NLBL_UNLABEL_C_LIST);
 838	if (data == NULL) {
 839		ret_val = -ENOMEM;
 840		goto list_failure;
 841	}
 842
 843	ret_val = nla_put_u8(ans_skb,
 844			     NLBL_UNLABEL_A_ACPTFLG,
 845			     netlabel_unlabel_acceptflg);
 846	if (ret_val != 0)
 847		goto list_failure;
 848
 849	genlmsg_end(ans_skb, data);
 850	return genlmsg_reply(ans_skb, info);
 851
 852list_failure:
 853	kfree_skb(ans_skb);
 854	return ret_val;
 855}
 856
 857/**
 858 * netlbl_unlabel_staticadd - Handle a STATICADD message
 859 * @skb: the NETLINK buffer
 860 * @info: the Generic NETLINK info block
 861 *
 862 * Description:
 863 * Process a user generated STATICADD message and add a new unlabeled
 864 * connection entry to the hash table.  Returns zero on success, negative
 865 * values on failure.
 866 *
 867 */
 868static int netlbl_unlabel_staticadd(struct sk_buff *skb,
 869				    struct genl_info *info)
 870{
 871	int ret_val;
 872	char *dev_name;
 873	void *addr;
 874	void *mask;
 875	u32 addr_len;
 876	u32 secid;
 877	struct netlbl_audit audit_info;
 878
 879	/* Don't allow users to add both IPv4 and IPv6 addresses for a
 880	 * single entry.  However, allow users to create two entries, one each
 881	 * for IPv4 and IPv6, with the same LSM security context which should
 882	 * achieve the same result. */
 883	if (!info->attrs[NLBL_UNLABEL_A_SECCTX] ||
 884	    !info->attrs[NLBL_UNLABEL_A_IFACE] ||
 885	    !((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
 886	       !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
 887	      (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
 888	       !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
 889		return -EINVAL;
 890
 891	netlbl_netlink_auditinfo(&audit_info);
 892
 893	ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
 894	if (ret_val != 0)
 895		return ret_val;
 896	dev_name = nla_data(info->attrs[NLBL_UNLABEL_A_IFACE]);
 897	ret_val = security_secctx_to_secid(
 898		                  nla_data(info->attrs[NLBL_UNLABEL_A_SECCTX]),
 899				  nla_len(info->attrs[NLBL_UNLABEL_A_SECCTX]),
 900				  &secid);
 901	if (ret_val != 0)
 902		return ret_val;
 903
 904	return netlbl_unlhsh_add(&init_net,
 905				 dev_name, addr, mask, addr_len, secid,
 906				 &audit_info);
 907}
 908
 909/**
 910 * netlbl_unlabel_staticadddef - Handle a STATICADDDEF message
 911 * @skb: the NETLINK buffer
 912 * @info: the Generic NETLINK info block
 913 *
 914 * Description:
 915 * Process a user generated STATICADDDEF message and add a new default
 916 * unlabeled connection entry.  Returns zero on success, negative values on
 917 * failure.
 918 *
 919 */
 920static int netlbl_unlabel_staticadddef(struct sk_buff *skb,
 921				       struct genl_info *info)
 922{
 923	int ret_val;
 924	void *addr;
 925	void *mask;
 926	u32 addr_len;
 927	u32 secid;
 928	struct netlbl_audit audit_info;
 929
 930	/* Don't allow users to add both IPv4 and IPv6 addresses for a
 931	 * single entry.  However, allow users to create two entries, one each
 932	 * for IPv4 and IPv6, with the same LSM security context which should
 933	 * achieve the same result. */
 934	if (!info->attrs[NLBL_UNLABEL_A_SECCTX] ||
 935	    !((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
 936	       !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
 937	      (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
 938	       !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
 939		return -EINVAL;
 940
 941	netlbl_netlink_auditinfo(&audit_info);
 942
 943	ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
 944	if (ret_val != 0)
 945		return ret_val;
 946	ret_val = security_secctx_to_secid(
 947		                  nla_data(info->attrs[NLBL_UNLABEL_A_SECCTX]),
 948				  nla_len(info->attrs[NLBL_UNLABEL_A_SECCTX]),
 949				  &secid);
 950	if (ret_val != 0)
 951		return ret_val;
 952
 953	return netlbl_unlhsh_add(&init_net,
 954				 NULL, addr, mask, addr_len, secid,
 955				 &audit_info);
 956}
 957
 958/**
 959 * netlbl_unlabel_staticremove - Handle a STATICREMOVE message
 960 * @skb: the NETLINK buffer
 961 * @info: the Generic NETLINK info block
 962 *
 963 * Description:
 964 * Process a user generated STATICREMOVE message and remove the specified
 965 * unlabeled connection entry.  Returns zero on success, negative values on
 966 * failure.
 967 *
 968 */
 969static int netlbl_unlabel_staticremove(struct sk_buff *skb,
 970				       struct genl_info *info)
 971{
 972	int ret_val;
 973	char *dev_name;
 974	void *addr;
 975	void *mask;
 976	u32 addr_len;
 977	struct netlbl_audit audit_info;
 978
 979	/* See the note in netlbl_unlabel_staticadd() about not allowing both
 980	 * IPv4 and IPv6 in the same entry. */
 981	if (!info->attrs[NLBL_UNLABEL_A_IFACE] ||
 982	    !((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
 983	       !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
 984	      (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
 985	       !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
 986		return -EINVAL;
 987
 988	netlbl_netlink_auditinfo(&audit_info);
 989
 990	ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
 991	if (ret_val != 0)
 992		return ret_val;
 993	dev_name = nla_data(info->attrs[NLBL_UNLABEL_A_IFACE]);
 994
 995	return netlbl_unlhsh_remove(&init_net,
 996				    dev_name, addr, mask, addr_len,
 997				    &audit_info);
 998}
 999
1000/**
1001 * netlbl_unlabel_staticremovedef - Handle a STATICREMOVEDEF message
1002 * @skb: the NETLINK buffer
1003 * @info: the Generic NETLINK info block
1004 *
1005 * Description:
1006 * Process a user generated STATICREMOVEDEF message and remove the default
1007 * unlabeled connection entry.  Returns zero on success, negative values on
1008 * failure.
1009 *
1010 */
1011static int netlbl_unlabel_staticremovedef(struct sk_buff *skb,
1012					  struct genl_info *info)
1013{
1014	int ret_val;
1015	void *addr;
1016	void *mask;
1017	u32 addr_len;
1018	struct netlbl_audit audit_info;
1019
1020	/* See the note in netlbl_unlabel_staticadd() about not allowing both
1021	 * IPv4 and IPv6 in the same entry. */
1022	if (!((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
1023	       !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
1024	      (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
1025	       !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
1026		return -EINVAL;
1027
1028	netlbl_netlink_auditinfo(&audit_info);
1029
1030	ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
1031	if (ret_val != 0)
1032		return ret_val;
1033
1034	return netlbl_unlhsh_remove(&init_net,
1035				    NULL, addr, mask, addr_len,
1036				    &audit_info);
1037}
1038
1039
1040/**
1041 * netlbl_unlabel_staticlist_gen - Generate messages for STATICLIST[DEF]
1042 * @cmd: command/message
1043 * @iface: the interface entry
1044 * @addr4: the IPv4 address entry
1045 * @addr6: the IPv6 address entry
1046 * @arg: the netlbl_unlhsh_walk_arg structure
1047 *
1048 * Description:
1049 * This function is designed to be used to generate a response for a
1050 * STATICLIST or STATICLISTDEF message.  When called either @addr4 or @addr6
1051 * can be specified, not both, the other unspecified entry should be set to
1052 * NULL by the caller.  Returns the size of the message on success, negative
1053 * values on failure.
1054 *
1055 */
1056static int netlbl_unlabel_staticlist_gen(u32 cmd,
1057				       const struct netlbl_unlhsh_iface *iface,
1058				       const struct netlbl_unlhsh_addr4 *addr4,
1059				       const struct netlbl_unlhsh_addr6 *addr6,
1060				       void *arg)
1061{
1062	int ret_val = -ENOMEM;
1063	struct netlbl_unlhsh_walk_arg *cb_arg = arg;
1064	struct net_device *dev;
1065	struct lsm_context ctx;
1066	void *data;
1067	u32 secid;
1068
1069	data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
1070			   cb_arg->seq, &netlbl_unlabel_gnl_family,
1071			   NLM_F_MULTI, cmd);
1072	if (data == NULL)
1073		goto list_cb_failure;
1074
1075	if (iface->ifindex > 0) {
1076		dev = dev_get_by_index(&init_net, iface->ifindex);
1077		if (!dev) {
1078			ret_val = -ENODEV;
1079			goto list_cb_failure;
1080		}
1081		ret_val = nla_put_string(cb_arg->skb,
1082					 NLBL_UNLABEL_A_IFACE, dev->name);
1083		dev_put(dev);
1084		if (ret_val != 0)
1085			goto list_cb_failure;
1086	}
1087
1088	if (addr4) {
1089		struct in_addr addr_struct;
1090
1091		addr_struct.s_addr = addr4->list.addr;
1092		ret_val = nla_put_in_addr(cb_arg->skb,
1093					  NLBL_UNLABEL_A_IPV4ADDR,
1094					  addr_struct.s_addr);
1095		if (ret_val != 0)
1096			goto list_cb_failure;
1097
1098		addr_struct.s_addr = addr4->list.mask;
1099		ret_val = nla_put_in_addr(cb_arg->skb,
1100					  NLBL_UNLABEL_A_IPV4MASK,
1101					  addr_struct.s_addr);
1102		if (ret_val != 0)
1103			goto list_cb_failure;
1104
1105		secid = addr4->secid;
1106	} else {
1107		ret_val = nla_put_in6_addr(cb_arg->skb,
1108					   NLBL_UNLABEL_A_IPV6ADDR,
1109					   &addr6->list.addr);
1110		if (ret_val != 0)
1111			goto list_cb_failure;
1112
1113		ret_val = nla_put_in6_addr(cb_arg->skb,
1114					   NLBL_UNLABEL_A_IPV6MASK,
1115					   &addr6->list.mask);
1116		if (ret_val != 0)
1117			goto list_cb_failure;
1118
1119		secid = addr6->secid;
1120	}
1121
1122	ret_val = security_secid_to_secctx(secid, &ctx);
1123	if (ret_val < 0)
1124		goto list_cb_failure;
1125	ret_val = nla_put(cb_arg->skb,
1126			  NLBL_UNLABEL_A_SECCTX,
1127			  ctx.len,
1128			  ctx.context);
1129	security_release_secctx(&ctx);
1130	if (ret_val != 0)
1131		goto list_cb_failure;
1132
1133	cb_arg->seq++;
1134	genlmsg_end(cb_arg->skb, data);
1135	return 0;
1136
1137list_cb_failure:
1138	genlmsg_cancel(cb_arg->skb, data);
1139	return ret_val;
1140}
1141
1142/**
1143 * netlbl_unlabel_staticlist - Handle a STATICLIST message
1144 * @skb: the NETLINK buffer
1145 * @cb: the NETLINK callback
1146 *
1147 * Description:
1148 * Process a user generated STATICLIST message and dump the unlabeled
1149 * connection hash table in a form suitable for use in a kernel generated
1150 * STATICLIST message.  Returns the length of @skb.
1151 *
1152 */
1153static int netlbl_unlabel_staticlist(struct sk_buff *skb,
1154				     struct netlink_callback *cb)
1155{
1156	struct netlbl_unlhsh_walk_arg cb_arg;
1157	u32 skip_bkt = cb->args[0];
1158	u32 skip_chain = cb->args[1];
1159	u32 skip_addr4 = cb->args[2];
1160	u32 iter_bkt, iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0;
1161	struct netlbl_unlhsh_iface *iface;
1162	struct list_head *iter_list;
1163	struct netlbl_af4list *addr4;
1164#if IS_ENABLED(CONFIG_IPV6)
1165	u32 skip_addr6 = cb->args[3];
1166	struct netlbl_af6list *addr6;
1167#endif
1168
1169	cb_arg.nl_cb = cb;
1170	cb_arg.skb = skb;
1171	cb_arg.seq = cb->nlh->nlmsg_seq;
1172
1173	rcu_read_lock();
1174	for (iter_bkt = skip_bkt;
1175	     iter_bkt < rcu_dereference(netlbl_unlhsh)->size;
1176	     iter_bkt++) {
1177		iter_list = &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt];
1178		list_for_each_entry_rcu(iface, iter_list, list) {
1179			if (!iface->valid ||
1180			    iter_chain++ < skip_chain)
1181				continue;
1182			netlbl_af4list_foreach_rcu(addr4,
1183						   &iface->addr4_list) {
1184				if (iter_addr4++ < skip_addr4)
1185					continue;
1186				if (netlbl_unlabel_staticlist_gen(
1187					      NLBL_UNLABEL_C_STATICLIST,
1188					      iface,
1189					      netlbl_unlhsh_addr4_entry(addr4),
1190					      NULL,
1191					      &cb_arg) < 0) {
1192					iter_addr4--;
1193					iter_chain--;
1194					goto unlabel_staticlist_return;
1195				}
1196			}
1197			iter_addr4 = 0;
1198			skip_addr4 = 0;
1199#if IS_ENABLED(CONFIG_IPV6)
1200			netlbl_af6list_foreach_rcu(addr6,
1201						   &iface->addr6_list) {
1202				if (iter_addr6++ < skip_addr6)
1203					continue;
1204				if (netlbl_unlabel_staticlist_gen(
1205					      NLBL_UNLABEL_C_STATICLIST,
1206					      iface,
1207					      NULL,
1208					      netlbl_unlhsh_addr6_entry(addr6),
1209					      &cb_arg) < 0) {
1210					iter_addr6--;
1211					iter_chain--;
1212					goto unlabel_staticlist_return;
1213				}
1214			}
1215			iter_addr6 = 0;
1216			skip_addr6 = 0;
1217#endif /* IPv6 */
1218		}
1219		iter_chain = 0;
1220		skip_chain = 0;
1221	}
1222
1223unlabel_staticlist_return:
1224	rcu_read_unlock();
1225	cb->args[0] = iter_bkt;
1226	cb->args[1] = iter_chain;
1227	cb->args[2] = iter_addr4;
1228	cb->args[3] = iter_addr6;
1229	return skb->len;
1230}
1231
1232/**
1233 * netlbl_unlabel_staticlistdef - Handle a STATICLISTDEF message
1234 * @skb: the NETLINK buffer
1235 * @cb: the NETLINK callback
1236 *
1237 * Description:
1238 * Process a user generated STATICLISTDEF message and dump the default
1239 * unlabeled connection entry in a form suitable for use in a kernel generated
1240 * STATICLISTDEF message.  Returns the length of @skb.
1241 *
1242 */
1243static int netlbl_unlabel_staticlistdef(struct sk_buff *skb,
1244					struct netlink_callback *cb)
1245{
1246	struct netlbl_unlhsh_walk_arg cb_arg;
1247	struct netlbl_unlhsh_iface *iface;
1248	u32 iter_addr4 = 0, iter_addr6 = 0;
1249	struct netlbl_af4list *addr4;
1250#if IS_ENABLED(CONFIG_IPV6)
1251	struct netlbl_af6list *addr6;
1252#endif
1253
1254	cb_arg.nl_cb = cb;
1255	cb_arg.skb = skb;
1256	cb_arg.seq = cb->nlh->nlmsg_seq;
1257
1258	rcu_read_lock();
1259	iface = rcu_dereference(netlbl_unlhsh_def);
1260	if (iface == NULL || !iface->valid)
1261		goto unlabel_staticlistdef_return;
1262
1263	netlbl_af4list_foreach_rcu(addr4, &iface->addr4_list) {
1264		if (iter_addr4++ < cb->args[0])
1265			continue;
1266		if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
1267					      iface,
1268					      netlbl_unlhsh_addr4_entry(addr4),
1269					      NULL,
1270					      &cb_arg) < 0) {
1271			iter_addr4--;
1272			goto unlabel_staticlistdef_return;
1273		}
1274	}
1275#if IS_ENABLED(CONFIG_IPV6)
1276	netlbl_af6list_foreach_rcu(addr6, &iface->addr6_list) {
1277		if (iter_addr6++ < cb->args[1])
1278			continue;
1279		if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
1280					      iface,
1281					      NULL,
1282					      netlbl_unlhsh_addr6_entry(addr6),
1283					      &cb_arg) < 0) {
1284			iter_addr6--;
1285			goto unlabel_staticlistdef_return;
1286		}
1287	}
1288#endif /* IPv6 */
1289
1290unlabel_staticlistdef_return:
1291	rcu_read_unlock();
1292	cb->args[0] = iter_addr4;
1293	cb->args[1] = iter_addr6;
1294	return skb->len;
1295}
1296
1297/*
1298 * NetLabel Generic NETLINK Command Definitions
1299 */
1300
1301static const struct genl_small_ops netlbl_unlabel_genl_ops[] = {
1302	{
1303	.cmd = NLBL_UNLABEL_C_STATICADD,
1304	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
1305	.flags = GENL_ADMIN_PERM,
1306	.doit = netlbl_unlabel_staticadd,
1307	.dumpit = NULL,
1308	},
1309	{
1310	.cmd = NLBL_UNLABEL_C_STATICREMOVE,
1311	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
1312	.flags = GENL_ADMIN_PERM,
1313	.doit = netlbl_unlabel_staticremove,
1314	.dumpit = NULL,
1315	},
1316	{
1317	.cmd = NLBL_UNLABEL_C_STATICLIST,
1318	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
1319	.flags = 0,
1320	.doit = NULL,
1321	.dumpit = netlbl_unlabel_staticlist,
1322	},
1323	{
1324	.cmd = NLBL_UNLABEL_C_STATICADDDEF,
1325	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
1326	.flags = GENL_ADMIN_PERM,
1327	.doit = netlbl_unlabel_staticadddef,
1328	.dumpit = NULL,
1329	},
1330	{
1331	.cmd = NLBL_UNLABEL_C_STATICREMOVEDEF,
1332	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
1333	.flags = GENL_ADMIN_PERM,
1334	.doit = netlbl_unlabel_staticremovedef,
1335	.dumpit = NULL,
1336	},
1337	{
1338	.cmd = NLBL_UNLABEL_C_STATICLISTDEF,
1339	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
1340	.flags = 0,
1341	.doit = NULL,
1342	.dumpit = netlbl_unlabel_staticlistdef,
1343	},
1344	{
1345	.cmd = NLBL_UNLABEL_C_ACCEPT,
1346	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
1347	.flags = GENL_ADMIN_PERM,
1348	.doit = netlbl_unlabel_accept,
1349	.dumpit = NULL,
1350	},
1351	{
1352	.cmd = NLBL_UNLABEL_C_LIST,
1353	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
1354	.flags = 0,
1355	.doit = netlbl_unlabel_list,
1356	.dumpit = NULL,
1357	},
1358};
1359
1360static struct genl_family netlbl_unlabel_gnl_family __ro_after_init = {
1361	.hdrsize = 0,
1362	.name = NETLBL_NLTYPE_UNLABELED_NAME,
1363	.version = NETLBL_PROTO_VERSION,
1364	.maxattr = NLBL_UNLABEL_A_MAX,
1365	.policy = netlbl_unlabel_genl_policy,
1366	.module = THIS_MODULE,
1367	.small_ops = netlbl_unlabel_genl_ops,
1368	.n_small_ops = ARRAY_SIZE(netlbl_unlabel_genl_ops),
1369	.resv_start_op = NLBL_UNLABEL_C_STATICLISTDEF + 1,
1370};
1371
1372/*
1373 * NetLabel Generic NETLINK Protocol Functions
1374 */
1375
1376/**
1377 * netlbl_unlabel_genl_init - Register the Unlabeled NetLabel component
1378 *
1379 * Description:
1380 * Register the unlabeled packet NetLabel component with the Generic NETLINK
1381 * mechanism.  Returns zero on success, negative values on failure.
1382 *
1383 */
1384int __init netlbl_unlabel_genl_init(void)
1385{
1386	return genl_register_family(&netlbl_unlabel_gnl_family);
1387}
1388
1389/*
1390 * NetLabel KAPI Hooks
1391 */
1392
1393static struct notifier_block netlbl_unlhsh_netdev_notifier = {
1394	.notifier_call = netlbl_unlhsh_netdev_handler,
1395};
1396
1397/**
1398 * netlbl_unlabel_init - Initialize the unlabeled connection hash table
1399 * @size: the number of bits to use for the hash buckets
1400 *
1401 * Description:
1402 * Initializes the unlabeled connection hash table and registers a network
1403 * device notification handler.  This function should only be called by the
1404 * NetLabel subsystem itself during initialization.  Returns zero on success,
1405 * non-zero values on error.
1406 *
1407 */
1408int __init netlbl_unlabel_init(u32 size)
1409{
1410	u32 iter;
1411	struct netlbl_unlhsh_tbl *hsh_tbl;
1412
1413	if (size == 0)
1414		return -EINVAL;
1415
1416	hsh_tbl = kmalloc(sizeof(*hsh_tbl), GFP_KERNEL);
1417	if (hsh_tbl == NULL)
1418		return -ENOMEM;
1419	hsh_tbl->size = 1 << size;
1420	hsh_tbl->tbl = kcalloc(hsh_tbl->size,
1421			       sizeof(struct list_head),
1422			       GFP_KERNEL);
1423	if (hsh_tbl->tbl == NULL) {
1424		kfree(hsh_tbl);
1425		return -ENOMEM;
1426	}
1427	for (iter = 0; iter < hsh_tbl->size; iter++)
1428		INIT_LIST_HEAD(&hsh_tbl->tbl[iter]);
1429
1430	spin_lock(&netlbl_unlhsh_lock);
1431	rcu_assign_pointer(netlbl_unlhsh, hsh_tbl);
1432	spin_unlock(&netlbl_unlhsh_lock);
1433
1434	register_netdevice_notifier(&netlbl_unlhsh_netdev_notifier);
1435
1436	return 0;
1437}
1438
1439/**
1440 * netlbl_unlabel_getattr - Get the security attributes for an unlabled packet
1441 * @skb: the packet
1442 * @family: protocol family
1443 * @secattr: the security attributes
1444 *
1445 * Description:
1446 * Determine the security attributes, if any, for an unlabled packet and return
1447 * them in @secattr.  Returns zero on success and negative values on failure.
1448 *
1449 */
1450int netlbl_unlabel_getattr(const struct sk_buff *skb,
1451			   u16 family,
1452			   struct netlbl_lsm_secattr *secattr)
1453{
1454	struct netlbl_unlhsh_iface *iface;
1455
1456	rcu_read_lock();
1457	iface = netlbl_unlhsh_search_iface(skb->skb_iif);
1458	if (iface == NULL)
1459		iface = rcu_dereference(netlbl_unlhsh_def);
1460	if (iface == NULL || !iface->valid)
1461		goto unlabel_getattr_nolabel;
1462
1463#if IS_ENABLED(CONFIG_IPV6)
1464	/* When resolving a fallback label, check the sk_buff version as
1465	 * it is possible (e.g. SCTP) to have family = PF_INET6 while
1466	 * receiving ip_hdr(skb)->version = 4.
1467	 */
1468	if (family == PF_INET6 && ip_hdr(skb)->version == 4)
1469		family = PF_INET;
1470#endif /* IPv6 */
1471
1472	switch (family) {
1473	case PF_INET: {
1474		struct iphdr *hdr4;
1475		struct netlbl_af4list *addr4;
1476
1477		hdr4 = ip_hdr(skb);
1478		addr4 = netlbl_af4list_search(hdr4->saddr,
1479					      &iface->addr4_list);
1480		if (addr4 == NULL)
1481			goto unlabel_getattr_nolabel;
1482		secattr->attr.secid = netlbl_unlhsh_addr4_entry(addr4)->secid;
1483		break;
1484	}
1485#if IS_ENABLED(CONFIG_IPV6)
1486	case PF_INET6: {
1487		struct ipv6hdr *hdr6;
1488		struct netlbl_af6list *addr6;
1489
1490		hdr6 = ipv6_hdr(skb);
1491		addr6 = netlbl_af6list_search(&hdr6->saddr,
1492					      &iface->addr6_list);
1493		if (addr6 == NULL)
1494			goto unlabel_getattr_nolabel;
1495		secattr->attr.secid = netlbl_unlhsh_addr6_entry(addr6)->secid;
1496		break;
1497	}
1498#endif /* IPv6 */
1499	default:
1500		goto unlabel_getattr_nolabel;
1501	}
1502	rcu_read_unlock();
1503
1504	secattr->flags |= NETLBL_SECATTR_SECID;
1505	secattr->type = NETLBL_NLTYPE_UNLABELED;
1506	return 0;
1507
1508unlabel_getattr_nolabel:
1509	rcu_read_unlock();
1510	if (netlabel_unlabel_acceptflg == 0)
1511		return -ENOMSG;
1512	secattr->type = NETLBL_NLTYPE_UNLABELED;
1513	return 0;
1514}
1515
1516/**
1517 * netlbl_unlabel_defconf - Set the default config to allow unlabeled packets
1518 *
1519 * Description:
1520 * Set the default NetLabel configuration to allow incoming unlabeled packets
1521 * and to send unlabeled network traffic by default.
1522 *
1523 */
1524int __init netlbl_unlabel_defconf(void)
1525{
1526	int ret_val;
1527	struct netlbl_dom_map *entry;
1528	struct netlbl_audit audit_info;
1529
1530	/* Only the kernel is allowed to call this function and the only time
1531	 * it is called is at bootup before the audit subsystem is reporting
1532	 * messages so don't worry to much about these values. */
1533	security_current_getlsmprop_subj(&audit_info.prop);
1534	audit_info.loginuid = GLOBAL_ROOT_UID;
1535	audit_info.sessionid = 0;
1536
1537	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
1538	if (entry == NULL)
1539		return -ENOMEM;
1540	entry->family = AF_UNSPEC;
1541	entry->def.type = NETLBL_NLTYPE_UNLABELED;
1542	ret_val = netlbl_domhsh_add_default(entry, &audit_info);
1543	if (ret_val != 0)
1544		return ret_val;
1545
1546	netlbl_unlabel_acceptflg_set(1, &audit_info);
1547
1548	return 0;
1549}
~/ Read-only file preview.