~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/netlabel/netlabel_unlabeled.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php