aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/netlabel/netlabel_kapi.c16
-rw-r--r--net/netlabel/netlabel_unlabeled.c1375
-rw-r--r--net/netlabel/netlabel_unlabeled.h145
3 files changed, 1519 insertions, 17 deletions
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c
index 49146153f235..c69e3e1f05c3 100644
--- a/net/netlabel/netlabel_kapi.c
+++ b/net/netlabel/netlabel_kapi.c
@@ -312,7 +312,7 @@ socket_setattr_return:
312 * @secattr: the security attributes 312 * @secattr: the security attributes
313 * 313 *
314 * Description: 314 * Description:
315 * Examines the given sock to see any NetLabel style labeling has been 315 * Examines the given sock to see if any NetLabel style labeling has been
316 * applied to the sock, if so it parses the socket label and returns the 316 * applied to the sock, if so it parses the socket label and returns the
317 * security attributes in @secattr. Returns zero on success, negative values 317 * security attributes in @secattr. Returns zero on success, negative values
318 * on failure. 318 * on failure.
@@ -320,13 +320,7 @@ socket_setattr_return:
320 */ 320 */
321int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) 321int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
322{ 322{
323 int ret_val; 323 return cipso_v4_sock_getattr(sk, secattr);
324
325 ret_val = cipso_v4_sock_getattr(sk, secattr);
326 if (ret_val == 0)
327 return 0;
328
329 return netlbl_unlabel_getattr(secattr);
330} 324}
331 325
332/** 326/**
@@ -350,7 +344,7 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
350 cipso_v4_skbuff_getattr(skb, secattr) == 0) 344 cipso_v4_skbuff_getattr(skb, secattr) == 0)
351 return 0; 345 return 0;
352 346
353 return netlbl_unlabel_getattr(secattr); 347 return netlbl_unlabel_getattr(skb, family, secattr);
354} 348}
355 349
356/** 350/**
@@ -434,6 +428,10 @@ static int __init netlbl_init(void)
434 if (ret_val != 0) 428 if (ret_val != 0)
435 goto init_failure; 429 goto init_failure;
436 430
431 ret_val = netlbl_unlabel_init(NETLBL_UNLHSH_BITSIZE);
432 if (ret_val != 0)
433 goto init_failure;
434
437 ret_val = netlbl_netlink_init(); 435 ret_val = netlbl_netlink_init();
438 if (ret_val != 0) 436 if (ret_val != 0)
439 goto init_failure; 437 goto init_failure;
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index 7f5df0cbc63f..d0c628c875ae 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.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 - 2007
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
@@ -29,27 +29,99 @@
29 */ 29 */
30 30
31#include <linux/types.h> 31#include <linux/types.h>
32#include <linux/rcupdate.h>
32#include <linux/list.h> 33#include <linux/list.h>
33#include <linux/spinlock.h> 34#include <linux/spinlock.h>
34#include <linux/socket.h> 35#include <linux/socket.h>
35#include <linux/string.h> 36#include <linux/string.h>
36#include <linux/skbuff.h> 37#include <linux/skbuff.h>
37#include <linux/audit.h> 38#include <linux/audit.h>
39#include <linux/in.h>
40#include <linux/in6.h>
41#include <linux/ip.h>
42#include <linux/ipv6.h>
43#include <linux/notifier.h>
44#include <linux/netdevice.h>
45#include <linux/security.h>
38#include <net/sock.h> 46#include <net/sock.h>
39#include <net/netlink.h> 47#include <net/netlink.h>
40#include <net/genetlink.h> 48#include <net/genetlink.h>
41 49#include <net/ip.h>
50#include <net/ipv6.h>
51#include <net/net_namespace.h>
42#include <net/netlabel.h> 52#include <net/netlabel.h>
43#include <asm/bug.h> 53#include <asm/bug.h>
54#include <asm/atomic.h>
44 55
45#include "netlabel_user.h" 56#include "netlabel_user.h"
46#include "netlabel_domainhash.h" 57#include "netlabel_domainhash.h"
47#include "netlabel_unlabeled.h" 58#include "netlabel_unlabeled.h"
59#include "netlabel_mgmt.h"
60
61/* NOTE: at present we always use init's network namespace since we don't
62 * presently support different namespaces even though the majority of
63 * the functions in this file are "namespace safe" */
64
65/* The unlabeled connection hash table which we use to map network interfaces
66 * and addresses of unlabeled packets to a user specified secid value for the
67 * LSM. The hash table is used to lookup the network interface entry
68 * (struct netlbl_unlhsh_iface) and then the interface entry is used to
69 * lookup an IP address match from an ordered list. If a network interface
70 * match can not be found in the hash table then the default entry
71 * (netlbl_unlhsh_def) is used. The IP address entry list
72 * (struct netlbl_unlhsh_addr) is ordered such that the entries with a
73 * larger netmask come first.
74 */
75struct netlbl_unlhsh_tbl {
76 struct list_head *tbl;
77 u32 size;
78};
79struct netlbl_unlhsh_addr4 {
80 __be32 addr;
81 __be32 mask;
82 u32 secid;
83
84 u32 valid;
85 struct list_head list;
86 struct rcu_head rcu;
87};
88struct netlbl_unlhsh_addr6 {
89 struct in6_addr addr;
90 struct in6_addr mask;
91 u32 secid;
92
93 u32 valid;
94 struct list_head list;
95 struct rcu_head rcu;
96};
97struct netlbl_unlhsh_iface {
98 int ifindex;
99 struct list_head addr4_list;
100 struct list_head addr6_list;
101
102 u32 valid;
103 struct list_head list;
104 struct rcu_head rcu;
105};
106
107/* Argument struct for netlbl_unlhsh_walk() */
108struct netlbl_unlhsh_walk_arg {
109 struct netlink_callback *nl_cb;
110 struct sk_buff *skb;
111 u32 seq;
112};
113
114/* Unlabeled connection hash table */
115/* updates should be so rare that having one spinlock for the entire
116 * hash table should be okay */
117static DEFINE_SPINLOCK(netlbl_unlhsh_lock);
118static struct netlbl_unlhsh_tbl *netlbl_unlhsh = NULL;
119static struct netlbl_unlhsh_iface *netlbl_unlhsh_def = NULL;
48 120
49/* Accept unlabeled packets flag */ 121/* Accept unlabeled packets flag */
50static u8 netlabel_unlabel_acceptflg = 0; 122static u8 netlabel_unlabel_acceptflg = 0;
51 123
52/* NetLabel Generic NETLINK CIPSOv4 family */ 124/* NetLabel Generic NETLINK unlabeled family */
53static struct genl_family netlbl_unlabel_gnl_family = { 125static struct genl_family netlbl_unlabel_gnl_family = {
54 .id = GENL_ID_GENERATE, 126 .id = GENL_ID_GENERATE,
55 .hdrsize = 0, 127 .hdrsize = 0,
@@ -61,11 +133,681 @@ static struct genl_family netlbl_unlabel_gnl_family = {
61/* NetLabel Netlink attribute policy */ 133/* NetLabel Netlink attribute policy */
62static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = { 134static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = {
63 [NLBL_UNLABEL_A_ACPTFLG] = { .type = NLA_U8 }, 135 [NLBL_UNLABEL_A_ACPTFLG] = { .type = NLA_U8 },
136 [NLBL_UNLABEL_A_IPV6ADDR] = { .type = NLA_BINARY,
137 .len = sizeof(struct in6_addr) },
138 [NLBL_UNLABEL_A_IPV6MASK] = { .type = NLA_BINARY,
139 .len = sizeof(struct in6_addr) },
140 [NLBL_UNLABEL_A_IPV4ADDR] = { .type = NLA_BINARY,
141 .len = sizeof(struct in_addr) },
142 [NLBL_UNLABEL_A_IPV4MASK] = { .type = NLA_BINARY,
143 .len = sizeof(struct in_addr) },
144 [NLBL_UNLABEL_A_IFACE] = { .type = NLA_NUL_STRING,
145 .len = IFNAMSIZ - 1 },
146 [NLBL_UNLABEL_A_SECCTX] = { .type = NLA_BINARY }
64}; 147};
65 148
66/* 149/*
67 * Helper Functions 150 * Unlabeled Connection Hash Table Functions
151 */
152
153/**
154 * netlbl_unlhsh_free_addr4 - Frees an IPv4 address entry from the hash table
155 * @entry: the entry's RCU field
156 *
157 * Description:
158 * This function is designed to be used as a callback to the call_rcu()
159 * function so that memory allocated to a hash table address entry can be
160 * released safely.
161 *
162 */
163static void netlbl_unlhsh_free_addr4(struct rcu_head *entry)
164{
165 struct netlbl_unlhsh_addr4 *ptr;
166
167 ptr = container_of(entry, struct netlbl_unlhsh_addr4, rcu);
168 kfree(ptr);
169}
170
171#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
172/**
173 * netlbl_unlhsh_free_addr6 - Frees an IPv6 address entry from the hash table
174 * @entry: the entry's RCU field
175 *
176 * Description:
177 * This function is designed to be used as a callback to the call_rcu()
178 * function so that memory allocated to a hash table address entry can be
179 * released safely.
180 *
181 */
182static void netlbl_unlhsh_free_addr6(struct rcu_head *entry)
183{
184 struct netlbl_unlhsh_addr6 *ptr;
185
186 ptr = container_of(entry, struct netlbl_unlhsh_addr6, rcu);
187 kfree(ptr);
188}
189#endif /* IPv6 */
190
191/**
192 * netlbl_unlhsh_free_iface - Frees an interface entry from the hash table
193 * @entry: the entry's RCU field
194 *
195 * Description:
196 * This function is designed to be used as a callback to the call_rcu()
197 * function so that memory allocated to a hash table interface entry can be
198 * released safely. It is important to note that this function does not free
199 * the IPv4 and IPv6 address lists contained as part of an interface entry. It
200 * is up to the rest of the code to make sure an interface entry is only freed
201 * once it's address lists are empty.
202 *
203 */
204static void netlbl_unlhsh_free_iface(struct rcu_head *entry)
205{
206 struct netlbl_unlhsh_iface *iface;
207 struct netlbl_unlhsh_addr4 *iter4;
208 struct netlbl_unlhsh_addr4 *tmp4;
209 struct netlbl_unlhsh_addr6 *iter6;
210 struct netlbl_unlhsh_addr6 *tmp6;
211
212 iface = container_of(entry, struct netlbl_unlhsh_iface, rcu);
213
214 /* no need for locks here since we are the only one with access to this
215 * structure */
216
217 list_for_each_entry_safe(iter4, tmp4, &iface->addr4_list, list)
218 if (iter4->valid) {
219 list_del_rcu(&iter4->list);
220 kfree(iter4);
221 }
222 list_for_each_entry_safe(iter6, tmp6, &iface->addr6_list, list)
223 if (iter6->valid) {
224 list_del_rcu(&iter6->list);
225 kfree(iter6);
226 }
227 kfree(iface);
228}
229
230/**
231 * netlbl_unlhsh_hash - Hashing function for the hash table
232 * @ifindex: the network interface/device to hash
233 *
234 * Description:
235 * This is the hashing function for the unlabeled hash table, it returns the
236 * bucket number for the given device/interface. The caller is responsible for
237 * calling the rcu_read_[un]lock() functions.
238 *
239 */
240static u32 netlbl_unlhsh_hash(int ifindex)
241{
242 /* this is taken _almost_ directly from
243 * security/selinux/netif.c:sel_netif_hasfn() as they do pretty much
244 * the same thing */
245 return ifindex & (rcu_dereference(netlbl_unlhsh)->size - 1);
246}
247
248/**
249 * netlbl_unlhsh_search_addr4 - Search for a matching IPv4 address entry
250 * @addr: IPv4 address
251 * @iface: the network interface entry
252 *
253 * Description:
254 * Searches the IPv4 address list of the network interface specified by @iface.
255 * If a matching address entry is found it is returned, otherwise NULL is
256 * returned. The caller is responsible for calling the rcu_read_[un]lock()
257 * functions.
258 *
259 */
260static struct netlbl_unlhsh_addr4 *netlbl_unlhsh_search_addr4(
261 __be32 addr,
262 const struct netlbl_unlhsh_iface *iface)
263{
264 struct netlbl_unlhsh_addr4 *iter;
265
266 list_for_each_entry_rcu(iter, &iface->addr4_list, list)
267 if (iter->valid && (addr & iter->mask) == iter->addr)
268 return iter;
269
270 return NULL;
271}
272
273#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
274/**
275 * netlbl_unlhsh_search_addr6 - Search for a matching IPv6 address entry
276 * @addr: IPv6 address
277 * @iface: the network interface entry
278 *
279 * Description:
280 * Searches the IPv6 address list of the network interface specified by @iface.
281 * If a matching address entry is found it is returned, otherwise NULL is
282 * returned. The caller is responsible for calling the rcu_read_[un]lock()
283 * functions.
284 *
285 */
286static struct netlbl_unlhsh_addr6 *netlbl_unlhsh_search_addr6(
287 const struct in6_addr *addr,
288 const struct netlbl_unlhsh_iface *iface)
289{
290 struct netlbl_unlhsh_addr6 *iter;
291
292 list_for_each_entry_rcu(iter, &iface->addr6_list, list)
293 if (iter->valid &&
294 ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0)
295 return iter;
296
297 return NULL;
298}
299#endif /* IPv6 */
300
301/**
302 * netlbl_unlhsh_search_iface - Search for a matching interface entry
303 * @ifindex: the network interface
304 *
305 * Description:
306 * Searches the unlabeled connection hash table and returns a pointer to the
307 * interface entry which matches @ifindex, otherwise NULL is returned. The
308 * caller is responsible for calling the rcu_read_[un]lock() functions.
309 *
310 */
311static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex)
312{
313 u32 bkt;
314 struct netlbl_unlhsh_iface *iter;
315
316 bkt = netlbl_unlhsh_hash(ifindex);
317 list_for_each_entry_rcu(iter,
318 &rcu_dereference(netlbl_unlhsh)->tbl[bkt],
319 list)
320 if (iter->valid && iter->ifindex == ifindex)
321 return iter;
322
323 return NULL;
324}
325
326/**
327 * netlbl_unlhsh_search_iface_def - Search for a matching interface entry
328 * @ifindex: the network interface
329 *
330 * Description:
331 * Searches the unlabeled connection hash table and returns a pointer to the
332 * interface entry which matches @ifindex. If an exact match can not be found
333 * and there is a valid default entry, the default entry is returned, otherwise
334 * NULL is returned. The caller is responsible for calling the
335 * rcu_read_[un]lock() functions.
336 *
337 */
338static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface_def(int ifindex)
339{
340 struct netlbl_unlhsh_iface *entry;
341
342 entry = netlbl_unlhsh_search_iface(ifindex);
343 if (entry != NULL)
344 return entry;
345
346 entry = rcu_dereference(netlbl_unlhsh_def);
347 if (entry != NULL && entry->valid)
348 return entry;
349
350 return NULL;
351}
352
353/**
354 * netlbl_unlhsh_add_addr4 - Add a new IPv4 address entry to the hash table
355 * @iface: the associated interface entry
356 * @addr: IPv4 address in network byte order
357 * @mask: IPv4 address mask in network byte order
358 * @secid: LSM secid value for entry
359 *
360 * Description:
361 * Add a new address entry into the unlabeled connection hash table using the
362 * interface entry specified by @iface. On success zero is returned, otherwise
363 * a negative value is returned. The caller is responsible for calling the
364 * rcu_read_[un]lock() functions.
365 *
68 */ 366 */
367static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface,
368 const struct in_addr *addr,
369 const struct in_addr *mask,
370 u32 secid)
371{
372 struct netlbl_unlhsh_addr4 *entry;
373 struct netlbl_unlhsh_addr4 *iter;
374
375 entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
376 if (entry == NULL)
377 return -ENOMEM;
378
379 entry->addr = addr->s_addr & mask->s_addr;
380 entry->mask = mask->s_addr;
381 entry->secid = secid;
382 entry->valid = 1;
383 INIT_RCU_HEAD(&entry->rcu);
384
385 spin_lock(&netlbl_unlhsh_lock);
386 iter = netlbl_unlhsh_search_addr4(entry->addr, iface);
387 if (iter != NULL &&
388 iter->addr == addr->s_addr && iter->mask == mask->s_addr) {
389 spin_unlock(&netlbl_unlhsh_lock);
390 kfree(entry);
391 return -EEXIST;
392 }
393 /* in order to speed up address searches through the list (the common
394 * case) we need to keep the list in order based on the size of the
395 * address mask such that the entry with the widest mask (smallest
396 * numerical value) appears first in the list */
397 list_for_each_entry_rcu(iter, &iface->addr4_list, list)
398 if (iter->valid &&
399 ntohl(entry->mask) > ntohl(iter->mask)) {
400 __list_add_rcu(&entry->list,
401 iter->list.prev,
402 &iter->list);
403 spin_unlock(&netlbl_unlhsh_lock);
404 return 0;
405 }
406 list_add_tail_rcu(&entry->list, &iface->addr4_list);
407 spin_unlock(&netlbl_unlhsh_lock);
408 return 0;
409}
410
411#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
412/**
413 * netlbl_unlhsh_add_addr6 - Add a new IPv6 address entry to the hash table
414 * @iface: the associated interface entry
415 * @addr: IPv6 address in network byte order
416 * @mask: IPv6 address mask in network byte order
417 * @secid: LSM secid value for entry
418 *
419 * Description:
420 * Add a new address entry into the unlabeled connection hash table using the
421 * interface entry specified by @iface. On success zero is returned, otherwise
422 * a negative value is returned. The caller is responsible for calling the
423 * rcu_read_[un]lock() functions.
424 *
425 */
426static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface,
427 const struct in6_addr *addr,
428 const struct in6_addr *mask,
429 u32 secid)
430{
431 struct netlbl_unlhsh_addr6 *entry;
432 struct netlbl_unlhsh_addr6 *iter;
433
434 entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
435 if (entry == NULL)
436 return -ENOMEM;
437
438 ipv6_addr_copy(&entry->addr, addr);
439 entry->addr.s6_addr32[0] &= mask->s6_addr32[0];
440 entry->addr.s6_addr32[1] &= mask->s6_addr32[1];
441 entry->addr.s6_addr32[2] &= mask->s6_addr32[2];
442 entry->addr.s6_addr32[3] &= mask->s6_addr32[3];
443 ipv6_addr_copy(&entry->mask, mask);
444 entry->secid = secid;
445 entry->valid = 1;
446 INIT_RCU_HEAD(&entry->rcu);
447
448 spin_lock(&netlbl_unlhsh_lock);
449 iter = netlbl_unlhsh_search_addr6(&entry->addr, iface);
450 if (iter != NULL &&
451 (ipv6_addr_equal(&iter->addr, addr) &&
452 ipv6_addr_equal(&iter->mask, mask))) {
453 spin_unlock(&netlbl_unlhsh_lock);
454 kfree(entry);
455 return -EEXIST;
456 }
457 /* in order to speed up address searches through the list (the common
458 * case) we need to keep the list in order based on the size of the
459 * address mask such that the entry with the widest mask (smallest
460 * numerical value) appears first in the list */
461 list_for_each_entry_rcu(iter, &iface->addr6_list, list)
462 if (iter->valid &&
463 ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) {
464 __list_add_rcu(&entry->list,
465 iter->list.prev,
466 &iter->list);
467 spin_unlock(&netlbl_unlhsh_lock);
468 return 0;
469 }
470 list_add_tail_rcu(&entry->list, &iface->addr6_list);
471 spin_unlock(&netlbl_unlhsh_lock);
472 return 0;
473}
474#endif /* IPv6 */
475
476/**
477 * netlbl_unlhsh_add_iface - Adds a new interface entry to the hash table
478 * @ifindex: network interface
479 *
480 * Description:
481 * Add a new, empty, interface entry into the unlabeled connection hash table.
482 * On success a pointer to the new interface entry is returned, on failure NULL
483 * is returned. The caller is responsible for calling the rcu_read_[un]lock()
484 * functions.
485 *
486 */
487static struct netlbl_unlhsh_iface *netlbl_unlhsh_add_iface(int ifindex)
488{
489 u32 bkt;
490 struct netlbl_unlhsh_iface *iface;
491
492 iface = kzalloc(sizeof(*iface), GFP_ATOMIC);
493 if (iface == NULL)
494 return NULL;
495
496 iface->ifindex = ifindex;
497 INIT_LIST_HEAD(&iface->addr4_list);
498 INIT_LIST_HEAD(&iface->addr6_list);
499 iface->valid = 1;
500 INIT_RCU_HEAD(&iface->rcu);
501
502 spin_lock(&netlbl_unlhsh_lock);
503 if (ifindex > 0) {
504 bkt = netlbl_unlhsh_hash(ifindex);
505 if (netlbl_unlhsh_search_iface(ifindex) != NULL)
506 goto add_iface_failure;
507 list_add_tail_rcu(&iface->list,
508 &rcu_dereference(netlbl_unlhsh)->tbl[bkt]);
509 } else {
510 INIT_LIST_HEAD(&iface->list);
511 if (rcu_dereference(netlbl_unlhsh_def) != NULL)
512 goto add_iface_failure;
513 rcu_assign_pointer(netlbl_unlhsh_def, iface);
514 }
515 spin_unlock(&netlbl_unlhsh_lock);
516
517 return iface;
518
519add_iface_failure:
520 spin_unlock(&netlbl_unlhsh_lock);
521 kfree(iface);
522 return NULL;
523}
524
525/**
526 * netlbl_unlhsh_add - Adds a new entry to the unlabeled connection hash table
527 * @net: network namespace
528 * @dev_name: interface name
529 * @addr: IP address in network byte order
530 * @mask: address mask in network byte order
531 * @addr_len: length of address/mask (4 for IPv4, 16 for IPv6)
532 * @secid: LSM secid value for the entry
533 *
534 * Description:
535 * Adds a new entry to the unlabeled connection hash table. Returns zero on
536 * success, negative values on failure.
537 *
538 */
539static int netlbl_unlhsh_add(struct net *net,
540 const char *dev_name,
541 const void *addr,
542 const void *mask,
543 u32 addr_len,
544 u32 secid)
545{
546 int ret_val;
547 int ifindex;
548 struct net_device *dev;
549 struct netlbl_unlhsh_iface *iface;
550
551 if (addr_len != sizeof(struct in_addr) &&
552 addr_len != sizeof(struct in6_addr))
553 return -EINVAL;
554
555 rcu_read_lock();
556 if (dev_name != NULL) {
557 dev = dev_get_by_name(net, dev_name);
558 if (dev == NULL) {
559 ret_val = -ENODEV;
560 goto unlhsh_add_return;
561 }
562 ifindex = dev->ifindex;
563 dev_put(dev);
564 iface = netlbl_unlhsh_search_iface(ifindex);
565 } else {
566 ifindex = 0;
567 iface = rcu_dereference(netlbl_unlhsh_def);
568 }
569 if (iface == NULL) {
570 iface = netlbl_unlhsh_add_iface(ifindex);
571 if (iface == NULL) {
572 ret_val = -ENOMEM;
573 goto unlhsh_add_return;
574 }
575 }
576 switch (addr_len) {
577 case sizeof(struct in_addr):
578 ret_val = netlbl_unlhsh_add_addr4(iface, addr, mask, secid);
579 break;
580#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
581 case sizeof(struct in6_addr):
582 ret_val = netlbl_unlhsh_add_addr6(iface, addr, mask, secid);
583 break;
584#endif /* IPv6 */
585 default:
586 ret_val = -EINVAL;
587 }
588 if (ret_val == 0)
589 atomic_inc(&netlabel_mgmt_protocount);
590
591unlhsh_add_return:
592 rcu_read_unlock();
593 return ret_val;
594}
595
596/**
597 * netlbl_unlhsh_remove_addr4 - Remove an IPv4 address entry
598 * @iface: interface entry
599 * @addr: IP address
600 * @mask: IP address mask
601 *
602 * Description:
603 * Remove an IP address entry from the unlabeled connection hash table.
604 * Returns zero on success, negative values on failure. The caller is
605 * responsible for calling the rcu_read_[un]lock() functions.
606 *
607 */
608static int netlbl_unlhsh_remove_addr4(struct netlbl_unlhsh_iface *iface,
609 const struct in_addr *addr,
610 const struct in_addr *mask)
611{
612 int ret_val = -ENOENT;
613 struct netlbl_unlhsh_addr4 *entry;
614
615 spin_lock(&netlbl_unlhsh_lock);
616 entry = netlbl_unlhsh_search_addr4(addr->s_addr, iface);
617 if (entry != NULL &&
618 entry->addr == addr->s_addr && entry->mask == mask->s_addr) {
619 entry->valid = 0;
620 list_del_rcu(&entry->list);
621 ret_val = 0;
622 }
623 spin_unlock(&netlbl_unlhsh_lock);
624
625 if (ret_val == 0)
626 call_rcu(&entry->rcu, netlbl_unlhsh_free_addr4);
627 return ret_val;
628}
629
630#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
631/**
632 * netlbl_unlhsh_remove_addr6 - Remove an IPv6 address entry
633 * @iface: interface entry
634 * @addr: IP address
635 * @mask: IP address mask
636 *
637 * Description:
638 * Remove an IP address entry from the unlabeled connection hash table.
639 * Returns zero on success, negative values on failure. The caller is
640 * responsible for calling the rcu_read_[un]lock() functions.
641 *
642 */
643static int netlbl_unlhsh_remove_addr6(struct netlbl_unlhsh_iface *iface,
644 const struct in6_addr *addr,
645 const struct in6_addr *mask)
646{
647 int ret_val = -ENOENT;
648 struct netlbl_unlhsh_addr6 *entry;
649
650 spin_lock(&netlbl_unlhsh_lock);
651 entry = netlbl_unlhsh_search_addr6(addr, iface);
652 if (entry != NULL &&
653 (ipv6_addr_equal(&entry->addr, addr) &&
654 ipv6_addr_equal(&entry->mask, mask))) {
655 entry->valid = 0;
656 list_del_rcu(&entry->list);
657 ret_val = 0;
658 }
659 spin_unlock(&netlbl_unlhsh_lock);
660
661 if (ret_val == 0)
662 call_rcu(&entry->rcu, netlbl_unlhsh_free_addr6);
663 return ret_val;
664}
665#endif /* IPv6 */
666
667/**
668 * netlbl_unlhsh_condremove_iface - Remove an interface entry
669 * @iface: the interface entry
670 *
671 * Description:
672 * Remove an interface entry from the unlabeled connection hash table if it is
673 * empty. An interface entry is considered to be empty if there are no
674 * address entries assigned to it.
675 *
676 */
677static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface)
678{
679 struct netlbl_unlhsh_addr4 *iter4;
680 struct netlbl_unlhsh_addr6 *iter6;
681
682 spin_lock(&netlbl_unlhsh_lock);
683 list_for_each_entry_rcu(iter4, &iface->addr4_list, list)
684 if (iter4->valid)
685 goto unlhsh_condremove_failure;
686 list_for_each_entry_rcu(iter6, &iface->addr6_list, list)
687 if (iter6->valid)
688 goto unlhsh_condremove_failure;
689 iface->valid = 0;
690 if (iface->ifindex > 0)
691 list_del_rcu(&iface->list);
692 else
693 rcu_assign_pointer(netlbl_unlhsh_def, NULL);
694 spin_unlock(&netlbl_unlhsh_lock);
695
696 call_rcu(&iface->rcu, netlbl_unlhsh_free_iface);
697 return;
698
699unlhsh_condremove_failure:
700 spin_unlock(&netlbl_unlhsh_lock);
701 return;
702}
703
704/**
705 * netlbl_unlhsh_remove - Remove an entry from the unlabeled hash table
706 * @net: network namespace
707 * @dev_name: interface name
708 * @addr: IP address in network byte order
709 * @mask: address mask in network byte order
710 * @addr_len: length of address/mask (4 for IPv4, 16 for IPv6)
711 *
712 * Description:
713 * Removes and existing entry from the unlabeled connection hash table.
714 * Returns zero on success, negative values on failure.
715 *
716 */
717static int netlbl_unlhsh_remove(struct net *net,
718 const char *dev_name,
719 const void *addr,
720 const void *mask,
721 u32 addr_len)
722{
723 int ret_val;
724 struct net_device *dev;
725 struct netlbl_unlhsh_iface *iface;
726
727 if (addr_len != sizeof(struct in_addr) &&
728 addr_len != sizeof(struct in6_addr))
729 return -EINVAL;
730
731 rcu_read_lock();
732 if (dev_name != NULL) {
733 dev = dev_get_by_name(net, dev_name);
734 if (dev == NULL) {
735 ret_val = -ENODEV;
736 goto unlhsh_remove_return;
737 }
738 iface = netlbl_unlhsh_search_iface(dev->ifindex);
739 dev_put(dev);
740 } else
741 iface = rcu_dereference(netlbl_unlhsh_def);
742 if (iface == NULL) {
743 ret_val = -ENOENT;
744 goto unlhsh_remove_return;
745 }
746 switch (addr_len) {
747 case sizeof(struct in_addr):
748 ret_val = netlbl_unlhsh_remove_addr4(iface, addr, mask);
749 break;
750#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
751 case sizeof(struct in6_addr):
752 ret_val = netlbl_unlhsh_remove_addr6(iface, addr, mask);
753 break;
754#endif /* IPv6 */
755 default:
756 ret_val = -EINVAL;
757 }
758 if (ret_val == 0) {
759 netlbl_unlhsh_condremove_iface(iface);
760 atomic_dec(&netlabel_mgmt_protocount);
761 }
762
763unlhsh_remove_return:
764 rcu_read_unlock();
765 return ret_val;
766}
767
768/*
769 * General Helper Functions
770 */
771
772/**
773 * netlbl_unlhsh_netdev_handler - Network device notification handler
774 * @this: notifier block
775 * @event: the event
776 * @ptr: the network device (cast to void)
777 *
778 * Description:
779 * Handle network device events, although at present all we care about is a
780 * network device going away. In the case of a device going away we clear any
781 * related entries from the unlabeled connection hash table.
782 *
783 */
784static int netlbl_unlhsh_netdev_handler(struct notifier_block *this,
785 unsigned long event,
786 void *ptr)
787{
788 struct net_device *dev = ptr;
789 struct netlbl_unlhsh_iface *iface = NULL;
790
791 if (dev->nd_net != &init_net)
792 return NOTIFY_DONE;
793
794 /* XXX - should this be a check for NETDEV_DOWN or _UNREGISTER? */
795 if (event == NETDEV_DOWN) {
796 spin_lock(&netlbl_unlhsh_lock);
797 iface = netlbl_unlhsh_search_iface(dev->ifindex);
798 if (iface != NULL && iface->valid) {
799 iface->valid = 0;
800 list_del_rcu(&iface->list);
801 } else
802 iface = NULL;
803 spin_unlock(&netlbl_unlhsh_lock);
804 }
805
806 if (iface != NULL)
807 call_rcu(&iface->rcu, netlbl_unlhsh_free_iface);
808
809 return NOTIFY_DONE;
810}
69 811
70/** 812/**
71 * netlbl_unlabel_acceptflg_set - Set the unlabeled accept flag 813 * netlbl_unlabel_acceptflg_set - Set the unlabeled accept flag
@@ -93,6 +835,48 @@ static void netlbl_unlabel_acceptflg_set(u8 value,
93 } 835 }
94} 836}
95 837
838/**
839 * netlbl_unlabel_addrinfo_get - Get the IPv4/6 address information
840 * @info: the Generic NETLINK info block
841 * @addr: the IP address
842 * @mask: the IP address mask
843 * @len: the address length
844 *
845 * Description:
846 * Examine the Generic NETLINK message and extract the IP address information.
847 * Returns zero on success, negative values on failure.
848 *
849 */
850static int netlbl_unlabel_addrinfo_get(struct genl_info *info,
851 void **addr,
852 void **mask,
853 u32 *len)
854{
855 u32 addr_len;
856
857 if (info->attrs[NLBL_UNLABEL_A_IPV4ADDR]) {
858 addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]);
859 if (addr_len != sizeof(struct in_addr) &&
860 addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV4MASK]))
861 return -EINVAL;
862 *len = addr_len;
863 *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]);
864 *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4MASK]);
865 return 0;
866 } else if (info->attrs[NLBL_UNLABEL_A_IPV6ADDR]) {
867 addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]);
868 if (addr_len != sizeof(struct in6_addr) &&
869 addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV6MASK]))
870 return -EINVAL;
871 *len = addr_len;
872 *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]);
873 *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6MASK]);
874 return 0;
875 }
876
877 return -EINVAL;
878}
879
96/* 880/*
97 * NetLabel Command Handlers 881 * NetLabel Command Handlers
98 */ 882 */
@@ -168,11 +952,470 @@ list_failure:
168 return ret_val; 952 return ret_val;
169} 953}
170 954
955/**
956 * netlbl_unlabel_staticadd - Handle a STATICADD message
957 * @skb: the NETLINK buffer
958 * @info: the Generic NETLINK info block
959 *
960 * Description:
961 * Process a user generated STATICADD message and add a new unlabeled
962 * connection entry to the hash table. Returns zero on success, negative
963 * values on failure.
964 *
965 */
966static int netlbl_unlabel_staticadd(struct sk_buff *skb,
967 struct genl_info *info)
968{
969 int ret_val;
970 char *dev_name;
971 void *addr;
972 void *mask;
973 u32 addr_len;
974 u32 secid;
975
976 /* Don't allow users to add both IPv4 and IPv6 addresses for a
977 * single entry. However, allow users to create two entries, one each
978 * for IPv4 and IPv4, with the same LSM security context which should
979 * achieve the same result. */
980 if (!info->attrs[NLBL_UNLABEL_A_SECCTX] ||
981 !info->attrs[NLBL_UNLABEL_A_IFACE] ||
982 !((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
983 !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
984 (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
985 !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
986 return -EINVAL;
987
988 ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
989 if (ret_val != 0)
990 return ret_val;
991 dev_name = nla_data(info->attrs[NLBL_UNLABEL_A_IFACE]);
992 ret_val = security_secctx_to_secid(
993 nla_data(info->attrs[NLBL_UNLABEL_A_SECCTX]),
994 nla_len(info->attrs[NLBL_UNLABEL_A_SECCTX]),
995 &secid);
996 if (ret_val != 0)
997 return ret_val;
998
999 return netlbl_unlhsh_add(&init_net,
1000 dev_name, addr, mask, addr_len, secid);
1001}
1002
1003/**
1004 * netlbl_unlabel_staticadddef - Handle a STATICADDDEF message
1005 * @skb: the NETLINK buffer
1006 * @info: the Generic NETLINK info block
1007 *
1008 * Description:
1009 * Process a user generated STATICADDDEF message and add a new default
1010 * unlabeled connection entry. Returns zero on success, negative values on
1011 * failure.
1012 *
1013 */
1014static int netlbl_unlabel_staticadddef(struct sk_buff *skb,
1015 struct genl_info *info)
1016{
1017 int ret_val;
1018 void *addr;
1019 void *mask;
1020 u32 addr_len;
1021 u32 secid;
1022
1023 /* Don't allow users to add both IPv4 and IPv6 addresses for a
1024 * single entry. However, allow users to create two entries, one each
1025 * for IPv4 and IPv6, with the same LSM security context which should
1026 * achieve the same result. */
1027 if (!info->attrs[NLBL_UNLABEL_A_SECCTX] ||
1028 !((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
1029 !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
1030 (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
1031 !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
1032 return -EINVAL;
1033
1034 ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
1035 if (ret_val != 0)
1036 return ret_val;
1037 ret_val = security_secctx_to_secid(
1038 nla_data(info->attrs[NLBL_UNLABEL_A_SECCTX]),
1039 nla_len(info->attrs[NLBL_UNLABEL_A_SECCTX]),
1040 &secid);
1041 if (ret_val != 0)
1042 return ret_val;
1043
1044 return netlbl_unlhsh_add(&init_net, NULL, addr, mask, addr_len, secid);
1045}
1046
1047/**
1048 * netlbl_unlabel_staticremove - Handle a STATICREMOVE message
1049 * @skb: the NETLINK buffer
1050 * @info: the Generic NETLINK info block
1051 *
1052 * Description:
1053 * Process a user generated STATICREMOVE message and remove the specified
1054 * unlabeled connection entry. Returns zero on success, negative values on
1055 * failure.
1056 *
1057 */
1058static int netlbl_unlabel_staticremove(struct sk_buff *skb,
1059 struct genl_info *info)
1060{
1061 int ret_val;
1062 char *dev_name;
1063 void *addr;
1064 void *mask;
1065 u32 addr_len;
1066
1067 /* See the note in netlbl_unlabel_staticadd() about not allowing both
1068 * IPv4 and IPv6 in the same entry. */
1069 if (!info->attrs[NLBL_UNLABEL_A_IFACE] ||
1070 !((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
1071 !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
1072 (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
1073 !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
1074 return -EINVAL;
1075
1076 ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
1077 if (ret_val != 0)
1078 return ret_val;
1079 dev_name = nla_data(info->attrs[NLBL_UNLABEL_A_IFACE]);
1080
1081 return netlbl_unlhsh_remove(&init_net, dev_name, addr, mask, addr_len);
1082}
1083
1084/**
1085 * netlbl_unlabel_staticremovedef - Handle a STATICREMOVEDEF message
1086 * @skb: the NETLINK buffer
1087 * @info: the Generic NETLINK info block
1088 *
1089 * Description:
1090 * Process a user generated STATICREMOVEDEF message and remove the default
1091 * unlabeled connection entry. Returns zero on success, negative values on
1092 * failure.
1093 *
1094 */
1095static int netlbl_unlabel_staticremovedef(struct sk_buff *skb,
1096 struct genl_info *info)
1097{
1098 int ret_val;
1099 void *addr;
1100 void *mask;
1101 u32 addr_len;
1102
1103 /* See the note in netlbl_unlabel_staticadd() about not allowing both
1104 * IPv4 and IPv6 in the same entry. */
1105 if (!((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
1106 !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
1107 (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
1108 !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
1109 return -EINVAL;
1110
1111 ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
1112 if (ret_val != 0)
1113 return ret_val;
1114
1115 return netlbl_unlhsh_remove(&init_net, NULL, addr, mask, addr_len);
1116}
1117
1118
1119/**
1120 * netlbl_unlabel_staticlist_gen - Generate messages for STATICLIST[DEF]
1121 * @cmd: command/message
1122 * @iface: the interface entry
1123 * @addr4: the IPv4 address entry
1124 * @addr6: the IPv6 address entry
1125 * @arg: the netlbl_unlhsh_walk_arg structure
1126 *
1127 * Description:
1128 * This function is designed to be used to generate a response for a
1129 * STATICLIST or STATICLISTDEF message. When called either @addr4 or @addr6
1130 * can be specified, not both, the other unspecified entry should be set to
1131 * NULL by the caller. Returns the size of the message on success, negative
1132 * values on failure.
1133 *
1134 */
1135static int netlbl_unlabel_staticlist_gen(u32 cmd,
1136 const struct netlbl_unlhsh_iface *iface,
1137 const struct netlbl_unlhsh_addr4 *addr4,
1138 const struct netlbl_unlhsh_addr6 *addr6,
1139 void *arg)
1140{
1141 int ret_val = -ENOMEM;
1142 struct netlbl_unlhsh_walk_arg *cb_arg = arg;
1143 struct net_device *dev;
1144 void *data;
1145 u32 secid;
1146 char *secctx;
1147 u32 secctx_len;
1148
1149 data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).pid,
1150 cb_arg->seq, &netlbl_unlabel_gnl_family,
1151 NLM_F_MULTI, cmd);
1152 if (data == NULL)
1153 goto list_cb_failure;
1154
1155 if (iface->ifindex > 0) {
1156 dev = dev_get_by_index(&init_net, iface->ifindex);
1157 ret_val = nla_put_string(cb_arg->skb,
1158 NLBL_UNLABEL_A_IFACE, dev->name);
1159 dev_put(dev);
1160 if (ret_val != 0)
1161 goto list_cb_failure;
1162 }
1163
1164 if (addr4) {
1165 struct in_addr addr_struct;
1166
1167 addr_struct.s_addr = addr4->addr;
1168 ret_val = nla_put(cb_arg->skb,
1169 NLBL_UNLABEL_A_IPV4ADDR,
1170 sizeof(struct in_addr),
1171 &addr_struct);
1172 if (ret_val != 0)
1173 goto list_cb_failure;
1174
1175 addr_struct.s_addr = addr4->mask;
1176 ret_val = nla_put(cb_arg->skb,
1177 NLBL_UNLABEL_A_IPV4MASK,
1178 sizeof(struct in_addr),
1179 &addr_struct);
1180 if (ret_val != 0)
1181 goto list_cb_failure;
1182
1183 secid = addr4->secid;
1184 } else {
1185 ret_val = nla_put(cb_arg->skb,
1186 NLBL_UNLABEL_A_IPV6ADDR,
1187 sizeof(struct in6_addr),
1188 &addr6->addr);
1189 if (ret_val != 0)
1190 goto list_cb_failure;
1191
1192 ret_val = nla_put(cb_arg->skb,
1193 NLBL_UNLABEL_A_IPV6MASK,
1194 sizeof(struct in6_addr),
1195 &addr6->mask);
1196 if (ret_val != 0)
1197 goto list_cb_failure;
1198
1199 secid = addr6->secid;
1200 }
1201
1202 ret_val = security_secid_to_secctx(secid, &secctx, &secctx_len);
1203 if (ret_val != 0)
1204 goto list_cb_failure;
1205 ret_val = nla_put(cb_arg->skb,
1206 NLBL_UNLABEL_A_SECCTX,
1207 secctx_len,
1208 secctx);
1209 security_release_secctx(secctx, secctx_len);
1210 if (ret_val != 0)
1211 goto list_cb_failure;
1212
1213 cb_arg->seq++;
1214 return genlmsg_end(cb_arg->skb, data);
1215
1216list_cb_failure:
1217 genlmsg_cancel(cb_arg->skb, data);
1218 return ret_val;
1219}
1220
1221/**
1222 * netlbl_unlabel_staticlist - Handle a STATICLIST message
1223 * @skb: the NETLINK buffer
1224 * @cb: the NETLINK callback
1225 *
1226 * Description:
1227 * Process a user generated STATICLIST message and dump the unlabeled
1228 * connection hash table in a form suitable for use in a kernel generated
1229 * STATICLIST message. Returns the length of @skb.
1230 *
1231 */
1232static int netlbl_unlabel_staticlist(struct sk_buff *skb,
1233 struct netlink_callback *cb)
1234{
1235 struct netlbl_unlhsh_walk_arg cb_arg;
1236 u32 skip_bkt = cb->args[0];
1237 u32 skip_chain = cb->args[1];
1238 u32 skip_addr4 = cb->args[2];
1239 u32 skip_addr6 = cb->args[3];
1240 u32 iter_bkt;
1241 u32 iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0;
1242 struct netlbl_unlhsh_iface *iface;
1243 struct netlbl_unlhsh_addr4 *addr4;
1244 struct netlbl_unlhsh_addr6 *addr6;
1245
1246 cb_arg.nl_cb = cb;
1247 cb_arg.skb = skb;
1248 cb_arg.seq = cb->nlh->nlmsg_seq;
1249
1250 rcu_read_lock();
1251 for (iter_bkt = skip_bkt;
1252 iter_bkt < rcu_dereference(netlbl_unlhsh)->size;
1253 iter_bkt++, iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0) {
1254 list_for_each_entry_rcu(iface,
1255 &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt],
1256 list) {
1257 if (!iface->valid ||
1258 iter_chain++ < skip_chain)
1259 continue;
1260 list_for_each_entry_rcu(addr4,
1261 &iface->addr4_list,
1262 list) {
1263 if (!addr4->valid || iter_addr4++ < skip_addr4)
1264 continue;
1265 if (netlbl_unlabel_staticlist_gen(
1266 NLBL_UNLABEL_C_STATICLIST,
1267 iface,
1268 addr4,
1269 NULL,
1270 &cb_arg) < 0) {
1271 iter_addr4--;
1272 iter_chain--;
1273 goto unlabel_staticlist_return;
1274 }
1275 }
1276 list_for_each_entry_rcu(addr6,
1277 &iface->addr6_list,
1278 list) {
1279 if (!addr6->valid || iter_addr6++ < skip_addr6)
1280 continue;
1281 if (netlbl_unlabel_staticlist_gen(
1282 NLBL_UNLABEL_C_STATICLIST,
1283 iface,
1284 NULL,
1285 addr6,
1286 &cb_arg) < 0) {
1287 iter_addr6--;
1288 iter_chain--;
1289 goto unlabel_staticlist_return;
1290 }
1291 }
1292 }
1293 }
1294
1295unlabel_staticlist_return:
1296 rcu_read_unlock();
1297 cb->args[0] = skip_bkt;
1298 cb->args[1] = skip_chain;
1299 cb->args[2] = skip_addr4;
1300 cb->args[3] = skip_addr6;
1301 return skb->len;
1302}
1303
1304/**
1305 * netlbl_unlabel_staticlistdef - Handle a STATICLISTDEF message
1306 * @skb: the NETLINK buffer
1307 * @cb: the NETLINK callback
1308 *
1309 * Description:
1310 * Process a user generated STATICLISTDEF message and dump the default
1311 * unlabeled connection entry in a form suitable for use in a kernel generated
1312 * STATICLISTDEF message. Returns the length of @skb.
1313 *
1314 */
1315static int netlbl_unlabel_staticlistdef(struct sk_buff *skb,
1316 struct netlink_callback *cb)
1317{
1318 struct netlbl_unlhsh_walk_arg cb_arg;
1319 struct netlbl_unlhsh_iface *iface;
1320 u32 skip_addr4 = cb->args[0];
1321 u32 skip_addr6 = cb->args[1];
1322 u32 iter_addr4 = 0, iter_addr6 = 0;
1323 struct netlbl_unlhsh_addr4 *addr4;
1324 struct netlbl_unlhsh_addr6 *addr6;
1325
1326 cb_arg.nl_cb = cb;
1327 cb_arg.skb = skb;
1328 cb_arg.seq = cb->nlh->nlmsg_seq;
1329
1330 rcu_read_lock();
1331 iface = rcu_dereference(netlbl_unlhsh_def);
1332 if (iface == NULL || !iface->valid)
1333 goto unlabel_staticlistdef_return;
1334
1335 list_for_each_entry_rcu(addr4, &iface->addr4_list, list) {
1336 if (!addr4->valid || iter_addr4++ < skip_addr4)
1337 continue;
1338 if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
1339 iface,
1340 addr4,
1341 NULL,
1342 &cb_arg) < 0) {
1343 iter_addr4--;
1344 goto unlabel_staticlistdef_return;
1345 }
1346 }
1347 list_for_each_entry_rcu(addr6, &iface->addr6_list, list) {
1348 if (addr6->valid || iter_addr6++ < skip_addr6)
1349 continue;
1350 if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
1351 iface,
1352 NULL,
1353 addr6,
1354 &cb_arg) < 0) {
1355 iter_addr6--;
1356 goto unlabel_staticlistdef_return;
1357 }
1358 }
1359
1360unlabel_staticlistdef_return:
1361 rcu_read_unlock();
1362 cb->args[0] = skip_addr4;
1363 cb->args[1] = skip_addr6;
1364 return skb->len;
1365}
171 1366
172/* 1367/*
173 * NetLabel Generic NETLINK Command Definitions 1368 * NetLabel Generic NETLINK Command Definitions
174 */ 1369 */
175 1370
1371static struct genl_ops netlbl_unlabel_genl_c_staticadd = {
1372 .cmd = NLBL_UNLABEL_C_STATICADD,
1373 .flags = GENL_ADMIN_PERM,
1374 .policy = netlbl_unlabel_genl_policy,
1375 .doit = netlbl_unlabel_staticadd,
1376 .dumpit = NULL,
1377};
1378
1379static struct genl_ops netlbl_unlabel_genl_c_staticremove = {
1380 .cmd = NLBL_UNLABEL_C_STATICREMOVE,
1381 .flags = GENL_ADMIN_PERM,
1382 .policy = netlbl_unlabel_genl_policy,
1383 .doit = netlbl_unlabel_staticremove,
1384 .dumpit = NULL,
1385};
1386
1387static struct genl_ops netlbl_unlabel_genl_c_staticlist = {
1388 .cmd = NLBL_UNLABEL_C_STATICLIST,
1389 .flags = 0,
1390 .policy = netlbl_unlabel_genl_policy,
1391 .doit = NULL,
1392 .dumpit = netlbl_unlabel_staticlist,
1393};
1394
1395static struct genl_ops netlbl_unlabel_genl_c_staticadddef = {
1396 .cmd = NLBL_UNLABEL_C_STATICADDDEF,
1397 .flags = GENL_ADMIN_PERM,
1398 .policy = netlbl_unlabel_genl_policy,
1399 .doit = netlbl_unlabel_staticadddef,
1400 .dumpit = NULL,
1401};
1402
1403static struct genl_ops netlbl_unlabel_genl_c_staticremovedef = {
1404 .cmd = NLBL_UNLABEL_C_STATICREMOVEDEF,
1405 .flags = GENL_ADMIN_PERM,
1406 .policy = netlbl_unlabel_genl_policy,
1407 .doit = netlbl_unlabel_staticremovedef,
1408 .dumpit = NULL,
1409};
1410
1411static struct genl_ops netlbl_unlabel_genl_c_staticlistdef = {
1412 .cmd = NLBL_UNLABEL_C_STATICLISTDEF,
1413 .flags = 0,
1414 .policy = netlbl_unlabel_genl_policy,
1415 .doit = NULL,
1416 .dumpit = netlbl_unlabel_staticlistdef,
1417};
1418
176static struct genl_ops netlbl_unlabel_genl_c_accept = { 1419static struct genl_ops netlbl_unlabel_genl_c_accept = {
177 .cmd = NLBL_UNLABEL_C_ACCEPT, 1420 .cmd = NLBL_UNLABEL_C_ACCEPT,
178 .flags = GENL_ADMIN_PERM, 1421 .flags = GENL_ADMIN_PERM,
@@ -189,7 +1432,6 @@ static struct genl_ops netlbl_unlabel_genl_c_list = {
189 .dumpit = NULL, 1432 .dumpit = NULL,
190}; 1433};
191 1434
192
193/* 1435/*
194 * NetLabel Generic NETLINK Protocol Functions 1436 * NetLabel Generic NETLINK Protocol Functions
195 */ 1437 */
@@ -211,6 +1453,36 @@ int netlbl_unlabel_genl_init(void)
211 return ret_val; 1453 return ret_val;
212 1454
213 ret_val = genl_register_ops(&netlbl_unlabel_gnl_family, 1455 ret_val = genl_register_ops(&netlbl_unlabel_gnl_family,
1456 &netlbl_unlabel_genl_c_staticadd);
1457 if (ret_val != 0)
1458 return ret_val;
1459
1460 ret_val = genl_register_ops(&netlbl_unlabel_gnl_family,
1461 &netlbl_unlabel_genl_c_staticremove);
1462 if (ret_val != 0)
1463 return ret_val;
1464
1465 ret_val = genl_register_ops(&netlbl_unlabel_gnl_family,
1466 &netlbl_unlabel_genl_c_staticlist);
1467 if (ret_val != 0)
1468 return ret_val;
1469
1470 ret_val = genl_register_ops(&netlbl_unlabel_gnl_family,
1471 &netlbl_unlabel_genl_c_staticadddef);
1472 if (ret_val != 0)
1473 return ret_val;
1474
1475 ret_val = genl_register_ops(&netlbl_unlabel_gnl_family,
1476 &netlbl_unlabel_genl_c_staticremovedef);
1477 if (ret_val != 0)
1478 return ret_val;
1479
1480 ret_val = genl_register_ops(&netlbl_unlabel_gnl_family,
1481 &netlbl_unlabel_genl_c_staticlistdef);
1482 if (ret_val != 0)
1483 return ret_val;
1484
1485 ret_val = genl_register_ops(&netlbl_unlabel_gnl_family,
214 &netlbl_unlabel_genl_c_accept); 1486 &netlbl_unlabel_genl_c_accept);
215 if (ret_val != 0) 1487 if (ret_val != 0)
216 return ret_val; 1488 return ret_val;
@@ -227,8 +1499,58 @@ int netlbl_unlabel_genl_init(void)
227 * NetLabel KAPI Hooks 1499 * NetLabel KAPI Hooks
228 */ 1500 */
229 1501
1502static struct notifier_block netlbl_unlhsh_netdev_notifier = {
1503 .notifier_call = netlbl_unlhsh_netdev_handler,
1504};
1505
1506/**
1507 * netlbl_unlabel_init - Initialize the unlabeled connection hash table
1508 * @size: the number of bits to use for the hash buckets
1509 *
1510 * Description:
1511 * Initializes the unlabeled connection hash table and registers a network
1512 * device notification handler. This function should only be called by the
1513 * NetLabel subsystem itself during initialization. Returns zero on success,
1514 * non-zero values on error.
1515 *
1516 */
1517int netlbl_unlabel_init(u32 size)
1518{
1519 u32 iter;
1520 struct netlbl_unlhsh_tbl *hsh_tbl;
1521
1522 if (size == 0)
1523 return -EINVAL;
1524
1525 hsh_tbl = kmalloc(sizeof(*hsh_tbl), GFP_KERNEL);
1526 if (hsh_tbl == NULL)
1527 return -ENOMEM;
1528 hsh_tbl->size = 1 << size;
1529 hsh_tbl->tbl = kcalloc(hsh_tbl->size,
1530 sizeof(struct list_head),
1531 GFP_KERNEL);
1532 if (hsh_tbl->tbl == NULL) {
1533 kfree(hsh_tbl);
1534 return -ENOMEM;
1535 }
1536 for (iter = 0; iter < hsh_tbl->size; iter++)
1537 INIT_LIST_HEAD(&hsh_tbl->tbl[iter]);
1538
1539 rcu_read_lock();
1540 spin_lock(&netlbl_unlhsh_lock);
1541 rcu_assign_pointer(netlbl_unlhsh, hsh_tbl);
1542 spin_unlock(&netlbl_unlhsh_lock);
1543 rcu_read_unlock();
1544
1545 register_netdevice_notifier(&netlbl_unlhsh_netdev_notifier);
1546
1547 return 0;
1548}
1549
230/** 1550/**
231 * netlbl_unlabel_getattr - Get the security attributes for an unlabled packet 1551 * netlbl_unlabel_getattr - Get the security attributes for an unlabled packet
1552 * @skb: the packet
1553 * @family: protocol family
232 * @secattr: the security attributes 1554 * @secattr: the security attributes
233 * 1555 *
234 * Description: 1556 * Description:
@@ -236,11 +1558,50 @@ int netlbl_unlabel_genl_init(void)
236 * them in @secattr. Returns zero on success and negative values on failure. 1558 * them in @secattr. Returns zero on success and negative values on failure.
237 * 1559 *
238 */ 1560 */
239int netlbl_unlabel_getattr(struct netlbl_lsm_secattr *secattr) 1561int netlbl_unlabel_getattr(const struct sk_buff *skb,
1562 u16 family,
1563 struct netlbl_lsm_secattr *secattr)
240{ 1564{
1565 struct iphdr *hdr4;
1566 struct ipv6hdr *hdr6;
1567 struct netlbl_unlhsh_addr4 *addr4;
1568 struct netlbl_unlhsh_addr6 *addr6;
1569 struct netlbl_unlhsh_iface *iface;
1570
1571 rcu_read_lock();
1572 iface = netlbl_unlhsh_search_iface_def(skb->iif);
1573 if (iface == NULL)
1574 goto unlabel_getattr_nolabel;
1575 switch (family) {
1576 case PF_INET:
1577 hdr4 = ip_hdr(skb);
1578 addr4 = netlbl_unlhsh_search_addr4(hdr4->saddr, iface);
1579 if (addr4 == NULL)
1580 goto unlabel_getattr_nolabel;
1581 secattr->attr.secid = addr4->secid;
1582 break;
1583#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1584 case PF_INET6:
1585 hdr6 = ipv6_hdr(skb);
1586 addr6 = netlbl_unlhsh_search_addr6(&hdr6->saddr, iface);
1587 if (addr6 == NULL)
1588 goto unlabel_getattr_nolabel;
1589 secattr->attr.secid = addr6->secid;
1590 break;
1591#endif /* IPv6 */
1592 default:
1593 goto unlabel_getattr_nolabel;
1594 }
1595 rcu_read_unlock();
1596
1597 secattr->flags |= NETLBL_SECATTR_SECID;
1598 secattr->type = NETLBL_NLTYPE_UNLABELED;
1599 return 0;
1600
1601unlabel_getattr_nolabel:
1602 rcu_read_unlock();
241 if (netlabel_unlabel_acceptflg == 0) 1603 if (netlabel_unlabel_acceptflg == 0)
242 return -ENOMSG; 1604 return -ENOMSG;
243 netlbl_secattr_init(secattr);
244 secattr->type = NETLBL_NLTYPE_UNLABELED; 1605 secattr->type = NETLBL_NLTYPE_UNLABELED;
245 return 0; 1606 return 0;
246} 1607}
diff --git a/net/netlabel/netlabel_unlabeled.h b/net/netlabel/netlabel_unlabeled.h
index c2917fbb42cf..06b1301ac072 100644
--- a/net/netlabel/netlabel_unlabeled.h
+++ b/net/netlabel/netlabel_unlabeled.h
@@ -36,6 +36,116 @@
36/* 36/*
37 * The following NetLabel payloads are supported by the Unlabeled subsystem. 37 * The following NetLabel payloads are supported by the Unlabeled subsystem.
38 * 38 *
39 * o STATICADD
40 * This message is sent from an application to add a new static label for
41 * incoming unlabeled connections.
42 *
43 * Required attributes:
44 *
45 * NLBL_UNLABEL_A_IFACE
46 * NLBL_UNLABEL_A_SECCTX
47 *
48 * If IPv4 is specified the following attributes are required:
49 *
50 * NLBL_UNLABEL_A_IPV4ADDR
51 * NLBL_UNLABEL_A_IPV4MASK
52 *
53 * If IPv6 is specified the following attributes are required:
54 *
55 * NLBL_UNLABEL_A_IPV6ADDR
56 * NLBL_UNLABEL_A_IPV6MASK
57 *
58 * o STATICREMOVE
59 * This message is sent from an application to remove an existing static
60 * label for incoming unlabeled connections.
61 *
62 * Required attributes:
63 *
64 * NLBL_UNLABEL_A_IFACE
65 *
66 * If IPv4 is specified the following attributes are required:
67 *
68 * NLBL_UNLABEL_A_IPV4ADDR
69 * NLBL_UNLABEL_A_IPV4MASK
70 *
71 * If IPv6 is specified the following attributes are required:
72 *
73 * NLBL_UNLABEL_A_IPV6ADDR
74 * NLBL_UNLABEL_A_IPV6MASK
75 *
76 * o STATICLIST
77 * This message can be sent either from an application or by the kernel in
78 * response to an application generated STATICLIST message. When sent by an
79 * application there is no payload and the NLM_F_DUMP flag should be set.
80 * The kernel should response with a series of the following messages.
81 *
82 * Required attributes:
83 *
84 * NLBL_UNLABEL_A_IFACE
85 * NLBL_UNLABEL_A_SECCTX
86 *
87 * If IPv4 is specified the following attributes are required:
88 *
89 * NLBL_UNLABEL_A_IPV4ADDR
90 * NLBL_UNLABEL_A_IPV4MASK
91 *
92 * If IPv6 is specified the following attributes are required:
93 *
94 * NLBL_UNLABEL_A_IPV6ADDR
95 * NLBL_UNLABEL_A_IPV6MASK
96 *
97 * o STATICADDDEF
98 * This message is sent from an application to set the default static
99 * label for incoming unlabeled connections.
100 *
101 * Required attribute:
102 *
103 * NLBL_UNLABEL_A_SECCTX
104 *
105 * If IPv4 is specified the following attributes are required:
106 *
107 * NLBL_UNLABEL_A_IPV4ADDR
108 * NLBL_UNLABEL_A_IPV4MASK
109 *
110 * If IPv6 is specified the following attributes are required:
111 *
112 * NLBL_UNLABEL_A_IPV6ADDR
113 * NLBL_UNLABEL_A_IPV6MASK
114 *
115 * o STATICREMOVEDEF
116 * This message is sent from an application to remove the existing default
117 * static label for incoming unlabeled connections.
118 *
119 * If IPv4 is specified the following attributes are required:
120 *
121 * NLBL_UNLABEL_A_IPV4ADDR
122 * NLBL_UNLABEL_A_IPV4MASK
123 *
124 * If IPv6 is specified the following attributes are required:
125 *
126 * NLBL_UNLABEL_A_IPV6ADDR
127 * NLBL_UNLABEL_A_IPV6MASK
128 *
129 * o STATICLISTDEF
130 * This message can be sent either from an application or by the kernel in
131 * response to an application generated STATICLISTDEF message. When sent by
132 * an application there is no payload and the NLM_F_DUMP flag should be set.
133 * The kernel should response with the following message.
134 *
135 * Required attribute:
136 *
137 * NLBL_UNLABEL_A_SECCTX
138 *
139 * If IPv4 is specified the following attributes are required:
140 *
141 * NLBL_UNLABEL_A_IPV4ADDR
142 * NLBL_UNLABEL_A_IPV4MASK
143 *
144 * If IPv6 is specified the following attributes are required:
145 *
146 * NLBL_UNLABEL_A_IPV6ADDR
147 * NLBL_UNLABEL_A_IPV6MASK
148 *
39 * o ACCEPT 149 * o ACCEPT
40 * This message is sent from an application to specify if the kernel should 150 * This message is sent from an application to specify if the kernel should
41 * allow unlabled packets to pass if they do not match any of the static 151 * allow unlabled packets to pass if they do not match any of the static
@@ -62,6 +172,12 @@ enum {
62 NLBL_UNLABEL_C_UNSPEC, 172 NLBL_UNLABEL_C_UNSPEC,
63 NLBL_UNLABEL_C_ACCEPT, 173 NLBL_UNLABEL_C_ACCEPT,
64 NLBL_UNLABEL_C_LIST, 174 NLBL_UNLABEL_C_LIST,
175 NLBL_UNLABEL_C_STATICADD,
176 NLBL_UNLABEL_C_STATICREMOVE,
177 NLBL_UNLABEL_C_STATICLIST,
178 NLBL_UNLABEL_C_STATICADDDEF,
179 NLBL_UNLABEL_C_STATICREMOVEDEF,
180 NLBL_UNLABEL_C_STATICLISTDEF,
65 __NLBL_UNLABEL_C_MAX, 181 __NLBL_UNLABEL_C_MAX,
66}; 182};
67#define NLBL_UNLABEL_C_MAX (__NLBL_UNLABEL_C_MAX - 1) 183#define NLBL_UNLABEL_C_MAX (__NLBL_UNLABEL_C_MAX - 1)
@@ -73,6 +189,24 @@ enum {
73 /* (NLA_U8) 189 /* (NLA_U8)
74 * if true then unlabeled packets are allowed to pass, else unlabeled 190 * if true then unlabeled packets are allowed to pass, else unlabeled
75 * packets are rejected */ 191 * packets are rejected */
192 NLBL_UNLABEL_A_IPV6ADDR,
193 /* (NLA_BINARY, struct in6_addr)
194 * an IPv6 address */
195 NLBL_UNLABEL_A_IPV6MASK,
196 /* (NLA_BINARY, struct in6_addr)
197 * an IPv6 address mask */
198 NLBL_UNLABEL_A_IPV4ADDR,
199 /* (NLA_BINARY, struct in_addr)
200 * an IPv4 address */
201 NLBL_UNLABEL_A_IPV4MASK,
202 /* (NLA_BINARY, struct in_addr)
203 * and IPv4 address mask */
204 NLBL_UNLABEL_A_IFACE,
205 /* (NLA_NULL_STRING)
206 * network interface */
207 NLBL_UNLABEL_A_SECCTX,
208 /* (NLA_BINARY)
209 * a LSM specific security context */
76 __NLBL_UNLABEL_A_MAX, 210 __NLBL_UNLABEL_A_MAX,
77}; 211};
78#define NLBL_UNLABEL_A_MAX (__NLBL_UNLABEL_A_MAX - 1) 212#define NLBL_UNLABEL_A_MAX (__NLBL_UNLABEL_A_MAX - 1)
@@ -80,8 +214,17 @@ enum {
80/* NetLabel protocol functions */ 214/* NetLabel protocol functions */
81int netlbl_unlabel_genl_init(void); 215int netlbl_unlabel_genl_init(void);
82 216
217/* Unlabeled connection hash table size */
218/* XXX - currently this number is an uneducated guess */
219#define NETLBL_UNLHSH_BITSIZE 7
220
221/* General Unlabeled init function */
222int netlbl_unlabel_init(u32 size);
223
83/* Process Unlabeled incoming network packets */ 224/* Process Unlabeled incoming network packets */
84int netlbl_unlabel_getattr(struct netlbl_lsm_secattr *secattr); 225int netlbl_unlabel_getattr(const struct sk_buff *skb,
226 u16 family,
227 struct netlbl_lsm_secattr *secattr);
85 228
86/* Set the default configuration to allow Unlabeled packets */ 229/* Set the default configuration to allow Unlabeled packets */
87int netlbl_unlabel_defconf(void); 230int netlbl_unlabel_defconf(void);