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