aboutsummaryrefslogtreecommitdiffstats
path: root/net/netlabel/netlabel_mgmt.c
diff options
context:
space:
mode:
authorPaul Moore <paul.moore@hp.com>2008-10-10 10:16:32 -0400
committerPaul Moore <paul.moore@hp.com>2008-10-10 10:16:32 -0400
commit63c41688743760631188cf0f4ae986a6793ccb0a (patch)
treeb270091d7b763e8b6c5073d4ca618f0d36065188 /net/netlabel/netlabel_mgmt.c
parent61e1068219950c672ce979719ad2be3aadb00d7d (diff)
netlabel: Add network address selectors to the NetLabel/LSM domain mapping
This patch extends the NetLabel traffic labeling capabilities to individual packets based not only on the LSM domain but the by the destination address as well. The changes here only affect the core NetLabel infrastructre, changes to the NetLabel KAPI and individial protocol engines are also required but are split out into a different patch to ease review. Signed-off-by: Paul Moore <paul.moore@hp.com> Reviewed-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'net/netlabel/netlabel_mgmt.c')
-rw-r--r--net/netlabel/netlabel_mgmt.c398
1 files changed, 304 insertions, 94 deletions
diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c
index c4e18c7bc0c1..ee769ecaa13c 100644
--- a/net/netlabel/netlabel_mgmt.c
+++ b/net/netlabel/netlabel_mgmt.c
@@ -10,7 +10,7 @@
10 */ 10 */
11 11
12/* 12/*
13 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 13 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
14 * 14 *
15 * This program is free software; you can redistribute it and/or modify 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 16 * it under the terms of the GNU General Public License as published by
@@ -32,9 +32,13 @@
32#include <linux/socket.h> 32#include <linux/socket.h>
33#include <linux/string.h> 33#include <linux/string.h>
34#include <linux/skbuff.h> 34#include <linux/skbuff.h>
35#include <linux/in.h>
36#include <linux/in6.h>
35#include <net/sock.h> 37#include <net/sock.h>
36#include <net/netlink.h> 38#include <net/netlink.h>
37#include <net/genetlink.h> 39#include <net/genetlink.h>
40#include <net/ip.h>
41#include <net/ipv6.h>
38#include <net/netlabel.h> 42#include <net/netlabel.h>
39#include <net/cipso_ipv4.h> 43#include <net/cipso_ipv4.h>
40#include <asm/atomic.h> 44#include <asm/atomic.h>
@@ -71,80 +75,337 @@ static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
71}; 75};
72 76
73/* 77/*
74 * NetLabel Command Handlers 78 * Helper Functions
75 */ 79 */
76 80
77/** 81/**
78 * netlbl_mgmt_add - Handle an ADD message 82 * netlbl_mgmt_add - Handle an ADD message
79 * @skb: the NETLINK buffer
80 * @info: the Generic NETLINK info block 83 * @info: the Generic NETLINK info block
84 * @audit_info: NetLabel audit information
81 * 85 *
82 * Description: 86 * Description:
83 * Process a user generated ADD message and add the domains from the message 87 * Helper function for the ADD and ADDDEF messages to add the domain mappings
84 * to the hash table. See netlabel.h for a description of the message format. 88 * from the message to the hash table. See netlabel.h for a description of the
85 * Returns zero on success, negative values on failure. 89 * message format. Returns zero on success, negative values on failure.
86 * 90 *
87 */ 91 */
88static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) 92static int netlbl_mgmt_add_common(struct genl_info *info,
93 struct netlbl_audit *audit_info)
89{ 94{
90 int ret_val = -EINVAL; 95 int ret_val = -EINVAL;
91 struct netlbl_dom_map *entry = NULL; 96 struct netlbl_dom_map *entry = NULL;
92 size_t tmp_size; 97 struct netlbl_domaddr_map *addrmap = NULL;
98 struct cipso_v4_doi *cipsov4 = NULL;
93 u32 tmp_val; 99 u32 tmp_val;
94 struct netlbl_audit audit_info;
95
96 if (!info->attrs[NLBL_MGMT_A_DOMAIN] ||
97 !info->attrs[NLBL_MGMT_A_PROTOCOL])
98 goto add_failure;
99
100 netlbl_netlink_auditinfo(skb, &audit_info);
101 100
102 entry = kzalloc(sizeof(*entry), GFP_KERNEL); 101 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
103 if (entry == NULL) { 102 if (entry == NULL) {
104 ret_val = -ENOMEM; 103 ret_val = -ENOMEM;
105 goto add_failure; 104 goto add_failure;
106 } 105 }
107 tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
108 entry->domain = kmalloc(tmp_size, GFP_KERNEL);
109 if (entry->domain == NULL) {
110 ret_val = -ENOMEM;
111 goto add_failure;
112 }
113 entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); 106 entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
114 nla_strlcpy(entry->domain, info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size); 107 if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
108 size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
109 entry->domain = kmalloc(tmp_size, GFP_KERNEL);
110 if (entry->domain == NULL) {
111 ret_val = -ENOMEM;
112 goto add_failure;
113 }
114 nla_strlcpy(entry->domain,
115 info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
116 }
117
118 /* NOTE: internally we allow/use a entry->type value of
119 * NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
120 * to pass that as a protocol value because we need to know the
121 * "real" protocol */
115 122
116 switch (entry->type) { 123 switch (entry->type) {
117 case NETLBL_NLTYPE_UNLABELED: 124 case NETLBL_NLTYPE_UNLABELED:
118 ret_val = netlbl_domhsh_add(entry, &audit_info);
119 break; 125 break;
120 case NETLBL_NLTYPE_CIPSOV4: 126 case NETLBL_NLTYPE_CIPSOV4:
121 if (!info->attrs[NLBL_MGMT_A_CV4DOI]) 127 if (!info->attrs[NLBL_MGMT_A_CV4DOI])
122 goto add_failure; 128 goto add_failure;
123 129
124 tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]); 130 tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
125 entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val); 131 cipsov4 = cipso_v4_doi_getdef(tmp_val);
126 if (entry->type_def.cipsov4 == NULL) 132 if (cipsov4 == NULL)
127 goto add_failure; 133 goto add_failure;
128 ret_val = netlbl_domhsh_add(entry, &audit_info); 134 entry->type_def.cipsov4 = cipsov4;
129 if (ret_val != 0)
130 cipso_v4_doi_putdef(entry->type_def.cipsov4);
131 break; 135 break;
132 default: 136 default:
133 goto add_failure; 137 goto add_failure;
134 } 138 }
139
140 if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
141 struct in_addr *addr;
142 struct in_addr *mask;
143 struct netlbl_domaddr4_map *map;
144
145 addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
146 if (addrmap == NULL) {
147 ret_val = -ENOMEM;
148 goto add_failure;
149 }
150 INIT_LIST_HEAD(&addrmap->list4);
151 INIT_LIST_HEAD(&addrmap->list6);
152
153 if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) !=
154 sizeof(struct in_addr)) {
155 ret_val = -EINVAL;
156 goto add_failure;
157 }
158 if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) !=
159 sizeof(struct in_addr)) {
160 ret_val = -EINVAL;
161 goto add_failure;
162 }
163 addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]);
164 mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]);
165
166 map = kzalloc(sizeof(*map), GFP_KERNEL);
167 if (map == NULL) {
168 ret_val = -ENOMEM;
169 goto add_failure;
170 }
171 map->list.addr = addr->s_addr & mask->s_addr;
172 map->list.mask = mask->s_addr;
173 map->list.valid = 1;
174 map->type = entry->type;
175 if (cipsov4)
176 map->type_def.cipsov4 = cipsov4;
177
178 ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
179 if (ret_val != 0) {
180 kfree(map);
181 goto add_failure;
182 }
183
184 entry->type = NETLBL_NLTYPE_ADDRSELECT;
185 entry->type_def.addrsel = addrmap;
186#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
187 } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) {
188 struct in6_addr *addr;
189 struct in6_addr *mask;
190 struct netlbl_domaddr6_map *map;
191
192 addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
193 if (addrmap == NULL) {
194 ret_val = -ENOMEM;
195 goto add_failure;
196 }
197 INIT_LIST_HEAD(&addrmap->list4);
198 INIT_LIST_HEAD(&addrmap->list6);
199
200 if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) !=
201 sizeof(struct in6_addr)) {
202 ret_val = -EINVAL;
203 goto add_failure;
204 }
205 if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) !=
206 sizeof(struct in6_addr)) {
207 ret_val = -EINVAL;
208 goto add_failure;
209 }
210 addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]);
211 mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]);
212
213 map = kzalloc(sizeof(*map), GFP_KERNEL);
214 if (map == NULL) {
215 ret_val = -ENOMEM;
216 goto add_failure;
217 }
218 ipv6_addr_copy(&map->list.addr, addr);
219 map->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
220 map->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
221 map->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
222 map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
223 ipv6_addr_copy(&map->list.mask, mask);
224 map->list.valid = 1;
225 map->type = entry->type;
226
227 ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
228 if (ret_val != 0) {
229 kfree(map);
230 goto add_failure;
231 }
232
233 entry->type = NETLBL_NLTYPE_ADDRSELECT;
234 entry->type_def.addrsel = addrmap;
235#endif /* IPv6 */
236 }
237
238 ret_val = netlbl_domhsh_add(entry, audit_info);
135 if (ret_val != 0) 239 if (ret_val != 0)
136 goto add_failure; 240 goto add_failure;
137 241
138 return 0; 242 return 0;
139 243
140add_failure: 244add_failure:
245 if (cipsov4)
246 cipso_v4_doi_putdef(cipsov4);
141 if (entry) 247 if (entry)
142 kfree(entry->domain); 248 kfree(entry->domain);
249 kfree(addrmap);
143 kfree(entry); 250 kfree(entry);
144 return ret_val; 251 return ret_val;
145} 252}
146 253
147/** 254/**
255 * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry
256 * @skb: the NETLINK buffer
257 * @entry: the map entry
258 *
259 * Description:
260 * This function is a helper function used by the LISTALL and LISTDEF command
261 * handlers. The caller is responsibile for ensuring that the RCU read lock
262 * is held. Returns zero on success, negative values on failure.
263 *
264 */
265static int netlbl_mgmt_listentry(struct sk_buff *skb,
266 struct netlbl_dom_map *entry)
267{
268 int ret_val;
269 struct nlattr *nla_a;
270 struct nlattr *nla_b;
271 struct netlbl_af4list *iter4;
272#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
273 struct netlbl_af6list *iter6;
274#endif
275
276 if (entry->domain != NULL) {
277 ret_val = nla_put_string(skb,
278 NLBL_MGMT_A_DOMAIN, entry->domain);
279 if (ret_val != 0)
280 return ret_val;
281 }
282
283 switch (entry->type) {
284 case NETLBL_NLTYPE_ADDRSELECT:
285 nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST);
286 if (nla_a == NULL)
287 return -ENOMEM;
288
289 netlbl_af4list_foreach_rcu(iter4,
290 &entry->type_def.addrsel->list4) {
291 struct netlbl_domaddr4_map *map4;
292 struct in_addr addr_struct;
293
294 nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR);
295 if (nla_b == NULL)
296 return -ENOMEM;
297
298 addr_struct.s_addr = iter4->addr;
299 ret_val = nla_put(skb, NLBL_MGMT_A_IPV4ADDR,
300 sizeof(struct in_addr),
301 &addr_struct);
302 if (ret_val != 0)
303 return ret_val;
304 addr_struct.s_addr = iter4->mask;
305 ret_val = nla_put(skb, NLBL_MGMT_A_IPV4MASK,
306 sizeof(struct in_addr),
307 &addr_struct);
308 if (ret_val != 0)
309 return ret_val;
310 map4 = netlbl_domhsh_addr4_entry(iter4);
311 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
312 map4->type);
313 if (ret_val != 0)
314 return ret_val;
315 switch (map4->type) {
316 case NETLBL_NLTYPE_CIPSOV4:
317 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
318 map4->type_def.cipsov4->doi);
319 if (ret_val != 0)
320 return ret_val;
321 break;
322 }
323
324 nla_nest_end(skb, nla_b);
325 }
326#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
327 netlbl_af6list_foreach_rcu(iter6,
328 &entry->type_def.addrsel->list6) {
329 struct netlbl_domaddr6_map *map6;
330
331 nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR);
332 if (nla_b == NULL)
333 return -ENOMEM;
334
335 ret_val = nla_put(skb, NLBL_MGMT_A_IPV6ADDR,
336 sizeof(struct in6_addr),
337 &iter6->addr);
338 if (ret_val != 0)
339 return ret_val;
340 ret_val = nla_put(skb, NLBL_MGMT_A_IPV6MASK,
341 sizeof(struct in6_addr),
342 &iter6->mask);
343 if (ret_val != 0)
344 return ret_val;
345 map6 = netlbl_domhsh_addr6_entry(iter6);
346 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
347 map6->type);
348 if (ret_val != 0)
349 return ret_val;
350
351 nla_nest_end(skb, nla_b);
352 }
353#endif /* IPv6 */
354
355 nla_nest_end(skb, nla_a);
356 break;
357 case NETLBL_NLTYPE_UNLABELED:
358 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type);
359 break;
360 case NETLBL_NLTYPE_CIPSOV4:
361 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type);
362 if (ret_val != 0)
363 return ret_val;
364 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
365 entry->type_def.cipsov4->doi);
366 break;
367 }
368
369 return ret_val;
370}
371
372/*
373 * NetLabel Command Handlers
374 */
375
376/**
377 * netlbl_mgmt_add - Handle an ADD message
378 * @skb: the NETLINK buffer
379 * @info: the Generic NETLINK info block
380 *
381 * Description:
382 * Process a user generated ADD message and add the domains from the message
383 * to the hash table. See netlabel.h for a description of the message format.
384 * Returns zero on success, negative values on failure.
385 *
386 */
387static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
388{
389 struct netlbl_audit audit_info;
390
391 if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) ||
392 (!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
393 (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
394 info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
395 (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
396 info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
397 ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
398 (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
399 ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
400 (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
401 return -EINVAL;
402
403 netlbl_netlink_auditinfo(skb, &audit_info);
404
405 return netlbl_mgmt_add_common(info, &audit_info);
406}
407
408/**
148 * netlbl_mgmt_remove - Handle a REMOVE message 409 * netlbl_mgmt_remove - Handle a REMOVE message
149 * @skb: the NETLINK buffer 410 * @skb: the NETLINK buffer
150 * @info: the Generic NETLINK info block 411 * @info: the Generic NETLINK info block
@@ -192,23 +453,9 @@ static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
192 if (data == NULL) 453 if (data == NULL)
193 goto listall_cb_failure; 454 goto listall_cb_failure;
194 455
195 ret_val = nla_put_string(cb_arg->skb, 456 ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry);
196 NLBL_MGMT_A_DOMAIN,
197 entry->domain);
198 if (ret_val != 0) 457 if (ret_val != 0)
199 goto listall_cb_failure; 458 goto listall_cb_failure;
200 ret_val = nla_put_u32(cb_arg->skb, NLBL_MGMT_A_PROTOCOL, entry->type);
201 if (ret_val != 0)
202 goto listall_cb_failure;
203 switch (entry->type) {
204 case NETLBL_NLTYPE_CIPSOV4:
205 ret_val = nla_put_u32(cb_arg->skb,
206 NLBL_MGMT_A_CV4DOI,
207 entry->type_def.cipsov4->doi);
208 if (ret_val != 0)
209 goto listall_cb_failure;
210 break;
211 }
212 459
213 cb_arg->seq++; 460 cb_arg->seq++;
214 return genlmsg_end(cb_arg->skb, data); 461 return genlmsg_end(cb_arg->skb, data);
@@ -262,50 +509,22 @@ static int netlbl_mgmt_listall(struct sk_buff *skb,
262 */ 509 */
263static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) 510static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
264{ 511{
265 int ret_val = -EINVAL;
266 struct netlbl_dom_map *entry = NULL;
267 u32 tmp_val;
268 struct netlbl_audit audit_info; 512 struct netlbl_audit audit_info;
269 513
270 if (!info->attrs[NLBL_MGMT_A_PROTOCOL]) 514 if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
271 goto adddef_failure; 515 (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
516 info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
517 (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
518 info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
519 ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
520 (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
521 ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
522 (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
523 return -EINVAL;
272 524
273 netlbl_netlink_auditinfo(skb, &audit_info); 525 netlbl_netlink_auditinfo(skb, &audit_info);
274 526
275 entry = kzalloc(sizeof(*entry), GFP_KERNEL); 527 return netlbl_mgmt_add_common(info, &audit_info);
276 if (entry == NULL) {
277 ret_val = -ENOMEM;
278 goto adddef_failure;
279 }
280 entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
281
282 switch (entry->type) {
283 case NETLBL_NLTYPE_UNLABELED:
284 ret_val = netlbl_domhsh_add_default(entry, &audit_info);
285 break;
286 case NETLBL_NLTYPE_CIPSOV4:
287 if (!info->attrs[NLBL_MGMT_A_CV4DOI])
288 goto adddef_failure;
289
290 tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
291 entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
292 if (entry->type_def.cipsov4 == NULL)
293 goto adddef_failure;
294 ret_val = netlbl_domhsh_add_default(entry, &audit_info);
295 if (ret_val != 0)
296 cipso_v4_doi_putdef(entry->type_def.cipsov4);
297 break;
298 default:
299 goto adddef_failure;
300 }
301 if (ret_val != 0)
302 goto adddef_failure;
303
304 return 0;
305
306adddef_failure:
307 kfree(entry);
308 return ret_val;
309} 528}
310 529
311/** 530/**
@@ -359,19 +578,10 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
359 ret_val = -ENOENT; 578 ret_val = -ENOENT;
360 goto listdef_failure_lock; 579 goto listdef_failure_lock;
361 } 580 }
362 ret_val = nla_put_u32(ans_skb, NLBL_MGMT_A_PROTOCOL, entry->type); 581 ret_val = netlbl_mgmt_listentry(ans_skb, entry);
363 if (ret_val != 0)
364 goto listdef_failure_lock;
365 switch (entry->type) {
366 case NETLBL_NLTYPE_CIPSOV4:
367 ret_val = nla_put_u32(ans_skb,
368 NLBL_MGMT_A_CV4DOI,
369 entry->type_def.cipsov4->doi);
370 if (ret_val != 0)
371 goto listdef_failure_lock;
372 break;
373 }
374 rcu_read_unlock(); 582 rcu_read_unlock();
583 if (ret_val != 0)
584 goto listdef_failure;
375 585
376 genlmsg_end(ans_skb, data); 586 genlmsg_end(ans_skb, data);
377 return genlmsg_reply(ans_skb, info); 587 return genlmsg_reply(ans_skb, info);