aboutsummaryrefslogtreecommitdiffstats
path: root/net/netlabel
diff options
context:
space:
mode:
authorPaul Moore <paul.moore@hp.com>2008-01-29 08:44:21 -0500
committerJames Morris <jmorris@namei.org>2008-01-29 16:17:28 -0500
commit8cc44579d1bd77ba3a32f2cb76fd9669c229c5fd (patch)
tree802d46ff2b1b1700a3baa726d2aa4aba320376c9 /net/netlabel
parent5dbe1eb0cfc144a2b0cb1466e22bcb6fc34229a8 (diff)
NetLabel: Introduce static network labels for unlabeled connections
Most trusted OSs, with the exception of Linux, have the ability to specify static security labels for unlabeled networks. This patch adds this ability to the NetLabel packet labeling framework. If the NetLabel subsystem is called to determine the security attributes of an incoming packet it first checks to see if any recognized NetLabel packet labeling protocols are in-use on the packet. If none can be found then the unlabled connection table is queried and based on the packets incoming interface and address it is matched with a security label as configured by the administrator using the netlabel_tools package. The matching security label is returned to the caller just as if the packet was explicitly labeled using a labeling protocol. Signed-off-by: Paul Moore <paul.moore@hp.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'net/netlabel')
-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);