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