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