1 /*
2  * NetLabel Domain Hash Table
3  *
4  * This file manages the domain hash table that NetLabel uses to determine
5  * which network labeling protocol to use for a given domain.  The NetLabel
6  * system manages static and dynamic label mappings for network protocols such
7  * as CIPSO and RIPSO.
8  *
9  * Author: Paul Moore <paul@paul-moore.com>
10  *
11  */
12 
13 /*
14  * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
15  *
16  * This program is free software;  you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation; either version 2 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
24  * the GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program;  if not, see <http://www.gnu.org/licenses/>.
28  *
29  */
30 
31 #include <linux/types.h>
32 #include <linux/rculist.h>
33 #include <linux/skbuff.h>
34 #include <linux/spinlock.h>
35 #include <linux/string.h>
36 #include <linux/audit.h>
37 #include <linux/slab.h>
38 #include <net/netlabel.h>
39 #include <net/cipso_ipv4.h>
40 #include <net/calipso.h>
41 #include <asm/bug.h>
42 
43 #include "netlabel_mgmt.h"
44 #include "netlabel_addrlist.h"
45 #include "netlabel_calipso.h"
46 #include "netlabel_domainhash.h"
47 #include "netlabel_user.h"
48 
49 struct netlbl_domhsh_tbl {
50 	struct list_head *tbl;
51 	u32 size;
52 };
53 
54 /* Domain hash table */
55 /* updates should be so rare that having one spinlock for the entire hash table
56  * should be okay */
57 static DEFINE_SPINLOCK(netlbl_domhsh_lock);
58 #define netlbl_domhsh_rcu_deref(p) \
59 	rcu_dereference_check(p, lockdep_is_held(&netlbl_domhsh_lock))
60 static struct netlbl_domhsh_tbl __rcu *netlbl_domhsh;
61 static struct netlbl_dom_map __rcu *netlbl_domhsh_def_ipv4;
62 static struct netlbl_dom_map __rcu *netlbl_domhsh_def_ipv6;
63 
64 /*
65  * Domain Hash Table Helper Functions
66  */
67 
68 /**
69  * netlbl_domhsh_free_entry - Frees a domain hash table entry
70  * @entry: the entry's RCU field
71  *
72  * Description:
73  * This function is designed to be used as a callback to the call_rcu()
74  * function so that the memory allocated to a hash table entry can be released
75  * safely.
76  *
77  */
netlbl_domhsh_free_entry(struct rcu_head * entry)78 static void netlbl_domhsh_free_entry(struct rcu_head *entry)
79 {
80 	struct netlbl_dom_map *ptr;
81 	struct netlbl_af4list *iter4;
82 	struct netlbl_af4list *tmp4;
83 #if IS_ENABLED(CONFIG_IPV6)
84 	struct netlbl_af6list *iter6;
85 	struct netlbl_af6list *tmp6;
86 #endif /* IPv6 */
87 
88 	ptr = container_of(entry, struct netlbl_dom_map, rcu);
89 	if (ptr->def.type == NETLBL_NLTYPE_ADDRSELECT) {
90 		netlbl_af4list_foreach_safe(iter4, tmp4,
91 					    &ptr->def.addrsel->list4) {
92 			netlbl_af4list_remove_entry(iter4);
93 			kfree(netlbl_domhsh_addr4_entry(iter4));
94 		}
95 #if IS_ENABLED(CONFIG_IPV6)
96 		netlbl_af6list_foreach_safe(iter6, tmp6,
97 					    &ptr->def.addrsel->list6) {
98 			netlbl_af6list_remove_entry(iter6);
99 			kfree(netlbl_domhsh_addr6_entry(iter6));
100 		}
101 #endif /* IPv6 */
102 	}
103 	kfree(ptr->domain);
104 	kfree(ptr);
105 }
106 
107 /**
108  * netlbl_domhsh_hash - Hashing function for the domain hash table
109  * @domain: the domain name to hash
110  *
111  * Description:
112  * This is the hashing function for the domain hash table, it returns the
113  * correct bucket number for the domain.  The caller is responsible for
114  * ensuring that the hash table is protected with either a RCU read lock or the
115  * hash table lock.
116  *
117  */
netlbl_domhsh_hash(const char * key)118 static u32 netlbl_domhsh_hash(const char *key)
119 {
120 	u32 iter;
121 	u32 val;
122 	u32 len;
123 
124 	/* This is taken (with slight modification) from
125 	 * security/selinux/ss/symtab.c:symhash() */
126 
127 	for (iter = 0, val = 0, len = strlen(key); iter < len; iter++)
128 		val = (val << 4 | (val >> (8 * sizeof(u32) - 4))) ^ key[iter];
129 	return val & (netlbl_domhsh_rcu_deref(netlbl_domhsh)->size - 1);
130 }
131 
netlbl_family_match(u16 f1,u16 f2)132 static bool netlbl_family_match(u16 f1, u16 f2)
133 {
134 	return (f1 == f2) || (f1 == AF_UNSPEC) || (f2 == AF_UNSPEC);
135 }
136 
137 /**
138  * netlbl_domhsh_search - Search for a domain entry
139  * @domain: the domain
140  * @family: the address family
141  *
142  * Description:
143  * Searches the domain hash table and returns a pointer to the hash table
144  * entry if found, otherwise NULL is returned.  @family may be %AF_UNSPEC
145  * which matches any address family entries.  The caller is responsible for
146  * ensuring that the hash table is protected with either a RCU read lock or the
147  * hash table lock.
148  *
149  */
netlbl_domhsh_search(const char * domain,u16 family)150 static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain,
151 						   u16 family)
152 {
153 	u32 bkt;
154 	struct list_head *bkt_list;
155 	struct netlbl_dom_map *iter;
156 
157 	if (domain != NULL) {
158 		bkt = netlbl_domhsh_hash(domain);
159 		bkt_list = &netlbl_domhsh_rcu_deref(netlbl_domhsh)->tbl[bkt];
160 		list_for_each_entry_rcu(iter, bkt_list, list)
161 			if (iter->valid &&
162 			    netlbl_family_match(iter->family, family) &&
163 			    strcmp(iter->domain, domain) == 0)
164 				return iter;
165 	}
166 
167 	return NULL;
168 }
169 
170 /**
171  * netlbl_domhsh_search_def - Search for a domain entry
172  * @domain: the domain
173  * @family: the address family
174  *
175  * Description:
176  * Searches the domain hash table and returns a pointer to the hash table
177  * entry if an exact match is found, if an exact match is not present in the
178  * hash table then the default entry is returned if valid otherwise NULL is
179  * returned.  @family may be %AF_UNSPEC which matches any address family
180  * entries.  The caller is responsible ensuring that the hash table is
181  * protected with either a RCU read lock or the hash table lock.
182  *
183  */
netlbl_domhsh_search_def(const char * domain,u16 family)184 static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain,
185 						       u16 family)
186 {
187 	struct netlbl_dom_map *entry;
188 
189 	entry = netlbl_domhsh_search(domain, family);
190 	if (entry != NULL)
191 		return entry;
192 	if (family == AF_INET || family == AF_UNSPEC) {
193 		entry = netlbl_domhsh_rcu_deref(netlbl_domhsh_def_ipv4);
194 		if (entry != NULL && entry->valid)
195 			return entry;
196 	}
197 	if (family == AF_INET6 || family == AF_UNSPEC) {
198 		entry = netlbl_domhsh_rcu_deref(netlbl_domhsh_def_ipv6);
199 		if (entry != NULL && entry->valid)
200 			return entry;
201 	}
202 
203 	return NULL;
204 }
205 
206 /**
207  * netlbl_domhsh_audit_add - Generate an audit entry for an add event
208  * @entry: the entry being added
209  * @addr4: the IPv4 address information
210  * @addr6: the IPv6 address information
211  * @result: the result code
212  * @audit_info: NetLabel audit information
213  *
214  * Description:
215  * Generate an audit record for adding a new NetLabel/LSM mapping entry with
216  * the given information.  Caller is responsible for holding the necessary
217  * locks.
218  *
219  */
netlbl_domhsh_audit_add(struct netlbl_dom_map * entry,struct netlbl_af4list * addr4,struct netlbl_af6list * addr6,int result,struct netlbl_audit * audit_info)220 static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry,
221 				    struct netlbl_af4list *addr4,
222 				    struct netlbl_af6list *addr6,
223 				    int result,
224 				    struct netlbl_audit *audit_info)
225 {
226 	struct audit_buffer *audit_buf;
227 	struct cipso_v4_doi *cipsov4 = NULL;
228 	struct calipso_doi *calipso = NULL;
229 	u32 type;
230 
231 	audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
232 	if (audit_buf != NULL) {
233 		audit_log_format(audit_buf, " nlbl_domain=%s",
234 				 entry->domain ? entry->domain : "(default)");
235 		if (addr4 != NULL) {
236 			struct netlbl_domaddr4_map *map4;
237 			map4 = netlbl_domhsh_addr4_entry(addr4);
238 			type = map4->def.type;
239 			cipsov4 = map4->def.cipso;
240 			netlbl_af4list_audit_addr(audit_buf, 0, NULL,
241 						  addr4->addr, addr4->mask);
242 #if IS_ENABLED(CONFIG_IPV6)
243 		} else if (addr6 != NULL) {
244 			struct netlbl_domaddr6_map *map6;
245 			map6 = netlbl_domhsh_addr6_entry(addr6);
246 			type = map6->def.type;
247 			calipso = map6->def.calipso;
248 			netlbl_af6list_audit_addr(audit_buf, 0, NULL,
249 						  &addr6->addr, &addr6->mask);
250 #endif /* IPv6 */
251 		} else {
252 			type = entry->def.type;
253 			cipsov4 = entry->def.cipso;
254 			calipso = entry->def.calipso;
255 		}
256 		switch (type) {
257 		case NETLBL_NLTYPE_UNLABELED:
258 			audit_log_format(audit_buf, " nlbl_protocol=unlbl");
259 			break;
260 		case NETLBL_NLTYPE_CIPSOV4:
261 			BUG_ON(cipsov4 == NULL);
262 			audit_log_format(audit_buf,
263 					 " nlbl_protocol=cipsov4 cipso_doi=%u",
264 					 cipsov4->doi);
265 			break;
266 		case NETLBL_NLTYPE_CALIPSO:
267 			BUG_ON(calipso == NULL);
268 			audit_log_format(audit_buf,
269 					 " nlbl_protocol=calipso calipso_doi=%u",
270 					 calipso->doi);
271 			break;
272 		}
273 		audit_log_format(audit_buf, " res=%u", result == 0 ? 1 : 0);
274 		audit_log_end(audit_buf);
275 	}
276 }
277 
278 /**
279  * netlbl_domhsh_validate - Validate a new domain mapping entry
280  * @entry: the entry to validate
281  *
282  * This function validates the new domain mapping entry to ensure that it is
283  * a valid entry.  Returns zero on success, negative values on failure.
284  *
285  */
netlbl_domhsh_validate(const struct netlbl_dom_map * entry)286 static int netlbl_domhsh_validate(const struct netlbl_dom_map *entry)
287 {
288 	struct netlbl_af4list *iter4;
289 	struct netlbl_domaddr4_map *map4;
290 #if IS_ENABLED(CONFIG_IPV6)
291 	struct netlbl_af6list *iter6;
292 	struct netlbl_domaddr6_map *map6;
293 #endif /* IPv6 */
294 
295 	if (entry == NULL)
296 		return -EINVAL;
297 
298 	if (entry->family != AF_INET && entry->family != AF_INET6 &&
299 	    (entry->family != AF_UNSPEC ||
300 	     entry->def.type != NETLBL_NLTYPE_UNLABELED))
301 		return -EINVAL;
302 
303 	switch (entry->def.type) {
304 	case NETLBL_NLTYPE_UNLABELED:
305 		if (entry->def.cipso != NULL || entry->def.calipso != NULL ||
306 		    entry->def.addrsel != NULL)
307 			return -EINVAL;
308 		break;
309 	case NETLBL_NLTYPE_CIPSOV4:
310 		if (entry->family != AF_INET ||
311 		    entry->def.cipso == NULL)
312 			return -EINVAL;
313 		break;
314 	case NETLBL_NLTYPE_CALIPSO:
315 		if (entry->family != AF_INET6 ||
316 		    entry->def.calipso == NULL)
317 			return -EINVAL;
318 		break;
319 	case NETLBL_NLTYPE_ADDRSELECT:
320 		netlbl_af4list_foreach(iter4, &entry->def.addrsel->list4) {
321 			map4 = netlbl_domhsh_addr4_entry(iter4);
322 			switch (map4->def.type) {
323 			case NETLBL_NLTYPE_UNLABELED:
324 				if (map4->def.cipso != NULL)
325 					return -EINVAL;
326 				break;
327 			case NETLBL_NLTYPE_CIPSOV4:
328 				if (map4->def.cipso == NULL)
329 					return -EINVAL;
330 				break;
331 			default:
332 				return -EINVAL;
333 			}
334 		}
335 #if IS_ENABLED(CONFIG_IPV6)
336 		netlbl_af6list_foreach(iter6, &entry->def.addrsel->list6) {
337 			map6 = netlbl_domhsh_addr6_entry(iter6);
338 			switch (map6->def.type) {
339 			case NETLBL_NLTYPE_UNLABELED:
340 				if (map6->def.calipso != NULL)
341 					return -EINVAL;
342 				break;
343 			case NETLBL_NLTYPE_CALIPSO:
344 				if (map6->def.calipso == NULL)
345 					return -EINVAL;
346 				break;
347 			default:
348 				return -EINVAL;
349 			}
350 		}
351 #endif /* IPv6 */
352 		break;
353 	default:
354 		return -EINVAL;
355 	}
356 
357 	return 0;
358 }
359 
360 /*
361  * Domain Hash Table Functions
362  */
363 
364 /**
365  * netlbl_domhsh_init - Init for the domain hash
366  * @size: the number of bits to use for the hash buckets
367  *
368  * Description:
369  * Initializes the domain hash table, should be called only by
370  * netlbl_user_init() during initialization.  Returns zero on success, non-zero
371  * values on error.
372  *
373  */
netlbl_domhsh_init(u32 size)374 int __init netlbl_domhsh_init(u32 size)
375 {
376 	u32 iter;
377 	struct netlbl_domhsh_tbl *hsh_tbl;
378 
379 	if (size == 0)
380 		return -EINVAL;
381 
382 	hsh_tbl = kmalloc(sizeof(*hsh_tbl), GFP_KERNEL);
383 	if (hsh_tbl == NULL)
384 		return -ENOMEM;
385 	hsh_tbl->size = 1 << size;
386 	hsh_tbl->tbl = kcalloc(hsh_tbl->size,
387 			       sizeof(struct list_head),
388 			       GFP_KERNEL);
389 	if (hsh_tbl->tbl == NULL) {
390 		kfree(hsh_tbl);
391 		return -ENOMEM;
392 	}
393 	for (iter = 0; iter < hsh_tbl->size; iter++)
394 		INIT_LIST_HEAD(&hsh_tbl->tbl[iter]);
395 
396 	spin_lock(&netlbl_domhsh_lock);
397 	rcu_assign_pointer(netlbl_domhsh, hsh_tbl);
398 	spin_unlock(&netlbl_domhsh_lock);
399 
400 	return 0;
401 }
402 
403 /**
404  * netlbl_domhsh_add - Adds a entry to the domain hash table
405  * @entry: the entry to add
406  * @audit_info: NetLabel audit information
407  *
408  * Description:
409  * Adds a new entry to the domain hash table and handles any updates to the
410  * lower level protocol handler (i.e. CIPSO).  @entry->family may be set to
411  * %AF_UNSPEC which will add an entry that matches all address families.  This
412  * is only useful for the unlabelled type and will only succeed if there is no
413  * existing entry for any address family with the same domain.  Returns zero
414  * on success, negative on failure.
415  *
416  */
netlbl_domhsh_add(struct netlbl_dom_map * entry,struct netlbl_audit * audit_info)417 int netlbl_domhsh_add(struct netlbl_dom_map *entry,
418 		      struct netlbl_audit *audit_info)
419 {
420 	int ret_val = 0;
421 	struct netlbl_dom_map *entry_old, *entry_b;
422 	struct netlbl_af4list *iter4;
423 	struct netlbl_af4list *tmp4;
424 #if IS_ENABLED(CONFIG_IPV6)
425 	struct netlbl_af6list *iter6;
426 	struct netlbl_af6list *tmp6;
427 #endif /* IPv6 */
428 
429 	ret_val = netlbl_domhsh_validate(entry);
430 	if (ret_val != 0)
431 		return ret_val;
432 
433 	/* XXX - we can remove this RCU read lock as the spinlock protects the
434 	 *       entire function, but before we do we need to fixup the
435 	 *       netlbl_af[4,6]list RCU functions to do "the right thing" with
436 	 *       respect to rcu_dereference() when only a spinlock is held. */
437 	rcu_read_lock();
438 	spin_lock(&netlbl_domhsh_lock);
439 	if (entry->domain != NULL)
440 		entry_old = netlbl_domhsh_search(entry->domain, entry->family);
441 	else
442 		entry_old = netlbl_domhsh_search_def(entry->domain,
443 						     entry->family);
444 	if (entry_old == NULL) {
445 		entry->valid = 1;
446 
447 		if (entry->domain != NULL) {
448 			u32 bkt = netlbl_domhsh_hash(entry->domain);
449 			list_add_tail_rcu(&entry->list,
450 				    &rcu_dereference(netlbl_domhsh)->tbl[bkt]);
451 		} else {
452 			INIT_LIST_HEAD(&entry->list);
453 			switch (entry->family) {
454 			case AF_INET:
455 				rcu_assign_pointer(netlbl_domhsh_def_ipv4,
456 						   entry);
457 				break;
458 			case AF_INET6:
459 				rcu_assign_pointer(netlbl_domhsh_def_ipv6,
460 						   entry);
461 				break;
462 			case AF_UNSPEC:
463 				if (entry->def.type !=
464 				    NETLBL_NLTYPE_UNLABELED) {
465 					ret_val = -EINVAL;
466 					goto add_return;
467 				}
468 				entry_b = kzalloc(sizeof(*entry_b), GFP_ATOMIC);
469 				if (entry_b == NULL) {
470 					ret_val = -ENOMEM;
471 					goto add_return;
472 				}
473 				entry_b->family = AF_INET6;
474 				entry_b->def.type = NETLBL_NLTYPE_UNLABELED;
475 				entry_b->valid = 1;
476 				entry->family = AF_INET;
477 				rcu_assign_pointer(netlbl_domhsh_def_ipv4,
478 						   entry);
479 				rcu_assign_pointer(netlbl_domhsh_def_ipv6,
480 						   entry_b);
481 				break;
482 			default:
483 				/* Already checked in
484 				 * netlbl_domhsh_validate(). */
485 				ret_val = -EINVAL;
486 				goto add_return;
487 			}
488 		}
489 
490 		if (entry->def.type == NETLBL_NLTYPE_ADDRSELECT) {
491 			netlbl_af4list_foreach_rcu(iter4,
492 						   &entry->def.addrsel->list4)
493 				netlbl_domhsh_audit_add(entry, iter4, NULL,
494 							ret_val, audit_info);
495 #if IS_ENABLED(CONFIG_IPV6)
496 			netlbl_af6list_foreach_rcu(iter6,
497 						   &entry->def.addrsel->list6)
498 				netlbl_domhsh_audit_add(entry, NULL, iter6,
499 							ret_val, audit_info);
500 #endif /* IPv6 */
501 		} else
502 			netlbl_domhsh_audit_add(entry, NULL, NULL,
503 						ret_val, audit_info);
504 	} else if (entry_old->def.type == NETLBL_NLTYPE_ADDRSELECT &&
505 		   entry->def.type == NETLBL_NLTYPE_ADDRSELECT) {
506 		struct list_head *old_list4;
507 		struct list_head *old_list6;
508 
509 		old_list4 = &entry_old->def.addrsel->list4;
510 		old_list6 = &entry_old->def.addrsel->list6;
511 
512 		/* we only allow the addition of address selectors if all of
513 		 * the selectors do not exist in the existing domain map */
514 		netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4)
515 			if (netlbl_af4list_search_exact(iter4->addr,
516 							iter4->mask,
517 							old_list4)) {
518 				ret_val = -EEXIST;
519 				goto add_return;
520 			}
521 #if IS_ENABLED(CONFIG_IPV6)
522 		netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6)
523 			if (netlbl_af6list_search_exact(&iter6->addr,
524 							&iter6->mask,
525 							old_list6)) {
526 				ret_val = -EEXIST;
527 				goto add_return;
528 			}
529 #endif /* IPv6 */
530 
531 		netlbl_af4list_foreach_safe(iter4, tmp4,
532 					    &entry->def.addrsel->list4) {
533 			netlbl_af4list_remove_entry(iter4);
534 			iter4->valid = 1;
535 			ret_val = netlbl_af4list_add(iter4, old_list4);
536 			netlbl_domhsh_audit_add(entry_old, iter4, NULL,
537 						ret_val, audit_info);
538 			if (ret_val != 0)
539 				goto add_return;
540 		}
541 #if IS_ENABLED(CONFIG_IPV6)
542 		netlbl_af6list_foreach_safe(iter6, tmp6,
543 					    &entry->def.addrsel->list6) {
544 			netlbl_af6list_remove_entry(iter6);
545 			iter6->valid = 1;
546 			ret_val = netlbl_af6list_add(iter6, old_list6);
547 			netlbl_domhsh_audit_add(entry_old, NULL, iter6,
548 						ret_val, audit_info);
549 			if (ret_val != 0)
550 				goto add_return;
551 		}
552 #endif /* IPv6 */
553 	} else
554 		ret_val = -EINVAL;
555 
556 add_return:
557 	spin_unlock(&netlbl_domhsh_lock);
558 	rcu_read_unlock();
559 	return ret_val;
560 }
561 
562 /**
563  * netlbl_domhsh_add_default - Adds the default entry to the domain hash table
564  * @entry: the entry to add
565  * @audit_info: NetLabel audit information
566  *
567  * Description:
568  * Adds a new default entry to the domain hash table and handles any updates
569  * to the lower level protocol handler (i.e. CIPSO).  Returns zero on success,
570  * negative on failure.
571  *
572  */
netlbl_domhsh_add_default(struct netlbl_dom_map * entry,struct netlbl_audit * audit_info)573 int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
574 			      struct netlbl_audit *audit_info)
575 {
576 	return netlbl_domhsh_add(entry, audit_info);
577 }
578 
579 /**
580  * netlbl_domhsh_remove_entry - Removes a given entry from the domain table
581  * @entry: the entry to remove
582  * @audit_info: NetLabel audit information
583  *
584  * Description:
585  * Removes an entry from the domain hash table and handles any updates to the
586  * lower level protocol handler (i.e. CIPSO).  Caller is responsible for
587  * ensuring that the RCU read lock is held.  Returns zero on success, negative
588  * on failure.
589  *
590  */
netlbl_domhsh_remove_entry(struct netlbl_dom_map * entry,struct netlbl_audit * audit_info)591 int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
592 			       struct netlbl_audit *audit_info)
593 {
594 	int ret_val = 0;
595 	struct audit_buffer *audit_buf;
596 
597 	if (entry == NULL)
598 		return -ENOENT;
599 
600 	spin_lock(&netlbl_domhsh_lock);
601 	if (entry->valid) {
602 		entry->valid = 0;
603 		if (entry == rcu_dereference(netlbl_domhsh_def_ipv4))
604 			RCU_INIT_POINTER(netlbl_domhsh_def_ipv4, NULL);
605 		else if (entry == rcu_dereference(netlbl_domhsh_def_ipv6))
606 			RCU_INIT_POINTER(netlbl_domhsh_def_ipv6, NULL);
607 		else
608 			list_del_rcu(&entry->list);
609 	} else
610 		ret_val = -ENOENT;
611 	spin_unlock(&netlbl_domhsh_lock);
612 
613 	audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info);
614 	if (audit_buf != NULL) {
615 		audit_log_format(audit_buf,
616 				 " nlbl_domain=%s res=%u",
617 				 entry->domain ? entry->domain : "(default)",
618 				 ret_val == 0 ? 1 : 0);
619 		audit_log_end(audit_buf);
620 	}
621 
622 	if (ret_val == 0) {
623 		struct netlbl_af4list *iter4;
624 		struct netlbl_domaddr4_map *map4;
625 #if IS_ENABLED(CONFIG_IPV6)
626 		struct netlbl_af6list *iter6;
627 		struct netlbl_domaddr6_map *map6;
628 #endif /* IPv6 */
629 
630 		switch (entry->def.type) {
631 		case NETLBL_NLTYPE_ADDRSELECT:
632 			netlbl_af4list_foreach_rcu(iter4,
633 					     &entry->def.addrsel->list4) {
634 				map4 = netlbl_domhsh_addr4_entry(iter4);
635 				cipso_v4_doi_putdef(map4->def.cipso);
636 			}
637 #if IS_ENABLED(CONFIG_IPV6)
638 			netlbl_af6list_foreach_rcu(iter6,
639 					     &entry->def.addrsel->list6) {
640 				map6 = netlbl_domhsh_addr6_entry(iter6);
641 				calipso_doi_putdef(map6->def.calipso);
642 			}
643 #endif /* IPv6 */
644 			break;
645 		case NETLBL_NLTYPE_CIPSOV4:
646 			cipso_v4_doi_putdef(entry->def.cipso);
647 			break;
648 #if IS_ENABLED(CONFIG_IPV6)
649 		case NETLBL_NLTYPE_CALIPSO:
650 			calipso_doi_putdef(entry->def.calipso);
651 			break;
652 #endif /* IPv6 */
653 		}
654 		call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
655 	}
656 
657 	return ret_val;
658 }
659 
660 /**
661  * netlbl_domhsh_remove_af4 - Removes an address selector entry
662  * @domain: the domain
663  * @addr: IPv4 address
664  * @mask: IPv4 address mask
665  * @audit_info: NetLabel audit information
666  *
667  * Description:
668  * Removes an individual address selector from a domain mapping and potentially
669  * the entire mapping if it is empty.  Returns zero on success, negative values
670  * on failure.
671  *
672  */
netlbl_domhsh_remove_af4(const char * domain,const struct in_addr * addr,const struct in_addr * mask,struct netlbl_audit * audit_info)673 int netlbl_domhsh_remove_af4(const char *domain,
674 			     const struct in_addr *addr,
675 			     const struct in_addr *mask,
676 			     struct netlbl_audit *audit_info)
677 {
678 	struct netlbl_dom_map *entry_map;
679 	struct netlbl_af4list *entry_addr;
680 	struct netlbl_af4list *iter4;
681 #if IS_ENABLED(CONFIG_IPV6)
682 	struct netlbl_af6list *iter6;
683 #endif /* IPv6 */
684 	struct netlbl_domaddr4_map *entry;
685 
686 	rcu_read_lock();
687 
688 	if (domain)
689 		entry_map = netlbl_domhsh_search(domain, AF_INET);
690 	else
691 		entry_map = netlbl_domhsh_search_def(domain, AF_INET);
692 	if (entry_map == NULL ||
693 	    entry_map->def.type != NETLBL_NLTYPE_ADDRSELECT)
694 		goto remove_af4_failure;
695 
696 	spin_lock(&netlbl_domhsh_lock);
697 	entry_addr = netlbl_af4list_remove(addr->s_addr, mask->s_addr,
698 					   &entry_map->def.addrsel->list4);
699 	spin_unlock(&netlbl_domhsh_lock);
700 
701 	if (entry_addr == NULL)
702 		goto remove_af4_failure;
703 	netlbl_af4list_foreach_rcu(iter4, &entry_map->def.addrsel->list4)
704 		goto remove_af4_single_addr;
705 #if IS_ENABLED(CONFIG_IPV6)
706 	netlbl_af6list_foreach_rcu(iter6, &entry_map->def.addrsel->list6)
707 		goto remove_af4_single_addr;
708 #endif /* IPv6 */
709 	/* the domain mapping is empty so remove it from the mapping table */
710 	netlbl_domhsh_remove_entry(entry_map, audit_info);
711 
712 remove_af4_single_addr:
713 	rcu_read_unlock();
714 	/* yick, we can't use call_rcu here because we don't have a rcu head
715 	 * pointer but hopefully this should be a rare case so the pause
716 	 * shouldn't be a problem */
717 	synchronize_rcu();
718 	entry = netlbl_domhsh_addr4_entry(entry_addr);
719 	cipso_v4_doi_putdef(entry->def.cipso);
720 	kfree(entry);
721 	return 0;
722 
723 remove_af4_failure:
724 	rcu_read_unlock();
725 	return -ENOENT;
726 }
727 
728 #if IS_ENABLED(CONFIG_IPV6)
729 /**
730  * netlbl_domhsh_remove_af6 - Removes an address selector entry
731  * @domain: the domain
732  * @addr: IPv6 address
733  * @mask: IPv6 address mask
734  * @audit_info: NetLabel audit information
735  *
736  * Description:
737  * Removes an individual address selector from a domain mapping and potentially
738  * the entire mapping if it is empty.  Returns zero on success, negative values
739  * on failure.
740  *
741  */
netlbl_domhsh_remove_af6(const char * domain,const struct in6_addr * addr,const struct in6_addr * mask,struct netlbl_audit * audit_info)742 int netlbl_domhsh_remove_af6(const char *domain,
743 			     const struct in6_addr *addr,
744 			     const struct in6_addr *mask,
745 			     struct netlbl_audit *audit_info)
746 {
747 	struct netlbl_dom_map *entry_map;
748 	struct netlbl_af6list *entry_addr;
749 	struct netlbl_af4list *iter4;
750 	struct netlbl_af6list *iter6;
751 	struct netlbl_domaddr6_map *entry;
752 
753 	rcu_read_lock();
754 
755 	if (domain)
756 		entry_map = netlbl_domhsh_search(domain, AF_INET6);
757 	else
758 		entry_map = netlbl_domhsh_search_def(domain, AF_INET6);
759 	if (entry_map == NULL ||
760 	    entry_map->def.type != NETLBL_NLTYPE_ADDRSELECT)
761 		goto remove_af6_failure;
762 
763 	spin_lock(&netlbl_domhsh_lock);
764 	entry_addr = netlbl_af6list_remove(addr, mask,
765 					   &entry_map->def.addrsel->list6);
766 	spin_unlock(&netlbl_domhsh_lock);
767 
768 	if (entry_addr == NULL)
769 		goto remove_af6_failure;
770 	netlbl_af4list_foreach_rcu(iter4, &entry_map->def.addrsel->list4)
771 		goto remove_af6_single_addr;
772 	netlbl_af6list_foreach_rcu(iter6, &entry_map->def.addrsel->list6)
773 		goto remove_af6_single_addr;
774 	/* the domain mapping is empty so remove it from the mapping table */
775 	netlbl_domhsh_remove_entry(entry_map, audit_info);
776 
777 remove_af6_single_addr:
778 	rcu_read_unlock();
779 	/* yick, we can't use call_rcu here because we don't have a rcu head
780 	 * pointer but hopefully this should be a rare case so the pause
781 	 * shouldn't be a problem */
782 	synchronize_rcu();
783 	entry = netlbl_domhsh_addr6_entry(entry_addr);
784 	calipso_doi_putdef(entry->def.calipso);
785 	kfree(entry);
786 	return 0;
787 
788 remove_af6_failure:
789 	rcu_read_unlock();
790 	return -ENOENT;
791 }
792 #endif /* IPv6 */
793 
794 /**
795  * netlbl_domhsh_remove - Removes an entry from the domain hash table
796  * @domain: the domain to remove
797  * @family: address family
798  * @audit_info: NetLabel audit information
799  *
800  * Description:
801  * Removes an entry from the domain hash table and handles any updates to the
802  * lower level protocol handler (i.e. CIPSO).  @family may be %AF_UNSPEC which
803  * removes all address family entries.  Returns zero on success, negative on
804  * failure.
805  *
806  */
netlbl_domhsh_remove(const char * domain,u16 family,struct netlbl_audit * audit_info)807 int netlbl_domhsh_remove(const char *domain, u16 family,
808 			 struct netlbl_audit *audit_info)
809 {
810 	int ret_val = -EINVAL;
811 	struct netlbl_dom_map *entry;
812 
813 	rcu_read_lock();
814 
815 	if (family == AF_INET || family == AF_UNSPEC) {
816 		if (domain)
817 			entry = netlbl_domhsh_search(domain, AF_INET);
818 		else
819 			entry = netlbl_domhsh_search_def(domain, AF_INET);
820 		ret_val = netlbl_domhsh_remove_entry(entry, audit_info);
821 		if (ret_val && ret_val != -ENOENT)
822 			goto done;
823 	}
824 	if (family == AF_INET6 || family == AF_UNSPEC) {
825 		int ret_val2;
826 
827 		if (domain)
828 			entry = netlbl_domhsh_search(domain, AF_INET6);
829 		else
830 			entry = netlbl_domhsh_search_def(domain, AF_INET6);
831 		ret_val2 = netlbl_domhsh_remove_entry(entry, audit_info);
832 		if (ret_val2 != -ENOENT)
833 			ret_val = ret_val2;
834 	}
835 done:
836 	rcu_read_unlock();
837 
838 	return ret_val;
839 }
840 
841 /**
842  * netlbl_domhsh_remove_default - Removes the default entry from the table
843  * @family: address family
844  * @audit_info: NetLabel audit information
845  *
846  * Description:
847  * Removes/resets the default entry corresponding to @family from the domain
848  * hash table and handles any updates to the lower level protocol handler
849  * (i.e. CIPSO).  @family may be %AF_UNSPEC which removes all address family
850  * entries.  Returns zero on success, negative on failure.
851  *
852  */
netlbl_domhsh_remove_default(u16 family,struct netlbl_audit * audit_info)853 int netlbl_domhsh_remove_default(u16 family, struct netlbl_audit *audit_info)
854 {
855 	return netlbl_domhsh_remove(NULL, family, audit_info);
856 }
857 
858 /**
859  * netlbl_domhsh_getentry - Get an entry from the domain hash table
860  * @domain: the domain name to search for
861  * @family: address family
862  *
863  * Description:
864  * Look through the domain hash table searching for an entry to match @domain,
865  * with address family @family, return a pointer to a copy of the entry or
866  * NULL.  The caller is responsible for ensuring that rcu_read_[un]lock() is
867  * called.
868  *
869  */
netlbl_domhsh_getentry(const char * domain,u16 family)870 struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain, u16 family)
871 {
872 	if (family == AF_UNSPEC)
873 		return NULL;
874 	return netlbl_domhsh_search_def(domain, family);
875 }
876 
877 /**
878  * netlbl_domhsh_getentry_af4 - Get an entry from the domain hash table
879  * @domain: the domain name to search for
880  * @addr: the IP address to search for
881  *
882  * Description:
883  * Look through the domain hash table searching for an entry to match @domain
884  * and @addr, return a pointer to a copy of the entry or NULL.  The caller is
885  * responsible for ensuring that rcu_read_[un]lock() is called.
886  *
887  */
netlbl_domhsh_getentry_af4(const char * domain,__be32 addr)888 struct netlbl_dommap_def *netlbl_domhsh_getentry_af4(const char *domain,
889 						     __be32 addr)
890 {
891 	struct netlbl_dom_map *dom_iter;
892 	struct netlbl_af4list *addr_iter;
893 
894 	dom_iter = netlbl_domhsh_search_def(domain, AF_INET);
895 	if (dom_iter == NULL)
896 		return NULL;
897 
898 	if (dom_iter->def.type != NETLBL_NLTYPE_ADDRSELECT)
899 		return &dom_iter->def;
900 	addr_iter = netlbl_af4list_search(addr, &dom_iter->def.addrsel->list4);
901 	if (addr_iter == NULL)
902 		return NULL;
903 	return &(netlbl_domhsh_addr4_entry(addr_iter)->def);
904 }
905 
906 #if IS_ENABLED(CONFIG_IPV6)
907 /**
908  * netlbl_domhsh_getentry_af6 - Get an entry from the domain hash table
909  * @domain: the domain name to search for
910  * @addr: the IP address to search for
911  *
912  * Description:
913  * Look through the domain hash table searching for an entry to match @domain
914  * and @addr, return a pointer to a copy of the entry or NULL.  The caller is
915  * responsible for ensuring that rcu_read_[un]lock() is called.
916  *
917  */
netlbl_domhsh_getentry_af6(const char * domain,const struct in6_addr * addr)918 struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain,
919 						   const struct in6_addr *addr)
920 {
921 	struct netlbl_dom_map *dom_iter;
922 	struct netlbl_af6list *addr_iter;
923 
924 	dom_iter = netlbl_domhsh_search_def(domain, AF_INET6);
925 	if (dom_iter == NULL)
926 		return NULL;
927 
928 	if (dom_iter->def.type != NETLBL_NLTYPE_ADDRSELECT)
929 		return &dom_iter->def;
930 	addr_iter = netlbl_af6list_search(addr, &dom_iter->def.addrsel->list6);
931 	if (addr_iter == NULL)
932 		return NULL;
933 	return &(netlbl_domhsh_addr6_entry(addr_iter)->def);
934 }
935 #endif /* IPv6 */
936 
937 /**
938  * netlbl_domhsh_walk - Iterate through the domain mapping hash table
939  * @skip_bkt: the number of buckets to skip at the start
940  * @skip_chain: the number of entries to skip in the first iterated bucket
941  * @callback: callback for each entry
942  * @cb_arg: argument for the callback function
943  *
944  * Description:
945  * Interate over the domain mapping hash table, skipping the first @skip_bkt
946  * buckets and @skip_chain entries.  For each entry in the table call
947  * @callback, if @callback returns a negative value stop 'walking' through the
948  * table and return.  Updates the values in @skip_bkt and @skip_chain on
949  * return.  Returns zero on success, negative values on failure.
950  *
951  */
netlbl_domhsh_walk(u32 * skip_bkt,u32 * skip_chain,int (* callback)(struct netlbl_dom_map * entry,void * arg),void * cb_arg)952 int netlbl_domhsh_walk(u32 *skip_bkt,
953 		     u32 *skip_chain,
954 		     int (*callback) (struct netlbl_dom_map *entry, void *arg),
955 		     void *cb_arg)
956 {
957 	int ret_val = -ENOENT;
958 	u32 iter_bkt;
959 	struct list_head *iter_list;
960 	struct netlbl_dom_map *iter_entry;
961 	u32 chain_cnt = 0;
962 
963 	rcu_read_lock();
964 	for (iter_bkt = *skip_bkt;
965 	     iter_bkt < rcu_dereference(netlbl_domhsh)->size;
966 	     iter_bkt++, chain_cnt = 0) {
967 		iter_list = &rcu_dereference(netlbl_domhsh)->tbl[iter_bkt];
968 		list_for_each_entry_rcu(iter_entry, iter_list, list)
969 			if (iter_entry->valid) {
970 				if (chain_cnt++ < *skip_chain)
971 					continue;
972 				ret_val = callback(iter_entry, cb_arg);
973 				if (ret_val < 0) {
974 					chain_cnt--;
975 					goto walk_return;
976 				}
977 			}
978 	}
979 
980 walk_return:
981 	rcu_read_unlock();
982 	*skip_bkt = iter_bkt;
983 	*skip_chain = chain_cnt;
984 	return ret_val;
985 }
986