Blame view

net/netlabel/netlabel_mgmt.c 20.1 KB
d15c345fe   Paul Moore   [NetLabel]: core ...
1
2
3
4
5
6
7
  /*
   * NetLabel Management Support
   *
   * This file defines the management functions for the NetLabel system.  The
   * NetLabel system manages static and dynamic label mappings for network
   * protocols such as CIPSO and RIPSO.
   *
82c21bfab   Paul Moore   doc: Update the e...
8
   * Author: Paul Moore <paul@paul-moore.com>
d15c345fe   Paul Moore   [NetLabel]: core ...
9
10
11
12
   *
   */
  
  /*
63c416887   Paul Moore   netlabel: Add net...
13
   * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
d15c345fe   Paul Moore   [NetLabel]: core ...
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
   *
   * This program is free software;  you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY;  without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
   * the GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program;  if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   *
   */
  
  #include <linux/types.h>
  #include <linux/socket.h>
  #include <linux/string.h>
  #include <linux/skbuff.h>
63c416887   Paul Moore   netlabel: Add net...
35
36
  #include <linux/in.h>
  #include <linux/in6.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
37
  #include <linux/slab.h>
d15c345fe   Paul Moore   [NetLabel]: core ...
38
39
40
  #include <net/sock.h>
  #include <net/netlink.h>
  #include <net/genetlink.h>
63c416887   Paul Moore   netlabel: Add net...
41
42
  #include <net/ip.h>
  #include <net/ipv6.h>
d15c345fe   Paul Moore   [NetLabel]: core ...
43
44
  #include <net/netlabel.h>
  #include <net/cipso_ipv4.h>
60063497a   Arun Sharma   atomic: use <linu...
45
  #include <linux/atomic.h>
d15c345fe   Paul Moore   [NetLabel]: core ...
46
47
48
49
  
  #include "netlabel_domainhash.h"
  #include "netlabel_user.h"
  #include "netlabel_mgmt.h"
c783f1ce5   Paul Moore   NetLabel: Remove ...
50
51
  /* NetLabel configured protocol counter */
  atomic_t netlabel_mgmt_protocount = ATOMIC_INIT(0);
23bcdc1ad   Paul Moore   SELinux: enable d...
52

fd3858554   Paul Moore   [NetLabel]: rewor...
53
54
55
56
57
58
  /* Argument struct for netlbl_domhsh_walk() */
  struct netlbl_domhsh_walk_arg {
  	struct netlink_callback *nl_cb;
  	struct sk_buff *skb;
  	u32 seq;
  };
d15c345fe   Paul Moore   [NetLabel]: core ...
59
60
61
62
63
64
  /* NetLabel Generic NETLINK CIPSOv4 family */
  static struct genl_family netlbl_mgmt_gnl_family = {
  	.id = GENL_ID_GENERATE,
  	.hdrsize = 0,
  	.name = NETLBL_NLTYPE_MGMT_NAME,
  	.version = NETLBL_PROTO_VERSION,
fd3858554   Paul Moore   [NetLabel]: rewor...
65
  	.maxattr = NLBL_MGMT_A_MAX,
d15c345fe   Paul Moore   [NetLabel]: core ...
66
  };
fd3858554   Paul Moore   [NetLabel]: rewor...
67
  /* NetLabel Netlink attribute policy */
ef7c79ed6   Patrick McHardy   [NETLINK]: Mark n...
68
  static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
fd3858554   Paul Moore   [NetLabel]: rewor...
69
70
71
72
73
  	[NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING },
  	[NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 },
  	[NLBL_MGMT_A_VERSION] = { .type = NLA_U32 },
  	[NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
  };
d15c345fe   Paul Moore   [NetLabel]: core ...
74
75
  
  /*
63c416887   Paul Moore   netlabel: Add net...
76
   * Helper Functions
d15c345fe   Paul Moore   [NetLabel]: core ...
77
78
79
80
   */
  
  /**
   * netlbl_mgmt_add - Handle an ADD message
d15c345fe   Paul Moore   [NetLabel]: core ...
81
   * @info: the Generic NETLINK info block
63c416887   Paul Moore   netlabel: Add net...
82
   * @audit_info: NetLabel audit information
d15c345fe   Paul Moore   [NetLabel]: core ...
83
84
   *
   * Description:
63c416887   Paul Moore   netlabel: Add net...
85
86
87
   * Helper function for the ADD and ADDDEF messages to add the domain mappings
   * from the message to the hash table.  See netlabel.h for a description of the
   * message format.  Returns zero on success, negative values on failure.
d15c345fe   Paul Moore   [NetLabel]: core ...
88
89
   *
   */
63c416887   Paul Moore   netlabel: Add net...
90
91
  static int netlbl_mgmt_add_common(struct genl_info *info,
  				  struct netlbl_audit *audit_info)
d15c345fe   Paul Moore   [NetLabel]: core ...
92
93
  {
  	int ret_val = -EINVAL;
d15c345fe   Paul Moore   [NetLabel]: core ...
94
  	struct netlbl_dom_map *entry = NULL;
63c416887   Paul Moore   netlabel: Add net...
95
96
  	struct netlbl_domaddr_map *addrmap = NULL;
  	struct cipso_v4_doi *cipsov4 = NULL;
d15c345fe   Paul Moore   [NetLabel]: core ...
97
  	u32 tmp_val;
95d4e6be2   Paul Moore   [NetLabel]: audit...
98

fd3858554   Paul Moore   [NetLabel]: rewor...
99
100
101
102
103
  	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
  	if (entry == NULL) {
  		ret_val = -ENOMEM;
  		goto add_failure;
  	}
fd3858554   Paul Moore   [NetLabel]: rewor...
104
  	entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
63c416887   Paul Moore   netlabel: Add net...
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  	if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
  		size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
  		entry->domain = kmalloc(tmp_size, GFP_KERNEL);
  		if (entry->domain == NULL) {
  			ret_val = -ENOMEM;
  			goto add_failure;
  		}
  		nla_strlcpy(entry->domain,
  			    info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
  	}
  
  	/* NOTE: internally we allow/use a entry->type value of
  	 *       NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
  	 *       to pass that as a protocol value because we need to know the
  	 *       "real" protocol */
d15c345fe   Paul Moore   [NetLabel]: core ...
120

fd3858554   Paul Moore   [NetLabel]: rewor...
121
122
  	switch (entry->type) {
  	case NETLBL_NLTYPE_UNLABELED:
fd3858554   Paul Moore   [NetLabel]: rewor...
123
124
125
  		break;
  	case NETLBL_NLTYPE_CIPSOV4:
  		if (!info->attrs[NLBL_MGMT_A_CV4DOI])
d15c345fe   Paul Moore   [NetLabel]: core ...
126
  			goto add_failure;
d15c345fe   Paul Moore   [NetLabel]: core ...
127

fd3858554   Paul Moore   [NetLabel]: rewor...
128
  		tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
63c416887   Paul Moore   netlabel: Add net...
129
130
  		cipsov4 = cipso_v4_doi_getdef(tmp_val);
  		if (cipsov4 == NULL)
d15c345fe   Paul Moore   [NetLabel]: core ...
131
  			goto add_failure;
63c416887   Paul Moore   netlabel: Add net...
132
  		entry->type_def.cipsov4 = cipsov4;
fd3858554   Paul Moore   [NetLabel]: rewor...
133
134
135
  		break;
  	default:
  		goto add_failure;
d15c345fe   Paul Moore   [NetLabel]: core ...
136
  	}
63c416887   Paul Moore   netlabel: Add net...
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
  
  	if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
  		struct in_addr *addr;
  		struct in_addr *mask;
  		struct netlbl_domaddr4_map *map;
  
  		addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
  		if (addrmap == NULL) {
  			ret_val = -ENOMEM;
  			goto add_failure;
  		}
  		INIT_LIST_HEAD(&addrmap->list4);
  		INIT_LIST_HEAD(&addrmap->list6);
  
  		if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) !=
  		    sizeof(struct in_addr)) {
  			ret_val = -EINVAL;
  			goto add_failure;
  		}
  		if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) !=
  		    sizeof(struct in_addr)) {
  			ret_val = -EINVAL;
  			goto add_failure;
  		}
  		addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]);
  		mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]);
  
  		map = kzalloc(sizeof(*map), GFP_KERNEL);
  		if (map == NULL) {
  			ret_val = -ENOMEM;
  			goto add_failure;
  		}
  		map->list.addr = addr->s_addr & mask->s_addr;
  		map->list.mask = mask->s_addr;
  		map->list.valid = 1;
  		map->type = entry->type;
  		if (cipsov4)
  			map->type_def.cipsov4 = cipsov4;
  
  		ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
  		if (ret_val != 0) {
  			kfree(map);
  			goto add_failure;
  		}
  
  		entry->type = NETLBL_NLTYPE_ADDRSELECT;
  		entry->type_def.addrsel = addrmap;
  #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
  	} else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) {
  		struct in6_addr *addr;
  		struct in6_addr *mask;
  		struct netlbl_domaddr6_map *map;
  
  		addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
  		if (addrmap == NULL) {
  			ret_val = -ENOMEM;
  			goto add_failure;
  		}
  		INIT_LIST_HEAD(&addrmap->list4);
  		INIT_LIST_HEAD(&addrmap->list6);
  
  		if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) !=
  		    sizeof(struct in6_addr)) {
  			ret_val = -EINVAL;
  			goto add_failure;
  		}
  		if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) !=
  		    sizeof(struct in6_addr)) {
  			ret_val = -EINVAL;
  			goto add_failure;
  		}
  		addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]);
  		mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]);
  
  		map = kzalloc(sizeof(*map), GFP_KERNEL);
  		if (map == NULL) {
  			ret_val = -ENOMEM;
  			goto add_failure;
  		}
  		ipv6_addr_copy(&map->list.addr, addr);
  		map->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
  		map->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
  		map->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
  		map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
  		ipv6_addr_copy(&map->list.mask, mask);
  		map->list.valid = 1;
  		map->type = entry->type;
  
  		ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
  		if (ret_val != 0) {
  			kfree(map);
  			goto add_failure;
  		}
  
  		entry->type = NETLBL_NLTYPE_ADDRSELECT;
  		entry->type_def.addrsel = addrmap;
  #endif /* IPv6 */
  	}
  
  	ret_val = netlbl_domhsh_add(entry, audit_info);
fd3858554   Paul Moore   [NetLabel]: rewor...
237
238
  	if (ret_val != 0)
  		goto add_failure;
d15c345fe   Paul Moore   [NetLabel]: core ...
239

d15c345fe   Paul Moore   [NetLabel]: core ...
240
241
242
  	return 0;
  
  add_failure:
63c416887   Paul Moore   netlabel: Add net...
243
244
  	if (cipsov4)
  		cipso_v4_doi_putdef(cipsov4);
d15c345fe   Paul Moore   [NetLabel]: core ...
245
246
  	if (entry)
  		kfree(entry->domain);
63c416887   Paul Moore   netlabel: Add net...
247
  	kfree(addrmap);
d15c345fe   Paul Moore   [NetLabel]: core ...
248
  	kfree(entry);
d15c345fe   Paul Moore   [NetLabel]: core ...
249
250
251
252
  	return ret_val;
  }
  
  /**
63c416887   Paul Moore   netlabel: Add net...
253
254
255
256
257
258
   * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry
   * @skb: the NETLINK buffer
   * @entry: the map entry
   *
   * Description:
   * This function is a helper function used by the LISTALL and LISTDEF command
25985edce   Lucas De Marchi   Fix common misspe...
259
   * handlers.  The caller is responsible for ensuring that the RCU read lock
63c416887   Paul Moore   netlabel: Add net...
260
261
262
263
264
265
   * is held.  Returns zero on success, negative values on failure.
   *
   */
  static int netlbl_mgmt_listentry(struct sk_buff *skb,
  				 struct netlbl_dom_map *entry)
  {
f8a024796   Paul Moore   netlabel: Fix com...
266
  	int ret_val = 0;
63c416887   Paul Moore   netlabel: Add net...
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
  	struct nlattr *nla_a;
  	struct nlattr *nla_b;
  	struct netlbl_af4list *iter4;
  #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
  	struct netlbl_af6list *iter6;
  #endif
  
  	if (entry->domain != NULL) {
  		ret_val = nla_put_string(skb,
  					 NLBL_MGMT_A_DOMAIN, entry->domain);
  		if (ret_val != 0)
  			return ret_val;
  	}
  
  	switch (entry->type) {
  	case NETLBL_NLTYPE_ADDRSELECT:
  		nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST);
  		if (nla_a == NULL)
  			return -ENOMEM;
  
  		netlbl_af4list_foreach_rcu(iter4,
  					   &entry->type_def.addrsel->list4) {
  			struct netlbl_domaddr4_map *map4;
  			struct in_addr addr_struct;
  
  			nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR);
  			if (nla_b == NULL)
  				return -ENOMEM;
  
  			addr_struct.s_addr = iter4->addr;
  			ret_val = nla_put(skb, NLBL_MGMT_A_IPV4ADDR,
  					  sizeof(struct in_addr),
  					  &addr_struct);
  			if (ret_val != 0)
  				return ret_val;
  			addr_struct.s_addr = iter4->mask;
  			ret_val = nla_put(skb, NLBL_MGMT_A_IPV4MASK,
  					  sizeof(struct in_addr),
  					  &addr_struct);
  			if (ret_val != 0)
  				return ret_val;
  			map4 = netlbl_domhsh_addr4_entry(iter4);
  			ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
  					      map4->type);
  			if (ret_val != 0)
  				return ret_val;
  			switch (map4->type) {
  			case NETLBL_NLTYPE_CIPSOV4:
  				ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
  						  map4->type_def.cipsov4->doi);
  				if (ret_val != 0)
  					return ret_val;
  				break;
  			}
  
  			nla_nest_end(skb, nla_b);
  		}
  #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
  		netlbl_af6list_foreach_rcu(iter6,
  					   &entry->type_def.addrsel->list6) {
  			struct netlbl_domaddr6_map *map6;
  
  			nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR);
  			if (nla_b == NULL)
  				return -ENOMEM;
  
  			ret_val = nla_put(skb, NLBL_MGMT_A_IPV6ADDR,
  					  sizeof(struct in6_addr),
  					  &iter6->addr);
  			if (ret_val != 0)
  				return ret_val;
  			ret_val = nla_put(skb, NLBL_MGMT_A_IPV6MASK,
  					  sizeof(struct in6_addr),
  					  &iter6->mask);
  			if (ret_val != 0)
  				return ret_val;
  			map6 = netlbl_domhsh_addr6_entry(iter6);
  			ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
  					      map6->type);
  			if (ret_val != 0)
  				return ret_val;
  
  			nla_nest_end(skb, nla_b);
  		}
  #endif /* IPv6 */
  
  		nla_nest_end(skb, nla_a);
  		break;
  	case NETLBL_NLTYPE_UNLABELED:
  		ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type);
  		break;
  	case NETLBL_NLTYPE_CIPSOV4:
  		ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type);
  		if (ret_val != 0)
  			return ret_val;
  		ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
  				      entry->type_def.cipsov4->doi);
  		break;
  	}
  
  	return ret_val;
  }
  
  /*
   * NetLabel Command Handlers
   */
  
  /**
   * netlbl_mgmt_add - Handle an ADD message
   * @skb: the NETLINK buffer
   * @info: the Generic NETLINK info block
   *
   * Description:
   * Process a user generated ADD message and add the domains from the message
   * to the hash table.  See netlabel.h for a description of the message format.
   * Returns zero on success, negative values on failure.
   *
   */
  static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
  {
  	struct netlbl_audit audit_info;
  
  	if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) ||
  	    (!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
  	    (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
  	     info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
  	    (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
  	     info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
  	    ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
  	     (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
  	    ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
  	     (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
  		return -EINVAL;
  
  	netlbl_netlink_auditinfo(skb, &audit_info);
  
  	return netlbl_mgmt_add_common(info, &audit_info);
  }
  
  /**
d15c345fe   Paul Moore   [NetLabel]: core ...
407
408
409
410
411
412
413
414
415
416
417
   * netlbl_mgmt_remove - Handle a REMOVE message
   * @skb: the NETLINK buffer
   * @info: the Generic NETLINK info block
   *
   * Description:
   * Process a user generated REMOVE message and remove the specified domain
   * mappings.  Returns zero on success, negative values on failure.
   *
   */
  static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
  {
fd3858554   Paul Moore   [NetLabel]: rewor...
418
  	char *domain;
95d4e6be2   Paul Moore   [NetLabel]: audit...
419
  	struct netlbl_audit audit_info;
d15c345fe   Paul Moore   [NetLabel]: core ...
420

fd3858554   Paul Moore   [NetLabel]: rewor...
421
422
  	if (!info->attrs[NLBL_MGMT_A_DOMAIN])
  		return -EINVAL;
d15c345fe   Paul Moore   [NetLabel]: core ...
423

95d4e6be2   Paul Moore   [NetLabel]: audit...
424
  	netlbl_netlink_auditinfo(skb, &audit_info);
fd3858554   Paul Moore   [NetLabel]: rewor...
425
  	domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
95d4e6be2   Paul Moore   [NetLabel]: audit...
426
  	return netlbl_domhsh_remove(domain, &audit_info);
fd3858554   Paul Moore   [NetLabel]: rewor...
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
  }
  
  /**
   * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL
   * @entry: the domain mapping hash table entry
   * @arg: the netlbl_domhsh_walk_arg structure
   *
   * Description:
   * This function is designed to be used as a callback to the
   * netlbl_domhsh_walk() function for use in generating a response for a LISTALL
   * message.  Returns the size of the message on success, negative values on
   * failure.
   *
   */
  static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
  {
  	int ret_val = -ENOMEM;
  	struct netlbl_domhsh_walk_arg *cb_arg = arg;
  	void *data;
17c157c88   Thomas Graf   [GENL]: Add genlm...
446
447
448
  	data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).pid,
  			   cb_arg->seq, &netlbl_mgmt_gnl_family,
  			   NLM_F_MULTI, NLBL_MGMT_C_LISTALL);
fd3858554   Paul Moore   [NetLabel]: rewor...
449
450
  	if (data == NULL)
  		goto listall_cb_failure;
63c416887   Paul Moore   netlabel: Add net...
451
  	ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry);
fd3858554   Paul Moore   [NetLabel]: rewor...
452
453
  	if (ret_val != 0)
  		goto listall_cb_failure;
d15c345fe   Paul Moore   [NetLabel]: core ...
454

fd3858554   Paul Moore   [NetLabel]: rewor...
455
456
  	cb_arg->seq++;
  	return genlmsg_end(cb_arg->skb, data);
d15c345fe   Paul Moore   [NetLabel]: core ...
457

fd3858554   Paul Moore   [NetLabel]: rewor...
458
459
  listall_cb_failure:
  	genlmsg_cancel(cb_arg->skb, data);
d15c345fe   Paul Moore   [NetLabel]: core ...
460
461
462
463
  	return ret_val;
  }
  
  /**
fd3858554   Paul Moore   [NetLabel]: rewor...
464
   * netlbl_mgmt_listall - Handle a LISTALL message
d15c345fe   Paul Moore   [NetLabel]: core ...
465
   * @skb: the NETLINK buffer
fd3858554   Paul Moore   [NetLabel]: rewor...
466
   * @cb: the NETLINK callback
d15c345fe   Paul Moore   [NetLabel]: core ...
467
468
   *
   * Description:
fd3858554   Paul Moore   [NetLabel]: rewor...
469
470
471
   * Process a user generated LISTALL message and dumps the domain hash table in
   * a form suitable for use in a kernel generated LISTALL message.  Returns zero
   * on success, negative values on failure.
d15c345fe   Paul Moore   [NetLabel]: core ...
472
473
   *
   */
fd3858554   Paul Moore   [NetLabel]: rewor...
474
475
  static int netlbl_mgmt_listall(struct sk_buff *skb,
  			       struct netlink_callback *cb)
d15c345fe   Paul Moore   [NetLabel]: core ...
476
  {
fd3858554   Paul Moore   [NetLabel]: rewor...
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
  	struct netlbl_domhsh_walk_arg cb_arg;
  	u32 skip_bkt = cb->args[0];
  	u32 skip_chain = cb->args[1];
  
  	cb_arg.nl_cb = cb;
  	cb_arg.skb = skb;
  	cb_arg.seq = cb->nlh->nlmsg_seq;
  
  	netlbl_domhsh_walk(&skip_bkt,
  			   &skip_chain,
  			   netlbl_mgmt_listall_cb,
  			   &cb_arg);
  
  	cb->args[0] = skip_bkt;
  	cb->args[1] = skip_chain;
  	return skb->len;
d15c345fe   Paul Moore   [NetLabel]: core ...
493
494
495
496
497
498
499
500
501
502
503
504
505
506
  }
  
  /**
   * netlbl_mgmt_adddef - Handle an ADDDEF message
   * @skb: the NETLINK buffer
   * @info: the Generic NETLINK info block
   *
   * Description:
   * Process a user generated ADDDEF message and respond accordingly.  Returns
   * zero on success, negative values on failure.
   *
   */
  static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
  {
95d4e6be2   Paul Moore   [NetLabel]: audit...
507
  	struct netlbl_audit audit_info;
d15c345fe   Paul Moore   [NetLabel]: core ...
508

63c416887   Paul Moore   netlabel: Add net...
509
510
511
512
513
514
515
516
517
518
  	if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
  	    (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
  	     info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
  	    (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
  	     info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
  	    ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
  	     (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
  	    ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
  	     (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
  		return -EINVAL;
d15c345fe   Paul Moore   [NetLabel]: core ...
519

95d4e6be2   Paul Moore   [NetLabel]: audit...
520
  	netlbl_netlink_auditinfo(skb, &audit_info);
63c416887   Paul Moore   netlabel: Add net...
521
  	return netlbl_mgmt_add_common(info, &audit_info);
d15c345fe   Paul Moore   [NetLabel]: core ...
522
523
524
525
526
527
528
529
530
531
532
533
534
535
  }
  
  /**
   * netlbl_mgmt_removedef - Handle a REMOVEDEF message
   * @skb: the NETLINK buffer
   * @info: the Generic NETLINK info block
   *
   * Description:
   * Process a user generated REMOVEDEF message and remove the default domain
   * mapping.  Returns zero on success, negative values on failure.
   *
   */
  static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
  {
95d4e6be2   Paul Moore   [NetLabel]: audit...
536
537
538
539
540
  	struct netlbl_audit audit_info;
  
  	netlbl_netlink_auditinfo(skb, &audit_info);
  
  	return netlbl_domhsh_remove_default(&audit_info);
d15c345fe   Paul Moore   [NetLabel]: core ...
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
  }
  
  /**
   * netlbl_mgmt_listdef - Handle a LISTDEF message
   * @skb: the NETLINK buffer
   * @info: the Generic NETLINK info block
   *
   * Description:
   * Process a user generated LISTDEF message and dumps the default domain
   * mapping in a form suitable for use in a kernel generated LISTDEF message.
   * Returns zero on success, negative values on failure.
   *
   */
  static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
  {
  	int ret_val = -ENOMEM;
fd3858554   Paul Moore   [NetLabel]: rewor...
557
558
559
  	struct sk_buff *ans_skb = NULL;
  	void *data;
  	struct netlbl_dom_map *entry;
d15c345fe   Paul Moore   [NetLabel]: core ...
560

339bf98ff   Thomas Graf   [NETLINK]: Do pre...
561
  	ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
d15c345fe   Paul Moore   [NetLabel]: core ...
562
  	if (ans_skb == NULL)
fd3858554   Paul Moore   [NetLabel]: rewor...
563
  		return -ENOMEM;
17c157c88   Thomas Graf   [GENL]: Add genlm...
564
565
  	data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
  				 0, NLBL_MGMT_C_LISTDEF);
fd3858554   Paul Moore   [NetLabel]: rewor...
566
  	if (data == NULL)
d15c345fe   Paul Moore   [NetLabel]: core ...
567
  		goto listdef_failure;
d15c345fe   Paul Moore   [NetLabel]: core ...
568

fd3858554   Paul Moore   [NetLabel]: rewor...
569
570
571
572
573
574
  	rcu_read_lock();
  	entry = netlbl_domhsh_getentry(NULL);
  	if (entry == NULL) {
  		ret_val = -ENOENT;
  		goto listdef_failure_lock;
  	}
63c416887   Paul Moore   netlabel: Add net...
575
  	ret_val = netlbl_mgmt_listentry(ans_skb, entry);
fd3858554   Paul Moore   [NetLabel]: rewor...
576
  	rcu_read_unlock();
63c416887   Paul Moore   netlabel: Add net...
577
578
  	if (ret_val != 0)
  		goto listdef_failure;
d15c345fe   Paul Moore   [NetLabel]: core ...
579

fd3858554   Paul Moore   [NetLabel]: rewor...
580
  	genlmsg_end(ans_skb, data);
fe785bee0   Denis V. Lunev   netlabel: netlink...
581
  	return genlmsg_reply(ans_skb, info);
d15c345fe   Paul Moore   [NetLabel]: core ...
582

fd3858554   Paul Moore   [NetLabel]: rewor...
583
584
  listdef_failure_lock:
  	rcu_read_unlock();
d15c345fe   Paul Moore   [NetLabel]: core ...
585
  listdef_failure:
fd3858554   Paul Moore   [NetLabel]: rewor...
586
  	kfree_skb(ans_skb);
d15c345fe   Paul Moore   [NetLabel]: core ...
587
588
589
590
  	return ret_val;
  }
  
  /**
fd3858554   Paul Moore   [NetLabel]: rewor...
591
592
   * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response
   * @skb: the skb to write to
fd3858554   Paul Moore   [NetLabel]: rewor...
593
594
   * @cb: the NETLINK callback
   * @protocol: the NetLabel protocol to use in the message
d15c345fe   Paul Moore   [NetLabel]: core ...
595
596
   *
   * Description:
fd3858554   Paul Moore   [NetLabel]: rewor...
597
598
599
   * This function is to be used in conjunction with netlbl_mgmt_protocols() to
   * answer a application's PROTOCOLS message.  Returns the size of the message
   * on success, negative values on failure.
d15c345fe   Paul Moore   [NetLabel]: core ...
600
601
   *
   */
fd3858554   Paul Moore   [NetLabel]: rewor...
602
603
604
  static int netlbl_mgmt_protocols_cb(struct sk_buff *skb,
  				    struct netlink_callback *cb,
  				    u32 protocol)
d15c345fe   Paul Moore   [NetLabel]: core ...
605
606
  {
  	int ret_val = -ENOMEM;
fd3858554   Paul Moore   [NetLabel]: rewor...
607
  	void *data;
17c157c88   Thomas Graf   [GENL]: Add genlm...
608
609
610
  	data = genlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
  			   &netlbl_mgmt_gnl_family, NLM_F_MULTI,
  			   NLBL_MGMT_C_PROTOCOLS);
fd3858554   Paul Moore   [NetLabel]: rewor...
611
612
613
614
  	if (data == NULL)
  		goto protocols_cb_failure;
  
  	ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol);
d15c345fe   Paul Moore   [NetLabel]: core ...
615
  	if (ret_val != 0)
fd3858554   Paul Moore   [NetLabel]: rewor...
616
  		goto protocols_cb_failure;
d15c345fe   Paul Moore   [NetLabel]: core ...
617

fd3858554   Paul Moore   [NetLabel]: rewor...
618
  	return genlmsg_end(skb, data);
d15c345fe   Paul Moore   [NetLabel]: core ...
619

fd3858554   Paul Moore   [NetLabel]: rewor...
620
621
  protocols_cb_failure:
  	genlmsg_cancel(skb, data);
d15c345fe   Paul Moore   [NetLabel]: core ...
622
623
624
625
  	return ret_val;
  }
  
  /**
fd3858554   Paul Moore   [NetLabel]: rewor...
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
   * netlbl_mgmt_protocols - Handle a PROTOCOLS message
   * @skb: the NETLINK buffer
   * @cb: the NETLINK callback
   *
   * Description:
   * Process a user generated PROTOCOLS message and respond accordingly.
   *
   */
  static int netlbl_mgmt_protocols(struct sk_buff *skb,
  				 struct netlink_callback *cb)
  {
  	u32 protos_sent = cb->args[0];
  
  	if (protos_sent == 0) {
  		if (netlbl_mgmt_protocols_cb(skb,
  					     cb,
  					     NETLBL_NLTYPE_UNLABELED) < 0)
  			goto protocols_return;
  		protos_sent++;
  	}
  	if (protos_sent == 1) {
  		if (netlbl_mgmt_protocols_cb(skb,
  					     cb,
  					     NETLBL_NLTYPE_CIPSOV4) < 0)
  			goto protocols_return;
  		protos_sent++;
  	}
  
  protocols_return:
  	cb->args[0] = protos_sent;
  	return skb->len;
  }
  
  /**
d15c345fe   Paul Moore   [NetLabel]: core ...
660
661
662
663
664
665
666
667
668
669
670
671
672
   * netlbl_mgmt_version - Handle a VERSION message
   * @skb: the NETLINK buffer
   * @info: the Generic NETLINK info block
   *
   * Description:
   * Process a user generated VERSION message and respond accordingly.  Returns
   * zero on success, negative values on failure.
   *
   */
  static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
  {
  	int ret_val = -ENOMEM;
  	struct sk_buff *ans_skb = NULL;
fd3858554   Paul Moore   [NetLabel]: rewor...
673
  	void *data;
d15c345fe   Paul Moore   [NetLabel]: core ...
674

339bf98ff   Thomas Graf   [NETLINK]: Do pre...
675
  	ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
d15c345fe   Paul Moore   [NetLabel]: core ...
676
  	if (ans_skb == NULL)
fd3858554   Paul Moore   [NetLabel]: rewor...
677
  		return -ENOMEM;
17c157c88   Thomas Graf   [GENL]: Add genlm...
678
679
  	data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
  				 0, NLBL_MGMT_C_VERSION);
fd3858554   Paul Moore   [NetLabel]: rewor...
680
  	if (data == NULL)
d15c345fe   Paul Moore   [NetLabel]: core ...
681
  		goto version_failure;
fd3858554   Paul Moore   [NetLabel]: rewor...
682
683
684
  	ret_val = nla_put_u32(ans_skb,
  			      NLBL_MGMT_A_VERSION,
  			      NETLBL_PROTO_VERSION);
d15c345fe   Paul Moore   [NetLabel]: core ...
685
686
  	if (ret_val != 0)
  		goto version_failure;
fd3858554   Paul Moore   [NetLabel]: rewor...
687
  	genlmsg_end(ans_skb, data);
fe785bee0   Denis V. Lunev   netlabel: netlink...
688
  	return genlmsg_reply(ans_skb, info);
d15c345fe   Paul Moore   [NetLabel]: core ...
689
690
691
  
  version_failure:
  	kfree_skb(ans_skb);
d15c345fe   Paul Moore   [NetLabel]: core ...
692
693
694
695
696
697
698
  	return ret_val;
  }
  
  
  /*
   * NetLabel Generic NETLINK Command Definitions
   */
227c43c3b   Pavel Emelyanov   [NETLABEL]: Shrin...
699
700
  static struct genl_ops netlbl_mgmt_genl_ops[] = {
  	{
d15c345fe   Paul Moore   [NetLabel]: core ...
701
  	.cmd = NLBL_MGMT_C_ADD,
fd3858554   Paul Moore   [NetLabel]: rewor...
702
703
  	.flags = GENL_ADMIN_PERM,
  	.policy = netlbl_mgmt_genl_policy,
d15c345fe   Paul Moore   [NetLabel]: core ...
704
705
  	.doit = netlbl_mgmt_add,
  	.dumpit = NULL,
227c43c3b   Pavel Emelyanov   [NETLABEL]: Shrin...
706
707
  	},
  	{
d15c345fe   Paul Moore   [NetLabel]: core ...
708
  	.cmd = NLBL_MGMT_C_REMOVE,
fd3858554   Paul Moore   [NetLabel]: rewor...
709
710
  	.flags = GENL_ADMIN_PERM,
  	.policy = netlbl_mgmt_genl_policy,
d15c345fe   Paul Moore   [NetLabel]: core ...
711
712
  	.doit = netlbl_mgmt_remove,
  	.dumpit = NULL,
227c43c3b   Pavel Emelyanov   [NETLABEL]: Shrin...
713
714
  	},
  	{
fd3858554   Paul Moore   [NetLabel]: rewor...
715
  	.cmd = NLBL_MGMT_C_LISTALL,
d15c345fe   Paul Moore   [NetLabel]: core ...
716
  	.flags = 0,
fd3858554   Paul Moore   [NetLabel]: rewor...
717
718
719
  	.policy = netlbl_mgmt_genl_policy,
  	.doit = NULL,
  	.dumpit = netlbl_mgmt_listall,
227c43c3b   Pavel Emelyanov   [NETLABEL]: Shrin...
720
721
  	},
  	{
d15c345fe   Paul Moore   [NetLabel]: core ...
722
  	.cmd = NLBL_MGMT_C_ADDDEF,
fd3858554   Paul Moore   [NetLabel]: rewor...
723
724
  	.flags = GENL_ADMIN_PERM,
  	.policy = netlbl_mgmt_genl_policy,
d15c345fe   Paul Moore   [NetLabel]: core ...
725
726
  	.doit = netlbl_mgmt_adddef,
  	.dumpit = NULL,
227c43c3b   Pavel Emelyanov   [NETLABEL]: Shrin...
727
728
  	},
  	{
d15c345fe   Paul Moore   [NetLabel]: core ...
729
  	.cmd = NLBL_MGMT_C_REMOVEDEF,
fd3858554   Paul Moore   [NetLabel]: rewor...
730
731
  	.flags = GENL_ADMIN_PERM,
  	.policy = netlbl_mgmt_genl_policy,
d15c345fe   Paul Moore   [NetLabel]: core ...
732
733
  	.doit = netlbl_mgmt_removedef,
  	.dumpit = NULL,
227c43c3b   Pavel Emelyanov   [NETLABEL]: Shrin...
734
735
  	},
  	{
d15c345fe   Paul Moore   [NetLabel]: core ...
736
737
  	.cmd = NLBL_MGMT_C_LISTDEF,
  	.flags = 0,
fd3858554   Paul Moore   [NetLabel]: rewor...
738
  	.policy = netlbl_mgmt_genl_policy,
d15c345fe   Paul Moore   [NetLabel]: core ...
739
740
  	.doit = netlbl_mgmt_listdef,
  	.dumpit = NULL,
227c43c3b   Pavel Emelyanov   [NETLABEL]: Shrin...
741
742
  	},
  	{
fd3858554   Paul Moore   [NetLabel]: rewor...
743
  	.cmd = NLBL_MGMT_C_PROTOCOLS,
d15c345fe   Paul Moore   [NetLabel]: core ...
744
  	.flags = 0,
fd3858554   Paul Moore   [NetLabel]: rewor...
745
746
747
  	.policy = netlbl_mgmt_genl_policy,
  	.doit = NULL,
  	.dumpit = netlbl_mgmt_protocols,
227c43c3b   Pavel Emelyanov   [NETLABEL]: Shrin...
748
749
  	},
  	{
d15c345fe   Paul Moore   [NetLabel]: core ...
750
751
  	.cmd = NLBL_MGMT_C_VERSION,
  	.flags = 0,
fd3858554   Paul Moore   [NetLabel]: rewor...
752
  	.policy = netlbl_mgmt_genl_policy,
d15c345fe   Paul Moore   [NetLabel]: core ...
753
754
  	.doit = netlbl_mgmt_version,
  	.dumpit = NULL,
227c43c3b   Pavel Emelyanov   [NETLABEL]: Shrin...
755
  	},
d15c345fe   Paul Moore   [NetLabel]: core ...
756
757
758
759
760
761
762
763
764
765
766
767
768
769
  };
  
  /*
   * NetLabel Generic NETLINK Protocol Functions
   */
  
  /**
   * netlbl_mgmt_genl_init - Register the NetLabel management component
   *
   * Description:
   * Register the NetLabel management component with the Generic NETLINK
   * mechanism.  Returns zero on success, negative values on failure.
   *
   */
05705e4e1   Pavel Emelyanov   [NETLABEL]: Move ...
770
  int __init netlbl_mgmt_genl_init(void)
d15c345fe   Paul Moore   [NetLabel]: core ...
771
  {
7ae740df3   Michał Mirosław   netlabel: Use gen...
772
773
  	return genl_register_family_with_ops(&netlbl_mgmt_gnl_family,
  		netlbl_mgmt_genl_ops, ARRAY_SIZE(netlbl_mgmt_genl_ops));
d15c345fe   Paul Moore   [NetLabel]: core ...
774
  }