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