xref: /openbmc/linux/net/netlabel/netlabel_mgmt.c (revision 8f762fe5)
1 /*
2  * NetLabel Management Support
3  *
4  * This file defines the management functions for the NetLabel system.  The
5  * NetLabel system manages static and dynamic label mappings for network
6  * protocols such as CIPSO and RIPSO.
7  *
8  * Author: Paul Moore <paul@paul-moore.com>
9  *
10  */
11 
12 /*
13  * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
14  *
15  * This program is free software;  you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
23  * the GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program;  if not, see <http://www.gnu.org/licenses/>.
27  *
28  */
29 
30 #include <linux/types.h>
31 #include <linux/socket.h>
32 #include <linux/string.h>
33 #include <linux/skbuff.h>
34 #include <linux/in.h>
35 #include <linux/in6.h>
36 #include <linux/slab.h>
37 #include <net/sock.h>
38 #include <net/netlink.h>
39 #include <net/genetlink.h>
40 #include <net/ip.h>
41 #include <net/ipv6.h>
42 #include <net/netlabel.h>
43 #include <net/cipso_ipv4.h>
44 #include <net/calipso.h>
45 #include <linux/atomic.h>
46 
47 #include "netlabel_calipso.h"
48 #include "netlabel_domainhash.h"
49 #include "netlabel_user.h"
50 #include "netlabel_mgmt.h"
51 
52 /* NetLabel configured protocol counter */
53 atomic_t netlabel_mgmt_protocount = ATOMIC_INIT(0);
54 
55 /* Argument struct for netlbl_domhsh_walk() */
56 struct netlbl_domhsh_walk_arg {
57 	struct netlink_callback *nl_cb;
58 	struct sk_buff *skb;
59 	u32 seq;
60 };
61 
62 /* NetLabel Generic NETLINK CIPSOv4 family */
63 static struct genl_family netlbl_mgmt_gnl_family;
64 
65 /* NetLabel Netlink attribute policy */
66 static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
67 	[NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING },
68 	[NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 },
69 	[NLBL_MGMT_A_VERSION] = { .type = NLA_U32 },
70 	[NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
71 	[NLBL_MGMT_A_FAMILY] = { .type = NLA_U16 },
72 	[NLBL_MGMT_A_CLPDOI] = { .type = NLA_U32 },
73 };
74 
75 /*
76  * Helper Functions
77  */
78 
79 /**
80  * netlbl_mgmt_add - Handle an ADD message
81  * @info: the Generic NETLINK info block
82  * @audit_info: NetLabel audit information
83  *
84  * Description:
85  * Helper function for the ADD and ADDDEF messages to add the domain mappings
86  * from the message to the hash table.  See netlabel.h for a description of the
87  * message format.  Returns zero on success, negative values on failure.
88  *
89  */
90 static int netlbl_mgmt_add_common(struct genl_info *info,
91 				  struct netlbl_audit *audit_info)
92 {
93 	int ret_val = -EINVAL;
94 	struct netlbl_domaddr_map *addrmap = NULL;
95 	struct cipso_v4_doi *cipsov4 = NULL;
96 #if IS_ENABLED(CONFIG_IPV6)
97 	struct calipso_doi *calipso = NULL;
98 #endif
99 	u32 tmp_val;
100 	struct netlbl_dom_map *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
101 
102 	if (!entry)
103 		return -ENOMEM;
104 	entry->def.type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
105 	if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
106 		size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
107 		entry->domain = kmalloc(tmp_size, GFP_KERNEL);
108 		if (entry->domain == NULL) {
109 			ret_val = -ENOMEM;
110 			goto add_free_entry;
111 		}
112 		nla_strlcpy(entry->domain,
113 			    info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
114 	}
115 
116 	/* NOTE: internally we allow/use a entry->def.type value of
117 	 *       NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
118 	 *       to pass that as a protocol value because we need to know the
119 	 *       "real" protocol */
120 
121 	switch (entry->def.type) {
122 	case NETLBL_NLTYPE_UNLABELED:
123 		if (info->attrs[NLBL_MGMT_A_FAMILY])
124 			entry->family =
125 				nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
126 		else
127 			entry->family = AF_UNSPEC;
128 		break;
129 	case NETLBL_NLTYPE_CIPSOV4:
130 		if (!info->attrs[NLBL_MGMT_A_CV4DOI])
131 			goto add_free_domain;
132 
133 		tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
134 		cipsov4 = cipso_v4_doi_getdef(tmp_val);
135 		if (cipsov4 == NULL)
136 			goto add_free_domain;
137 		entry->family = AF_INET;
138 		entry->def.cipso = cipsov4;
139 		break;
140 #if IS_ENABLED(CONFIG_IPV6)
141 	case NETLBL_NLTYPE_CALIPSO:
142 		if (!info->attrs[NLBL_MGMT_A_CLPDOI])
143 			goto add_free_domain;
144 
145 		tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CLPDOI]);
146 		calipso = calipso_doi_getdef(tmp_val);
147 		if (calipso == NULL)
148 			goto add_free_domain;
149 		entry->family = AF_INET6;
150 		entry->def.calipso = calipso;
151 		break;
152 #endif /* IPv6 */
153 	default:
154 		goto add_free_domain;
155 	}
156 
157 	if ((entry->family == AF_INET && info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
158 	    (entry->family == AF_INET6 && info->attrs[NLBL_MGMT_A_IPV4ADDR]))
159 		goto add_doi_put_def;
160 
161 	if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
162 		struct in_addr *addr;
163 		struct in_addr *mask;
164 		struct netlbl_domaddr4_map *map;
165 
166 		addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
167 		if (addrmap == NULL) {
168 			ret_val = -ENOMEM;
169 			goto add_doi_put_def;
170 		}
171 		INIT_LIST_HEAD(&addrmap->list4);
172 		INIT_LIST_HEAD(&addrmap->list6);
173 
174 		if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) !=
175 		    sizeof(struct in_addr)) {
176 			ret_val = -EINVAL;
177 			goto add_free_addrmap;
178 		}
179 		if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) !=
180 		    sizeof(struct in_addr)) {
181 			ret_val = -EINVAL;
182 			goto add_free_addrmap;
183 		}
184 		addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]);
185 		mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]);
186 
187 		map = kzalloc(sizeof(*map), GFP_KERNEL);
188 		if (map == NULL) {
189 			ret_val = -ENOMEM;
190 			goto add_free_addrmap;
191 		}
192 		map->list.addr = addr->s_addr & mask->s_addr;
193 		map->list.mask = mask->s_addr;
194 		map->list.valid = 1;
195 		map->def.type = entry->def.type;
196 		if (cipsov4)
197 			map->def.cipso = cipsov4;
198 
199 		ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
200 		if (ret_val != 0) {
201 			kfree(map);
202 			goto add_free_addrmap;
203 		}
204 
205 		entry->family = AF_INET;
206 		entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
207 		entry->def.addrsel = addrmap;
208 #if IS_ENABLED(CONFIG_IPV6)
209 	} else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) {
210 		struct in6_addr *addr;
211 		struct in6_addr *mask;
212 		struct netlbl_domaddr6_map *map;
213 
214 		addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
215 		if (addrmap == NULL) {
216 			ret_val = -ENOMEM;
217 			goto add_doi_put_def;
218 		}
219 		INIT_LIST_HEAD(&addrmap->list4);
220 		INIT_LIST_HEAD(&addrmap->list6);
221 
222 		if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) !=
223 		    sizeof(struct in6_addr)) {
224 			ret_val = -EINVAL;
225 			goto add_free_addrmap;
226 		}
227 		if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) !=
228 		    sizeof(struct in6_addr)) {
229 			ret_val = -EINVAL;
230 			goto add_free_addrmap;
231 		}
232 		addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]);
233 		mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]);
234 
235 		map = kzalloc(sizeof(*map), GFP_KERNEL);
236 		if (map == NULL) {
237 			ret_val = -ENOMEM;
238 			goto add_free_addrmap;
239 		}
240 		map->list.addr = *addr;
241 		map->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
242 		map->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
243 		map->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
244 		map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
245 		map->list.mask = *mask;
246 		map->list.valid = 1;
247 		map->def.type = entry->def.type;
248 		if (calipso)
249 			map->def.calipso = calipso;
250 
251 		ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
252 		if (ret_val != 0) {
253 			kfree(map);
254 			goto add_free_addrmap;
255 		}
256 
257 		entry->family = AF_INET6;
258 		entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
259 		entry->def.addrsel = addrmap;
260 #endif /* IPv6 */
261 	}
262 
263 	ret_val = netlbl_domhsh_add(entry, audit_info);
264 	if (ret_val != 0)
265 		goto add_free_addrmap;
266 
267 	return 0;
268 
269 add_free_addrmap:
270 	kfree(addrmap);
271 add_doi_put_def:
272 	cipso_v4_doi_putdef(cipsov4);
273 #if IS_ENABLED(CONFIG_IPV6)
274 	calipso_doi_putdef(calipso);
275 #endif
276 add_free_domain:
277 	kfree(entry->domain);
278 add_free_entry:
279 	kfree(entry);
280 	return ret_val;
281 }
282 
283 /**
284  * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry
285  * @skb: the NETLINK buffer
286  * @entry: the map entry
287  *
288  * Description:
289  * This function is a helper function used by the LISTALL and LISTDEF command
290  * handlers.  The caller is responsible for ensuring that the RCU read lock
291  * is held.  Returns zero on success, negative values on failure.
292  *
293  */
294 static int netlbl_mgmt_listentry(struct sk_buff *skb,
295 				 struct netlbl_dom_map *entry)
296 {
297 	int ret_val = 0;
298 	struct nlattr *nla_a;
299 	struct nlattr *nla_b;
300 	struct netlbl_af4list *iter4;
301 #if IS_ENABLED(CONFIG_IPV6)
302 	struct netlbl_af6list *iter6;
303 #endif
304 
305 	if (entry->domain != NULL) {
306 		ret_val = nla_put_string(skb,
307 					 NLBL_MGMT_A_DOMAIN, entry->domain);
308 		if (ret_val != 0)
309 			return ret_val;
310 	}
311 
312 	ret_val = nla_put_u16(skb, NLBL_MGMT_A_FAMILY, entry->family);
313 	if (ret_val != 0)
314 		return ret_val;
315 
316 	switch (entry->def.type) {
317 	case NETLBL_NLTYPE_ADDRSELECT:
318 		nla_a = nla_nest_start_noflag(skb, NLBL_MGMT_A_SELECTORLIST);
319 		if (nla_a == NULL)
320 			return -ENOMEM;
321 
322 		netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) {
323 			struct netlbl_domaddr4_map *map4;
324 			struct in_addr addr_struct;
325 
326 			nla_b = nla_nest_start_noflag(skb,
327 						      NLBL_MGMT_A_ADDRSELECTOR);
328 			if (nla_b == NULL)
329 				return -ENOMEM;
330 
331 			addr_struct.s_addr = iter4->addr;
332 			ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4ADDR,
333 						  addr_struct.s_addr);
334 			if (ret_val != 0)
335 				return ret_val;
336 			addr_struct.s_addr = iter4->mask;
337 			ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4MASK,
338 						  addr_struct.s_addr);
339 			if (ret_val != 0)
340 				return ret_val;
341 			map4 = netlbl_domhsh_addr4_entry(iter4);
342 			ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
343 					      map4->def.type);
344 			if (ret_val != 0)
345 				return ret_val;
346 			switch (map4->def.type) {
347 			case NETLBL_NLTYPE_CIPSOV4:
348 				ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
349 						      map4->def.cipso->doi);
350 				if (ret_val != 0)
351 					return ret_val;
352 				break;
353 			}
354 
355 			nla_nest_end(skb, nla_b);
356 		}
357 #if IS_ENABLED(CONFIG_IPV6)
358 		netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) {
359 			struct netlbl_domaddr6_map *map6;
360 
361 			nla_b = nla_nest_start_noflag(skb,
362 						      NLBL_MGMT_A_ADDRSELECTOR);
363 			if (nla_b == NULL)
364 				return -ENOMEM;
365 
366 			ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6ADDR,
367 						   &iter6->addr);
368 			if (ret_val != 0)
369 				return ret_val;
370 			ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6MASK,
371 						   &iter6->mask);
372 			if (ret_val != 0)
373 				return ret_val;
374 			map6 = netlbl_domhsh_addr6_entry(iter6);
375 			ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
376 					      map6->def.type);
377 			if (ret_val != 0)
378 				return ret_val;
379 
380 			switch (map6->def.type) {
381 			case NETLBL_NLTYPE_CALIPSO:
382 				ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
383 						      map6->def.calipso->doi);
384 				if (ret_val != 0)
385 					return ret_val;
386 				break;
387 			}
388 
389 			nla_nest_end(skb, nla_b);
390 		}
391 #endif /* IPv6 */
392 
393 		nla_nest_end(skb, nla_a);
394 		break;
395 	case NETLBL_NLTYPE_UNLABELED:
396 		ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
397 				      entry->def.type);
398 		break;
399 	case NETLBL_NLTYPE_CIPSOV4:
400 		ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
401 				      entry->def.type);
402 		if (ret_val != 0)
403 			return ret_val;
404 		ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
405 				      entry->def.cipso->doi);
406 		break;
407 	case NETLBL_NLTYPE_CALIPSO:
408 		ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
409 				      entry->def.type);
410 		if (ret_val != 0)
411 			return ret_val;
412 		ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
413 				      entry->def.calipso->doi);
414 		break;
415 	}
416 
417 	return ret_val;
418 }
419 
420 /*
421  * NetLabel Command Handlers
422  */
423 
424 /**
425  * netlbl_mgmt_add - Handle an ADD message
426  * @skb: the NETLINK buffer
427  * @info: the Generic NETLINK info block
428  *
429  * Description:
430  * Process a user generated ADD message and add the domains from the message
431  * to the hash table.  See netlabel.h for a description of the message format.
432  * Returns zero on success, negative values on failure.
433  *
434  */
435 static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
436 {
437 	struct netlbl_audit audit_info;
438 
439 	if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) ||
440 	    (!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
441 	    (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
442 	     info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
443 	    (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
444 	     info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
445 	    ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
446 	     (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
447 	    ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
448 	     (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
449 		return -EINVAL;
450 
451 	netlbl_netlink_auditinfo(skb, &audit_info);
452 
453 	return netlbl_mgmt_add_common(info, &audit_info);
454 }
455 
456 /**
457  * netlbl_mgmt_remove - Handle a REMOVE message
458  * @skb: the NETLINK buffer
459  * @info: the Generic NETLINK info block
460  *
461  * Description:
462  * Process a user generated REMOVE message and remove the specified domain
463  * mappings.  Returns zero on success, negative values on failure.
464  *
465  */
466 static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
467 {
468 	char *domain;
469 	struct netlbl_audit audit_info;
470 
471 	if (!info->attrs[NLBL_MGMT_A_DOMAIN])
472 		return -EINVAL;
473 
474 	netlbl_netlink_auditinfo(skb, &audit_info);
475 
476 	domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
477 	return netlbl_domhsh_remove(domain, AF_UNSPEC, &audit_info);
478 }
479 
480 /**
481  * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL
482  * @entry: the domain mapping hash table entry
483  * @arg: the netlbl_domhsh_walk_arg structure
484  *
485  * Description:
486  * This function is designed to be used as a callback to the
487  * netlbl_domhsh_walk() function for use in generating a response for a LISTALL
488  * message.  Returns the size of the message on success, negative values on
489  * failure.
490  *
491  */
492 static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
493 {
494 	int ret_val = -ENOMEM;
495 	struct netlbl_domhsh_walk_arg *cb_arg = arg;
496 	void *data;
497 
498 	data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
499 			   cb_arg->seq, &netlbl_mgmt_gnl_family,
500 			   NLM_F_MULTI, NLBL_MGMT_C_LISTALL);
501 	if (data == NULL)
502 		goto listall_cb_failure;
503 
504 	ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry);
505 	if (ret_val != 0)
506 		goto listall_cb_failure;
507 
508 	cb_arg->seq++;
509 	genlmsg_end(cb_arg->skb, data);
510 	return 0;
511 
512 listall_cb_failure:
513 	genlmsg_cancel(cb_arg->skb, data);
514 	return ret_val;
515 }
516 
517 /**
518  * netlbl_mgmt_listall - Handle a LISTALL message
519  * @skb: the NETLINK buffer
520  * @cb: the NETLINK callback
521  *
522  * Description:
523  * Process a user generated LISTALL message and dumps the domain hash table in
524  * a form suitable for use in a kernel generated LISTALL message.  Returns zero
525  * on success, negative values on failure.
526  *
527  */
528 static int netlbl_mgmt_listall(struct sk_buff *skb,
529 			       struct netlink_callback *cb)
530 {
531 	struct netlbl_domhsh_walk_arg cb_arg;
532 	u32 skip_bkt = cb->args[0];
533 	u32 skip_chain = cb->args[1];
534 
535 	cb_arg.nl_cb = cb;
536 	cb_arg.skb = skb;
537 	cb_arg.seq = cb->nlh->nlmsg_seq;
538 
539 	netlbl_domhsh_walk(&skip_bkt,
540 			   &skip_chain,
541 			   netlbl_mgmt_listall_cb,
542 			   &cb_arg);
543 
544 	cb->args[0] = skip_bkt;
545 	cb->args[1] = skip_chain;
546 	return skb->len;
547 }
548 
549 /**
550  * netlbl_mgmt_adddef - Handle an ADDDEF message
551  * @skb: the NETLINK buffer
552  * @info: the Generic NETLINK info block
553  *
554  * Description:
555  * Process a user generated ADDDEF message and respond accordingly.  Returns
556  * zero on success, negative values on failure.
557  *
558  */
559 static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
560 {
561 	struct netlbl_audit audit_info;
562 
563 	if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
564 	    (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
565 	     info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
566 	    (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
567 	     info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
568 	    ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
569 	     (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
570 	    ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
571 	     (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
572 		return -EINVAL;
573 
574 	netlbl_netlink_auditinfo(skb, &audit_info);
575 
576 	return netlbl_mgmt_add_common(info, &audit_info);
577 }
578 
579 /**
580  * netlbl_mgmt_removedef - Handle a REMOVEDEF message
581  * @skb: the NETLINK buffer
582  * @info: the Generic NETLINK info block
583  *
584  * Description:
585  * Process a user generated REMOVEDEF message and remove the default domain
586  * mapping.  Returns zero on success, negative values on failure.
587  *
588  */
589 static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
590 {
591 	struct netlbl_audit audit_info;
592 
593 	netlbl_netlink_auditinfo(skb, &audit_info);
594 
595 	return netlbl_domhsh_remove_default(AF_UNSPEC, &audit_info);
596 }
597 
598 /**
599  * netlbl_mgmt_listdef - Handle a LISTDEF message
600  * @skb: the NETLINK buffer
601  * @info: the Generic NETLINK info block
602  *
603  * Description:
604  * Process a user generated LISTDEF message and dumps the default domain
605  * mapping in a form suitable for use in a kernel generated LISTDEF message.
606  * Returns zero on success, negative values on failure.
607  *
608  */
609 static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
610 {
611 	int ret_val = -ENOMEM;
612 	struct sk_buff *ans_skb = NULL;
613 	void *data;
614 	struct netlbl_dom_map *entry;
615 	u16 family;
616 
617 	if (info->attrs[NLBL_MGMT_A_FAMILY])
618 		family = nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
619 	else
620 		family = AF_INET;
621 
622 	ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
623 	if (ans_skb == NULL)
624 		return -ENOMEM;
625 	data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
626 				 0, NLBL_MGMT_C_LISTDEF);
627 	if (data == NULL)
628 		goto listdef_failure;
629 
630 	rcu_read_lock();
631 	entry = netlbl_domhsh_getentry(NULL, family);
632 	if (entry == NULL) {
633 		ret_val = -ENOENT;
634 		goto listdef_failure_lock;
635 	}
636 	ret_val = netlbl_mgmt_listentry(ans_skb, entry);
637 	rcu_read_unlock();
638 	if (ret_val != 0)
639 		goto listdef_failure;
640 
641 	genlmsg_end(ans_skb, data);
642 	return genlmsg_reply(ans_skb, info);
643 
644 listdef_failure_lock:
645 	rcu_read_unlock();
646 listdef_failure:
647 	kfree_skb(ans_skb);
648 	return ret_val;
649 }
650 
651 /**
652  * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response
653  * @skb: the skb to write to
654  * @cb: the NETLINK callback
655  * @protocol: the NetLabel protocol to use in the message
656  *
657  * Description:
658  * This function is to be used in conjunction with netlbl_mgmt_protocols() to
659  * answer a application's PROTOCOLS message.  Returns the size of the message
660  * on success, negative values on failure.
661  *
662  */
663 static int netlbl_mgmt_protocols_cb(struct sk_buff *skb,
664 				    struct netlink_callback *cb,
665 				    u32 protocol)
666 {
667 	int ret_val = -ENOMEM;
668 	void *data;
669 
670 	data = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
671 			   &netlbl_mgmt_gnl_family, NLM_F_MULTI,
672 			   NLBL_MGMT_C_PROTOCOLS);
673 	if (data == NULL)
674 		goto protocols_cb_failure;
675 
676 	ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol);
677 	if (ret_val != 0)
678 		goto protocols_cb_failure;
679 
680 	genlmsg_end(skb, data);
681 	return 0;
682 
683 protocols_cb_failure:
684 	genlmsg_cancel(skb, data);
685 	return ret_val;
686 }
687 
688 /**
689  * netlbl_mgmt_protocols - Handle a PROTOCOLS message
690  * @skb: the NETLINK buffer
691  * @cb: the NETLINK callback
692  *
693  * Description:
694  * Process a user generated PROTOCOLS message and respond accordingly.
695  *
696  */
697 static int netlbl_mgmt_protocols(struct sk_buff *skb,
698 				 struct netlink_callback *cb)
699 {
700 	u32 protos_sent = cb->args[0];
701 
702 	if (protos_sent == 0) {
703 		if (netlbl_mgmt_protocols_cb(skb,
704 					     cb,
705 					     NETLBL_NLTYPE_UNLABELED) < 0)
706 			goto protocols_return;
707 		protos_sent++;
708 	}
709 	if (protos_sent == 1) {
710 		if (netlbl_mgmt_protocols_cb(skb,
711 					     cb,
712 					     NETLBL_NLTYPE_CIPSOV4) < 0)
713 			goto protocols_return;
714 		protos_sent++;
715 	}
716 #if IS_ENABLED(CONFIG_IPV6)
717 	if (protos_sent == 2) {
718 		if (netlbl_mgmt_protocols_cb(skb,
719 					     cb,
720 					     NETLBL_NLTYPE_CALIPSO) < 0)
721 			goto protocols_return;
722 		protos_sent++;
723 	}
724 #endif
725 
726 protocols_return:
727 	cb->args[0] = protos_sent;
728 	return skb->len;
729 }
730 
731 /**
732  * netlbl_mgmt_version - Handle a VERSION message
733  * @skb: the NETLINK buffer
734  * @info: the Generic NETLINK info block
735  *
736  * Description:
737  * Process a user generated VERSION message and respond accordingly.  Returns
738  * zero on success, negative values on failure.
739  *
740  */
741 static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
742 {
743 	int ret_val = -ENOMEM;
744 	struct sk_buff *ans_skb = NULL;
745 	void *data;
746 
747 	ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
748 	if (ans_skb == NULL)
749 		return -ENOMEM;
750 	data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
751 				 0, NLBL_MGMT_C_VERSION);
752 	if (data == NULL)
753 		goto version_failure;
754 
755 	ret_val = nla_put_u32(ans_skb,
756 			      NLBL_MGMT_A_VERSION,
757 			      NETLBL_PROTO_VERSION);
758 	if (ret_val != 0)
759 		goto version_failure;
760 
761 	genlmsg_end(ans_skb, data);
762 	return genlmsg_reply(ans_skb, info);
763 
764 version_failure:
765 	kfree_skb(ans_skb);
766 	return ret_val;
767 }
768 
769 
770 /*
771  * NetLabel Generic NETLINK Command Definitions
772  */
773 
774 static const struct genl_ops netlbl_mgmt_genl_ops[] = {
775 	{
776 	.cmd = NLBL_MGMT_C_ADD,
777 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
778 	.flags = GENL_ADMIN_PERM,
779 	.doit = netlbl_mgmt_add,
780 	.dumpit = NULL,
781 	},
782 	{
783 	.cmd = NLBL_MGMT_C_REMOVE,
784 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
785 	.flags = GENL_ADMIN_PERM,
786 	.doit = netlbl_mgmt_remove,
787 	.dumpit = NULL,
788 	},
789 	{
790 	.cmd = NLBL_MGMT_C_LISTALL,
791 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
792 	.flags = 0,
793 	.doit = NULL,
794 	.dumpit = netlbl_mgmt_listall,
795 	},
796 	{
797 	.cmd = NLBL_MGMT_C_ADDDEF,
798 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
799 	.flags = GENL_ADMIN_PERM,
800 	.doit = netlbl_mgmt_adddef,
801 	.dumpit = NULL,
802 	},
803 	{
804 	.cmd = NLBL_MGMT_C_REMOVEDEF,
805 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
806 	.flags = GENL_ADMIN_PERM,
807 	.doit = netlbl_mgmt_removedef,
808 	.dumpit = NULL,
809 	},
810 	{
811 	.cmd = NLBL_MGMT_C_LISTDEF,
812 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
813 	.flags = 0,
814 	.doit = netlbl_mgmt_listdef,
815 	.dumpit = NULL,
816 	},
817 	{
818 	.cmd = NLBL_MGMT_C_PROTOCOLS,
819 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
820 	.flags = 0,
821 	.doit = NULL,
822 	.dumpit = netlbl_mgmt_protocols,
823 	},
824 	{
825 	.cmd = NLBL_MGMT_C_VERSION,
826 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
827 	.flags = 0,
828 	.doit = netlbl_mgmt_version,
829 	.dumpit = NULL,
830 	},
831 };
832 
833 static struct genl_family netlbl_mgmt_gnl_family __ro_after_init = {
834 	.hdrsize = 0,
835 	.name = NETLBL_NLTYPE_MGMT_NAME,
836 	.version = NETLBL_PROTO_VERSION,
837 	.maxattr = NLBL_MGMT_A_MAX,
838 	.policy = netlbl_mgmt_genl_policy,
839 	.module = THIS_MODULE,
840 	.ops = netlbl_mgmt_genl_ops,
841 	.n_ops = ARRAY_SIZE(netlbl_mgmt_genl_ops),
842 };
843 
844 /*
845  * NetLabel Generic NETLINK Protocol Functions
846  */
847 
848 /**
849  * netlbl_mgmt_genl_init - Register the NetLabel management component
850  *
851  * Description:
852  * Register the NetLabel management component with the Generic NETLINK
853  * mechanism.  Returns zero on success, negative values on failure.
854  *
855  */
856 int __init netlbl_mgmt_genl_init(void)
857 {
858 	return genl_register_family(&netlbl_mgmt_gnl_family);
859 }
860