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