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