// SPDX-License-Identifier: GPL-2.0-only
      /*
       *        IEEE 802.1Q Multiple VLAN Registration Protocol (MVRP)
       *
       *        Copyright (c) 2012 Massachusetts Institute of Technology
       *
       *        Adapted from code in net/8021q/vlan_gvrp.c
       *        Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
       */
      #include <linux/types.h>
      #include <linux/if_ether.h>
      #include <linux/if_vlan.h>
      #include <net/mrp.h>
      #include "vlan.h"
      
      #define MRP_MVRP_ADDRESS        { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x21 }
      
      enum mvrp_attributes {
              MVRP_ATTR_INVALID,
              MVRP_ATTR_VID,
              __MVRP_ATTR_MAX
      };
      #define MVRP_ATTR_MAX        (__MVRP_ATTR_MAX - 1)
      
      static struct mrp_application vlan_mrp_app __read_mostly = {
              .type                = MRP_APPLICATION_MVRP,
              .maxattr        = MVRP_ATTR_MAX,
              .pkttype.type        = htons(ETH_P_MVRP),
              .group_address        = MRP_MVRP_ADDRESS,
              .version        = 0,
      };
      
      int vlan_mvrp_request_join(const struct net_device *dev)
      {
              const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
   16         __be16 vlan_id = htons(vlan->vlan_id);
      
   16         if (vlan->vlan_proto != htons(ETH_P_8021Q))
                      return 0;
   14         return mrp_request_join(vlan->real_dev, &vlan_mrp_app,
                                      &vlan_id, sizeof(vlan_id), MVRP_ATTR_VID);
      }
      
      void vlan_mvrp_request_leave(const struct net_device *dev)
      {
              const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
   24         __be16 vlan_id = htons(vlan->vlan_id);
      
              if (vlan->vlan_proto != htons(ETH_P_8021Q))
   24                 return;
   21         mrp_request_leave(vlan->real_dev, &vlan_mrp_app,
                                &vlan_id, sizeof(vlan_id), MVRP_ATTR_VID);
      }
      
      int vlan_mvrp_init_applicant(struct net_device *dev)
      {
   88         return mrp_init_applicant(dev, &vlan_mrp_app);
      }
      
      void vlan_mvrp_uninit_applicant(struct net_device *dev)
      {
   45         mrp_uninit_applicant(dev, &vlan_mrp_app);
      }
      
      int __init vlan_mvrp_init(void)
      {
              return mrp_register_application(&vlan_mrp_app);
      }
      
      void vlan_mvrp_uninit(void)
      {
              mrp_unregister_application(&vlan_mrp_app);
      }
      // SPDX-License-Identifier: GPL-2.0-only
      /*
       * IPv6 library code, needed by static components when full IPv6 support is
       * not configured or static.
       */
      
      #include <linux/export.h>
      #include <net/ipv6.h>
      #include <net/ipv6_stubs.h>
      #include <net/addrconf.h>
      #include <net/ip.h>
      
      /* if ipv6 module registers this function is used by xfrm to force all
       * sockets to relookup their nodes - this is fairly expensive, be
       * careful
       */
      void (*__fib6_flush_trees)(struct net *);
      EXPORT_SYMBOL(__fib6_flush_trees);
      
      #define IPV6_ADDR_SCOPE_TYPE(scope)        ((scope) << 16)
      
      static inline unsigned int ipv6_addr_scope2type(unsigned int scope)
      {
              switch (scope) {
              case IPV6_ADDR_SCOPE_NODELOCAL:
                      return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_NODELOCAL) |
                              IPV6_ADDR_LOOPBACK);
              case IPV6_ADDR_SCOPE_LINKLOCAL:
                      return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL) |
                              IPV6_ADDR_LINKLOCAL);
              case IPV6_ADDR_SCOPE_SITELOCAL:
                      return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL) |
                              IPV6_ADDR_SITELOCAL);
              }
              return IPV6_ADDR_SCOPE_TYPE(scope);
      }
      
  661 int __ipv6_addr_type(const struct in6_addr *addr)
      {
              __be32 st;
      
 2693         st = addr->s6_addr32[0];
      
              /* Consider all addresses with the first three bits different of
                 000 and 111 as unicasts.
               */
 2115         if ((st & htonl(0xE0000000)) != htonl(0x00000000) &&
                  (st & htonl(0xE0000000)) != htonl(0xE0000000))
                      return (IPV6_ADDR_UNICAST |
                              IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
      
 2686         if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) {
                      /* multicast */
                      /* addr-select 3.1 */
                      return (IPV6_ADDR_MULTICAST |
  661                         ipv6_addr_scope2type(IPV6_ADDR_MC_SCOPE(addr)));
              }
      
 2453         if ((st & htonl(0xFFC00000)) == htonl(0xFE800000))
                      return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST |
                              IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));                /* addr-select 3.1 */
 1828         if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000))
                      return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST |
                              IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL));                /* addr-select 3.1 */
 1827         if ((st & htonl(0xFE000000)) == htonl(0xFC000000))
                      return (IPV6_ADDR_UNICAST |
                              IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));                        /* RFC 4193 */
      
 1811         if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) {
 1786                 if (addr->s6_addr32[2] == 0) {
 1635                         if (addr->s6_addr32[3] == 0)
                                      return IPV6_ADDR_ANY;
      
 1391                         if (addr->s6_addr32[3] == htonl(0x00000001))
                                      return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST |
                                              IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));        /* addr-select 3.4 */
      
 2591                         return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST |
                                      IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));        /* addr-select 3.3 */
                      }
      
  692                 if (addr->s6_addr32[2] == htonl(0x0000ffff))
  692                         return (IPV6_ADDR_MAPPED |
                                      IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));        /* addr-select 3.3 */
              }
      
              return (IPV6_ADDR_UNICAST |
                      IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));        /* addr-select 3.4 */
      }
      EXPORT_SYMBOL(__ipv6_addr_type);
      
      static ATOMIC_NOTIFIER_HEAD(inet6addr_chain);
      static BLOCKING_NOTIFIER_HEAD(inet6addr_validator_chain);
      
      int register_inet6addr_notifier(struct notifier_block *nb)
      {
   39         return atomic_notifier_chain_register(&inet6addr_chain, nb);
      }
      EXPORT_SYMBOL(register_inet6addr_notifier);
      
      int unregister_inet6addr_notifier(struct notifier_block *nb)
      {
   14         return atomic_notifier_chain_unregister(&inet6addr_chain, nb);
      }
      EXPORT_SYMBOL(unregister_inet6addr_notifier);
      
      int inet6addr_notifier_call_chain(unsigned long val, void *v)
      {
  308         return atomic_notifier_call_chain(&inet6addr_chain, val, v);
      }
      EXPORT_SYMBOL(inet6addr_notifier_call_chain);
      
      int register_inet6addr_validator_notifier(struct notifier_block *nb)
      {
              return blocking_notifier_chain_register(&inet6addr_validator_chain, nb);
      }
      EXPORT_SYMBOL(register_inet6addr_validator_notifier);
      
      int unregister_inet6addr_validator_notifier(struct notifier_block *nb)
      {
              return blocking_notifier_chain_unregister(&inet6addr_validator_chain,
                                                        nb);
      }
      EXPORT_SYMBOL(unregister_inet6addr_validator_notifier);
      
      int inet6addr_validator_notifier_call_chain(unsigned long val, void *v)
      {
  297         return blocking_notifier_call_chain(&inet6addr_validator_chain, val, v);
      }
      EXPORT_SYMBOL(inet6addr_validator_notifier_call_chain);
      
      static struct dst_entry *eafnosupport_ipv6_dst_lookup_flow(struct net *net,
                                                                 const struct sock *sk,
                                                                 struct flowi6 *fl6,
                                                                 const struct in6_addr *final_dst)
      {
              return ERR_PTR(-EAFNOSUPPORT);
      }
      
      static int eafnosupport_ipv6_route_input(struct sk_buff *skb)
      {
              return -EAFNOSUPPORT;
      }
      
      static struct fib6_table *eafnosupport_fib6_get_table(struct net *net, u32 id)
      {
              return NULL;
      }
      
      static int
      eafnosupport_fib6_table_lookup(struct net *net, struct fib6_table *table,
                                     int oif, struct flowi6 *fl6,
                                     struct fib6_result *res, int flags)
      {
              return -EAFNOSUPPORT;
      }
      
      static int
      eafnosupport_fib6_lookup(struct net *net, int oif, struct flowi6 *fl6,
                               struct fib6_result *res, int flags)
      {
              return -EAFNOSUPPORT;
      }
      
      static void
      eafnosupport_fib6_select_path(const struct net *net, struct fib6_result *res,
                                    struct flowi6 *fl6, int oif, bool have_oif_match,
                                    const struct sk_buff *skb, int strict)
      {
      }
      
      static u32
      eafnosupport_ip6_mtu_from_fib6(const struct fib6_result *res,
                                     const struct in6_addr *daddr,
                                     const struct in6_addr *saddr)
      {
              return 0;
      }
      
      static int eafnosupport_fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
                                           struct fib6_config *cfg, gfp_t gfp_flags,
                                           struct netlink_ext_ack *extack)
      {
              NL_SET_ERR_MSG(extack, "IPv6 support not enabled in kernel");
              return -EAFNOSUPPORT;
      }
      
      static int eafnosupport_ip6_del_rt(struct net *net, struct fib6_info *rt)
      {
              return -EAFNOSUPPORT;
      }
      
      const struct ipv6_stub *ipv6_stub __read_mostly = &(struct ipv6_stub) {
              .ipv6_dst_lookup_flow = eafnosupport_ipv6_dst_lookup_flow,
              .ipv6_route_input  = eafnosupport_ipv6_route_input,
              .fib6_get_table    = eafnosupport_fib6_get_table,
              .fib6_table_lookup = eafnosupport_fib6_table_lookup,
              .fib6_lookup       = eafnosupport_fib6_lookup,
              .fib6_select_path  = eafnosupport_fib6_select_path,
              .ip6_mtu_from_fib6 = eafnosupport_ip6_mtu_from_fib6,
              .fib6_nh_init           = eafnosupport_fib6_nh_init,
              .ip6_del_rt           = eafnosupport_ip6_del_rt,
      };
      EXPORT_SYMBOL_GPL(ipv6_stub);
      
      /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
      const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
      EXPORT_SYMBOL(in6addr_loopback);
      const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
      EXPORT_SYMBOL(in6addr_any);
      const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
      EXPORT_SYMBOL(in6addr_linklocal_allnodes);
      const struct in6_addr in6addr_linklocal_allrouters = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
      EXPORT_SYMBOL(in6addr_linklocal_allrouters);
      const struct in6_addr in6addr_interfacelocal_allnodes = IN6ADDR_INTERFACELOCAL_ALLNODES_INIT;
      EXPORT_SYMBOL(in6addr_interfacelocal_allnodes);
      const struct in6_addr in6addr_interfacelocal_allrouters = IN6ADDR_INTERFACELOCAL_ALLROUTERS_INIT;
      EXPORT_SYMBOL(in6addr_interfacelocal_allrouters);
      const struct in6_addr in6addr_sitelocal_allrouters = IN6ADDR_SITELOCAL_ALLROUTERS_INIT;
      EXPORT_SYMBOL(in6addr_sitelocal_allrouters);
      
      static void snmp6_free_dev(struct inet6_dev *idev)
      {
              kfree(idev->stats.icmpv6msgdev);
              kfree(idev->stats.icmpv6dev);
              free_percpu(idev->stats.ipv6);
      }
      
      static void in6_dev_finish_destroy_rcu(struct rcu_head *head)
      {
              struct inet6_dev *idev = container_of(head, struct inet6_dev, rcu);
      
              snmp6_free_dev(idev);
              kfree(idev);
      }
      
      /* Nobody refers to this device, we may destroy it. */
      
      void in6_dev_finish_destroy(struct inet6_dev *idev)
      {
  372         struct net_device *dev = idev->dev;
      
              WARN_ON(!list_empty(&idev->addr_list));
  372         WARN_ON(idev->mc_list);
  372         WARN_ON(timer_pending(&idev->rs_timer));
      
      #ifdef NET_REFCNT_DEBUG
              pr_debug("%s: %s\n", __func__, dev ? dev->name : "NIL");
      #endif
  372         dev_put(dev);
              if (!idev->dead) {
                      pr_warn("Freeing alive inet6 device %p\n", idev);
                      return;
              }
  372         call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu);
      }
      EXPORT_SYMBOL(in6_dev_finish_destroy);
      // SPDX-License-Identifier: GPL-2.0
      /*
       * security/tomoyo/common.c
       *
       * Copyright (C) 2005-2011  NTT DATA CORPORATION
       */
      
      #include <linux/uaccess.h>
      #include <linux/slab.h>
      #include <linux/security.h>
      #include "common.h"
      
      /* String table for operation mode. */
      const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE] = {
              [TOMOYO_CONFIG_DISABLED]   = "disabled",
              [TOMOYO_CONFIG_LEARNING]   = "learning",
              [TOMOYO_CONFIG_PERMISSIVE] = "permissive",
              [TOMOYO_CONFIG_ENFORCING]  = "enforcing"
      };
      
      /* String table for /sys/kernel/security/tomoyo/profile */
      const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
                                             + TOMOYO_MAX_MAC_CATEGORY_INDEX] = {
              /* CONFIG::file group */
              [TOMOYO_MAC_FILE_EXECUTE]    = "execute",
              [TOMOYO_MAC_FILE_OPEN]       = "open",
              [TOMOYO_MAC_FILE_CREATE]     = "create",
              [TOMOYO_MAC_FILE_UNLINK]     = "unlink",
              [TOMOYO_MAC_FILE_GETATTR]    = "getattr",
              [TOMOYO_MAC_FILE_MKDIR]      = "mkdir",
              [TOMOYO_MAC_FILE_RMDIR]      = "rmdir",
              [TOMOYO_MAC_FILE_MKFIFO]     = "mkfifo",
              [TOMOYO_MAC_FILE_MKSOCK]     = "mksock",
              [TOMOYO_MAC_FILE_TRUNCATE]   = "truncate",
              [TOMOYO_MAC_FILE_SYMLINK]    = "symlink",
              [TOMOYO_MAC_FILE_MKBLOCK]    = "mkblock",
              [TOMOYO_MAC_FILE_MKCHAR]     = "mkchar",
              [TOMOYO_MAC_FILE_LINK]       = "link",
              [TOMOYO_MAC_FILE_RENAME]     = "rename",
              [TOMOYO_MAC_FILE_CHMOD]      = "chmod",
              [TOMOYO_MAC_FILE_CHOWN]      = "chown",
              [TOMOYO_MAC_FILE_CHGRP]      = "chgrp",
              [TOMOYO_MAC_FILE_IOCTL]      = "ioctl",
              [TOMOYO_MAC_FILE_CHROOT]     = "chroot",
              [TOMOYO_MAC_FILE_MOUNT]      = "mount",
              [TOMOYO_MAC_FILE_UMOUNT]     = "unmount",
              [TOMOYO_MAC_FILE_PIVOT_ROOT] = "pivot_root",
              /* CONFIG::network group */
              [TOMOYO_MAC_NETWORK_INET_STREAM_BIND]       = "inet_stream_bind",
              [TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN]     = "inet_stream_listen",
              [TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT]    = "inet_stream_connect",
              [TOMOYO_MAC_NETWORK_INET_DGRAM_BIND]        = "inet_dgram_bind",
              [TOMOYO_MAC_NETWORK_INET_DGRAM_SEND]        = "inet_dgram_send",
              [TOMOYO_MAC_NETWORK_INET_RAW_BIND]          = "inet_raw_bind",
              [TOMOYO_MAC_NETWORK_INET_RAW_SEND]          = "inet_raw_send",
              [TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND]       = "unix_stream_bind",
              [TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN]     = "unix_stream_listen",
              [TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT]    = "unix_stream_connect",
              [TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND]        = "unix_dgram_bind",
              [TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND]        = "unix_dgram_send",
              [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND]    = "unix_seqpacket_bind",
              [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN]  = "unix_seqpacket_listen",
              [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = "unix_seqpacket_connect",
              /* CONFIG::misc group */
              [TOMOYO_MAC_ENVIRON] = "env",
              /* CONFIG group */
              [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file",
              [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_NETWORK] = "network",
              [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_MISC] = "misc",
      };
      
      /* String table for conditions. */
      const char * const tomoyo_condition_keyword[TOMOYO_MAX_CONDITION_KEYWORD] = {
              [TOMOYO_TASK_UID]             = "task.uid",
              [TOMOYO_TASK_EUID]            = "task.euid",
              [TOMOYO_TASK_SUID]            = "task.suid",
              [TOMOYO_TASK_FSUID]           = "task.fsuid",
              [TOMOYO_TASK_GID]             = "task.gid",
              [TOMOYO_TASK_EGID]            = "task.egid",
              [TOMOYO_TASK_SGID]            = "task.sgid",
              [TOMOYO_TASK_FSGID]           = "task.fsgid",
              [TOMOYO_TASK_PID]             = "task.pid",
              [TOMOYO_TASK_PPID]            = "task.ppid",
              [TOMOYO_EXEC_ARGC]            = "exec.argc",
              [TOMOYO_EXEC_ENVC]            = "exec.envc",
              [TOMOYO_TYPE_IS_SOCKET]       = "socket",
              [TOMOYO_TYPE_IS_SYMLINK]      = "symlink",
              [TOMOYO_TYPE_IS_FILE]         = "file",
              [TOMOYO_TYPE_IS_BLOCK_DEV]    = "block",
              [TOMOYO_TYPE_IS_DIRECTORY]    = "directory",
              [TOMOYO_TYPE_IS_CHAR_DEV]     = "char",
              [TOMOYO_TYPE_IS_FIFO]         = "fifo",
              [TOMOYO_MODE_SETUID]          = "setuid",
              [TOMOYO_MODE_SETGID]          = "setgid",
              [TOMOYO_MODE_STICKY]          = "sticky",
              [TOMOYO_MODE_OWNER_READ]      = "owner_read",
              [TOMOYO_MODE_OWNER_WRITE]     = "owner_write",
              [TOMOYO_MODE_OWNER_EXECUTE]   = "owner_execute",
              [TOMOYO_MODE_GROUP_READ]      = "group_read",
              [TOMOYO_MODE_GROUP_WRITE]     = "group_write",
              [TOMOYO_MODE_GROUP_EXECUTE]   = "group_execute",
              [TOMOYO_MODE_OTHERS_READ]     = "others_read",
              [TOMOYO_MODE_OTHERS_WRITE]    = "others_write",
              [TOMOYO_MODE_OTHERS_EXECUTE]  = "others_execute",
              [TOMOYO_EXEC_REALPATH]        = "exec.realpath",
              [TOMOYO_SYMLINK_TARGET]       = "symlink.target",
              [TOMOYO_PATH1_UID]            = "path1.uid",
              [TOMOYO_PATH1_GID]            = "path1.gid",
              [TOMOYO_PATH1_INO]            = "path1.ino",
              [TOMOYO_PATH1_MAJOR]          = "path1.major",
              [TOMOYO_PATH1_MINOR]          = "path1.minor",
              [TOMOYO_PATH1_PERM]           = "path1.perm",
              [TOMOYO_PATH1_TYPE]           = "path1.type",
              [TOMOYO_PATH1_DEV_MAJOR]      = "path1.dev_major",
              [TOMOYO_PATH1_DEV_MINOR]      = "path1.dev_minor",
              [TOMOYO_PATH2_UID]            = "path2.uid",
              [TOMOYO_PATH2_GID]            = "path2.gid",
              [TOMOYO_PATH2_INO]            = "path2.ino",
              [TOMOYO_PATH2_MAJOR]          = "path2.major",
              [TOMOYO_PATH2_MINOR]          = "path2.minor",
              [TOMOYO_PATH2_PERM]           = "path2.perm",
              [TOMOYO_PATH2_TYPE]           = "path2.type",
              [TOMOYO_PATH2_DEV_MAJOR]      = "path2.dev_major",
              [TOMOYO_PATH2_DEV_MINOR]      = "path2.dev_minor",
              [TOMOYO_PATH1_PARENT_UID]     = "path1.parent.uid",
              [TOMOYO_PATH1_PARENT_GID]     = "path1.parent.gid",
              [TOMOYO_PATH1_PARENT_INO]     = "path1.parent.ino",
              [TOMOYO_PATH1_PARENT_PERM]    = "path1.parent.perm",
              [TOMOYO_PATH2_PARENT_UID]     = "path2.parent.uid",
              [TOMOYO_PATH2_PARENT_GID]     = "path2.parent.gid",
              [TOMOYO_PATH2_PARENT_INO]     = "path2.parent.ino",
              [TOMOYO_PATH2_PARENT_PERM]    = "path2.parent.perm",
      };
      
      /* String table for PREFERENCE keyword. */
      static const char * const tomoyo_pref_keywords[TOMOYO_MAX_PREF] = {
              [TOMOYO_PREF_MAX_AUDIT_LOG]      = "max_audit_log",
              [TOMOYO_PREF_MAX_LEARNING_ENTRY] = "max_learning_entry",
      };
      
      /* String table for path operation. */
      const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {
              [TOMOYO_TYPE_EXECUTE]    = "execute",
              [TOMOYO_TYPE_READ]       = "read",
              [TOMOYO_TYPE_WRITE]      = "write",
              [TOMOYO_TYPE_APPEND]     = "append",
              [TOMOYO_TYPE_UNLINK]     = "unlink",
              [TOMOYO_TYPE_GETATTR]    = "getattr",
              [TOMOYO_TYPE_RMDIR]      = "rmdir",
              [TOMOYO_TYPE_TRUNCATE]   = "truncate",
              [TOMOYO_TYPE_SYMLINK]    = "symlink",
              [TOMOYO_TYPE_CHROOT]     = "chroot",
              [TOMOYO_TYPE_UMOUNT]     = "unmount",
      };
      
      /* String table for socket's operation. */
      const char * const tomoyo_socket_keyword[TOMOYO_MAX_NETWORK_OPERATION] = {
              [TOMOYO_NETWORK_BIND]    = "bind",
              [TOMOYO_NETWORK_LISTEN]  = "listen",
              [TOMOYO_NETWORK_CONNECT] = "connect",
              [TOMOYO_NETWORK_SEND]    = "send",
      };
      
      /* String table for categories. */
      static const char * const tomoyo_category_keywords
      [TOMOYO_MAX_MAC_CATEGORY_INDEX] = {
              [TOMOYO_MAC_CATEGORY_FILE]    = "file",
              [TOMOYO_MAC_CATEGORY_NETWORK] = "network",
              [TOMOYO_MAC_CATEGORY_MISC]    = "misc",
      };
      
      /* Permit policy management by non-root user? */
      static bool tomoyo_manage_by_non_root;
      
      /* Utility functions. */
      
      /**
       * tomoyo_yesno - Return "yes" or "no".
       *
       * @value: Bool value.
       */
      const char *tomoyo_yesno(const unsigned int value)
      {
  212         return value ? "yes" : "no";
      }
      
      /**
       * tomoyo_addprintf - strncat()-like-snprintf().
       *
       * @buffer: Buffer to write to. Must be '\0'-terminated.
       * @len:    Size of @buffer.
       * @fmt:    The printf()'s format string, followed by parameters.
       *
       * Returns nothing.
       */
      static void tomoyo_addprintf(char *buffer, int len, const char *fmt, ...)
      {
              va_list args;
              const int pos = strlen(buffer);
      
              va_start(args, fmt);
              vsnprintf(buffer + pos, len - pos - 1, fmt, args);
              va_end(args);
      }
      
      /**
       * tomoyo_flush - Flush queued string to userspace's buffer.
       *
       * @head:   Pointer to "struct tomoyo_io_buffer".
       *
       * Returns true if all data was flushed, false otherwise.
       */
      static bool tomoyo_flush(struct tomoyo_io_buffer *head)
      {
              while (head->r.w_pos) {
                      const char *w = head->r.w[0];
                      size_t len = strlen(w);
      
                      if (len) {
                              if (len > head->read_user_buf_avail)
                                      len = head->read_user_buf_avail;
                              if (!len)
                                      return false;
                              if (copy_to_user(head->read_user_buf, w, len))
                                      return false;
                              head->read_user_buf_avail -= len;
                              head->read_user_buf += len;
                              w += len;
                      }
                      head->r.w[0] = w;
                      if (*w)
                              return false;
                      /* Add '\0' for audit logs and query. */
                      if (head->poll) {
                              if (!head->read_user_buf_avail ||
                                  copy_to_user(head->read_user_buf, "", 1))
                                      return false;
                              head->read_user_buf_avail--;
                              head->read_user_buf++;
                      }
                      head->r.w_pos--;
                      for (len = 0; len < head->r.w_pos; len++)
                              head->r.w[len] = head->r.w[len + 1];
              }
              head->r.avail = 0;
              return true;
      }
      
      /**
       * tomoyo_set_string - Queue string to "struct tomoyo_io_buffer" structure.
       *
       * @head:   Pointer to "struct tomoyo_io_buffer".
       * @string: String to print.
       *
       * Note that @string has to be kept valid until @head is kfree()d.
       * This means that char[] allocated on stack memory cannot be passed to
       * this function. Use tomoyo_io_printf() for char[] allocated on stack memory.
       */
      static void tomoyo_set_string(struct tomoyo_io_buffer *head, const char *string)
      {
              if (head->r.w_pos < TOMOYO_MAX_IO_READ_QUEUE) {
                      head->r.w[head->r.w_pos++] = string;
                      tomoyo_flush(head);
              } else
                      WARN_ON(1);
      }
      
      static void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt,
                                   ...) __printf(2, 3);
      
      /**
       * tomoyo_io_printf - printf() to "struct tomoyo_io_buffer" structure.
       *
       * @head: Pointer to "struct tomoyo_io_buffer".
       * @fmt:  The printf()'s format string, followed by parameters.
       */
      static void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt,
                                   ...)
      {
              va_list args;
              size_t len;
              size_t pos = head->r.avail;
              int size = head->readbuf_size - pos;
      
              if (size <= 0)
                      return;
              va_start(args, fmt);
              len = vsnprintf(head->read_buf + pos, size, fmt, args) + 1;
              va_end(args);
              if (pos + len >= head->readbuf_size) {
                      WARN_ON(1);
                      return;
              }
              head->r.avail += len;
              tomoyo_set_string(head, head->read_buf + pos);
      }
      
      /**
       * tomoyo_set_space - Put a space to "struct tomoyo_io_buffer" structure.
       *
       * @head: Pointer to "struct tomoyo_io_buffer".
       *
       * Returns nothing.
       */
      static void tomoyo_set_space(struct tomoyo_io_buffer *head)
      {
              tomoyo_set_string(head, " ");
      }
      
      /**
       * tomoyo_set_lf - Put a line feed to "struct tomoyo_io_buffer" structure.
       *
       * @head: Pointer to "struct tomoyo_io_buffer".
       *
       * Returns nothing.
       */
      static bool tomoyo_set_lf(struct tomoyo_io_buffer *head)
      {
              tomoyo_set_string(head, "\n");
              return !head->r.w_pos;
      }
      
      /**
       * tomoyo_set_slash - Put a shash to "struct tomoyo_io_buffer" structure.
       *
       * @head: Pointer to "struct tomoyo_io_buffer".
       *
       * Returns nothing.
       */
      static void tomoyo_set_slash(struct tomoyo_io_buffer *head)
      {
              tomoyo_set_string(head, "/");
      }
      
      /* List of namespaces. */
      LIST_HEAD(tomoyo_namespace_list);
      /* True if namespace other than tomoyo_kernel_namespace is defined. */
      static bool tomoyo_namespace_enabled;
      
      /**
       * tomoyo_init_policy_namespace - Initialize namespace.
       *
       * @ns: Pointer to "struct tomoyo_policy_namespace".
       *
       * Returns nothing.
       */
      void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns)
      {
              unsigned int idx;
      
              for (idx = 0; idx < TOMOYO_MAX_ACL_GROUPS; idx++)
                      INIT_LIST_HEAD(&ns->acl_group[idx]);
              for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++)
                      INIT_LIST_HEAD(&ns->group_list[idx]);
              for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++)
                      INIT_LIST_HEAD(&ns->policy_list[idx]);
              ns->profile_version = 20150505;
              tomoyo_namespace_enabled = !list_empty(&tomoyo_namespace_list);
              list_add_tail_rcu(&ns->namespace_list, &tomoyo_namespace_list);
      }
      
      /**
       * tomoyo_print_namespace - Print namespace header.
       *
       * @head: Pointer to "struct tomoyo_io_buffer".
       *
       * Returns nothing.
       */
      static void tomoyo_print_namespace(struct tomoyo_io_buffer *head)
      {
              if (!tomoyo_namespace_enabled)
                      return;
              tomoyo_set_string(head,
                                container_of(head->r.ns,
                                             struct tomoyo_policy_namespace,
                                             namespace_list)->name);
              tomoyo_set_space(head);
      }
      
      /**
       * tomoyo_print_name_union - Print a tomoyo_name_union.
       *
       * @head: Pointer to "struct tomoyo_io_buffer".
       * @ptr:  Pointer to "struct tomoyo_name_union".
       */
      static void tomoyo_print_name_union(struct tomoyo_io_buffer *head,
                                          const struct tomoyo_name_union *ptr)
      {
              tomoyo_set_space(head);
              if (ptr->group) {
                      tomoyo_set_string(head, "@");
                      tomoyo_set_string(head, ptr->group->group_name->name);
              } else {
                      tomoyo_set_string(head, ptr->filename->name);
              }
      }
      
      /**
       * tomoyo_print_name_union_quoted - Print a tomoyo_name_union with a quote.
       *
       * @head: Pointer to "struct tomoyo_io_buffer".
       * @ptr:  Pointer to "struct tomoyo_name_union".
       *
       * Returns nothing.
       */
      static void tomoyo_print_name_union_quoted(struct tomoyo_io_buffer *head,
                                                 const struct tomoyo_name_union *ptr)
      {
              if (ptr->group) {
                      tomoyo_set_string(head, "@");
                      tomoyo_set_string(head, ptr->group->group_name->name);
              } else {
                      tomoyo_set_string(head, "\"");
                      tomoyo_set_string(head, ptr->filename->name);
                      tomoyo_set_string(head, "\"");
              }
      }
      
      /**
       * tomoyo_print_number_union_nospace - Print a tomoyo_number_union without a space.
       *
       * @head: Pointer to "struct tomoyo_io_buffer".
       * @ptr:  Pointer to "struct tomoyo_number_union".
       *
       * Returns nothing.
       */
      static void tomoyo_print_number_union_nospace
      (struct tomoyo_io_buffer *head, const struct tomoyo_number_union *ptr)
      {
              if (ptr->group) {
                      tomoyo_set_string(head, "@");
                      tomoyo_set_string(head, ptr->group->group_name->name);
              } else {
                      int i;
                      unsigned long min = ptr->values[0];
                      const unsigned long max = ptr->values[1];
                      u8 min_type = ptr->value_type[0];
                      const u8 max_type = ptr->value_type[1];
                      char buffer[128];
      
                      buffer[0] = '\0';
                      for (i = 0; i < 2; i++) {
                              switch (min_type) {
                              case TOMOYO_VALUE_TYPE_HEXADECIMAL:
                                      tomoyo_addprintf(buffer, sizeof(buffer),
                                                       "0x%lX", min);
                                      break;
                              case TOMOYO_VALUE_TYPE_OCTAL:
                                      tomoyo_addprintf(buffer, sizeof(buffer),
                                                       "0%lo", min);
                                      break;
                              default:
                                      tomoyo_addprintf(buffer, sizeof(buffer), "%lu",
                                                       min);
                                      break;
                              }
                              if (min == max && min_type == max_type)
                                      break;
                              tomoyo_addprintf(buffer, sizeof(buffer), "-");
                              min_type = max_type;
                              min = max;
                      }
                      tomoyo_io_printf(head, "%s", buffer);
              }
      }
      
      /**
       * tomoyo_print_number_union - Print a tomoyo_number_union.
       *
       * @head: Pointer to "struct tomoyo_io_buffer".
       * @ptr:  Pointer to "struct tomoyo_number_union".
       *
       * Returns nothing.
       */
      static void tomoyo_print_number_union(struct tomoyo_io_buffer *head,
                                            const struct tomoyo_number_union *ptr)
      {
              tomoyo_set_space(head);
              tomoyo_print_number_union_nospace(head, ptr);
      }
      
      /**
       * tomoyo_assign_profile - Create a new profile.
       *
       * @ns:      Pointer to "struct tomoyo_policy_namespace".
       * @profile: Profile number to create.
       *
       * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise.
       */
      static struct tomoyo_profile *tomoyo_assign_profile
      (struct tomoyo_policy_namespace *ns, const unsigned int profile)
      {
              struct tomoyo_profile *ptr;
              struct tomoyo_profile *entry;
      
              if (profile >= TOMOYO_MAX_PROFILES)
                      return NULL;
              ptr = ns->profile_ptr[profile];
              if (ptr)
                      return ptr;
              entry = kzalloc(sizeof(*entry), GFP_NOFS);
              if (mutex_lock_interruptible(&tomoyo_policy_lock))
                      goto out;
              ptr = ns->profile_ptr[profile];
              if (!ptr && tomoyo_memory_ok(entry)) {
                      ptr = entry;
                      ptr->default_config = TOMOYO_CONFIG_DISABLED |
                              TOMOYO_CONFIG_WANT_GRANT_LOG |
                              TOMOYO_CONFIG_WANT_REJECT_LOG;
                      memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT,
                             sizeof(ptr->config));
                      ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] =
                              CONFIG_SECURITY_TOMOYO_MAX_AUDIT_LOG;
                      ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] =
                              CONFIG_SECURITY_TOMOYO_MAX_ACCEPT_ENTRY;
                      mb(); /* Avoid out-of-order execution. */
                      ns->profile_ptr[profile] = ptr;
                      entry = NULL;
              }
              mutex_unlock(&tomoyo_policy_lock);
       out:
              kfree(entry);
              return ptr;
      }
      
      /**
       * tomoyo_profile - Find a profile.
       *
       * @ns:      Pointer to "struct tomoyo_policy_namespace".
       * @profile: Profile number to find.
       *
       * Returns pointer to "struct tomoyo_profile".
       */
      struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns,
                                            const u8 profile)
      {
              static struct tomoyo_profile tomoyo_null_profile;
 4104         struct tomoyo_profile *ptr = ns->profile_ptr[profile];
      
              if (!ptr)
                      ptr = &tomoyo_null_profile;
 4104         return ptr;
      }
      
      /**
       * tomoyo_find_yesno - Find values for specified keyword.
       *
       * @string: String to check.
       * @find:   Name of keyword.
       *
       * Returns 1 if "@find=yes" was found, 0 if "@find=no" was found, -1 otherwise.
       */
      static s8 tomoyo_find_yesno(const char *string, const char *find)
      {
              const char *cp = strstr(string, find);
      
              if (cp) {
                      cp += strlen(find);
                      if (!strncmp(cp, "=yes", 4))
                              return 1;
                      else if (!strncmp(cp, "=no", 3))
                              return 0;
              }
              return -1;
      }
      
      /**
       * tomoyo_set_uint - Set value for specified preference.
       *
       * @i:      Pointer to "unsigned int".
       * @string: String to check.
       * @find:   Name of keyword.
       *
       * Returns nothing.
       */
      static void tomoyo_set_uint(unsigned int *i, const char *string,
                                  const char *find)
      {
              const char *cp = strstr(string, find);
      
              if (cp)
                      sscanf(cp + strlen(find), "=%u", i);
      }
      
      /**
       * tomoyo_set_mode - Set mode for specified profile.
       *
       * @name:    Name of functionality.
       * @value:   Mode for @name.
       * @profile: Pointer to "struct tomoyo_profile".
       *
       * Returns 0 on success, negative value otherwise.
       */
      static int tomoyo_set_mode(char *name, const char *value,
                                 struct tomoyo_profile *profile)
      {
              u8 i;
              u8 config;
      
              if (!strcmp(name, "CONFIG")) {
                      i = TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX;
                      config = profile->default_config;
              } else if (tomoyo_str_starts(&name, "CONFIG::")) {
                      config = 0;
                      for (i = 0; i < TOMOYO_MAX_MAC_INDEX
                                   + TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) {
                              int len = 0;
      
                              if (i < TOMOYO_MAX_MAC_INDEX) {
                                      const u8 c = tomoyo_index2category[i];
                                      const char *category =
                                              tomoyo_category_keywords[c];
      
                                      len = strlen(category);
                                      if (strncmp(name, category, len) ||
                                          name[len++] != ':' || name[len++] != ':')
                                              continue;
                              }
                              if (strcmp(name + len, tomoyo_mac_keywords[i]))
                                      continue;
                              config = profile->config[i];
                              break;
                      }
                      if (i == TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX)
                              return -EINVAL;
              } else {
                      return -EINVAL;
              }
              if (strstr(value, "use_default")) {
                      config = TOMOYO_CONFIG_USE_DEFAULT;
              } else {
                      u8 mode;
      
                      for (mode = 0; mode < 4; mode++)
                              if (strstr(value, tomoyo_mode[mode]))
                                      /*
                                       * Update lower 3 bits in order to distinguish
                                       * 'config' from 'TOMOYO_CONFIG_USE_DEAFULT'.
                                       */
                                      config = (config & ~7) | mode;
                      if (config != TOMOYO_CONFIG_USE_DEFAULT) {
                              switch (tomoyo_find_yesno(value, "grant_log")) {
                              case 1:
                                      config |= TOMOYO_CONFIG_WANT_GRANT_LOG;
                                      break;
                              case 0:
                                      config &= ~TOMOYO_CONFIG_WANT_GRANT_LOG;
                                      break;
                              }
                              switch (tomoyo_find_yesno(value, "reject_log")) {
                              case 1:
                                      config |= TOMOYO_CONFIG_WANT_REJECT_LOG;
                                      break;
                              case 0:
                                      config &= ~TOMOYO_CONFIG_WANT_REJECT_LOG;
                                      break;
                              }
                      }
              }
              if (i < TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX)
                      profile->config[i] = config;
              else if (config != TOMOYO_CONFIG_USE_DEFAULT)
                      profile->default_config = config;
              return 0;
      }
      
      /**
       * tomoyo_write_profile - Write profile table.
       *
       * @head: Pointer to "struct tomoyo_io_buffer".
       *
       * Returns 0 on success, negative value otherwise.
       */
      static int tomoyo_write_profile(struct tomoyo_io_buffer *head)
      {
              char *data = head->write_buf;
              unsigned int i;
              char *cp;
              struct tomoyo_profile *profile;
      
              if (sscanf(data, "PROFILE_VERSION=%u", &head->w.ns->profile_version)
                  == 1)
                      return 0;
              i = simple_strtoul(data, &cp, 10);
              if (*cp != '-')
                      return -EINVAL;
              data = cp + 1;
              profile = tomoyo_assign_profile(head->w.ns, i);
              if (!profile)
                      return -EINVAL;
              cp = strchr(data, '=');
              if (!cp)
                      return -EINVAL;
              *cp++ = '\0';
              if (!strcmp(data, "COMMENT")) {
                      static DEFINE_SPINLOCK(lock);
                      const struct tomoyo_path_info *new_comment
                              = tomoyo_get_name(cp);
                      const struct tomoyo_path_info *old_comment;
      
                      if (!new_comment)
                              return -ENOMEM;
                      spin_lock(&lock);
                      old_comment = profile->comment;
                      profile->comment = new_comment;
                      spin_unlock(&lock);
                      tomoyo_put_name(old_comment);
                      return 0;
              }
              if (!strcmp(data, "PREFERENCE")) {
                      for (i = 0; i < TOMOYO_MAX_PREF; i++)
                              tomoyo_set_uint(&profile->pref[i], cp,
                                              tomoyo_pref_keywords[i]);
                      return 0;
              }
              return tomoyo_set_mode(data, cp, profile);
      }
      
      /**
       * tomoyo_print_config - Print mode for specified functionality.
       *
       * @head:   Pointer to "struct tomoyo_io_buffer".
       * @config: Mode for that functionality.
       *
       * Returns nothing.
       *
       * Caller prints functionality's name.
       */
      static void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 config)
      {
              tomoyo_io_printf(head, "={ mode=%s grant_log=%s reject_log=%s }\n",
                               tomoyo_mode[config & 3],
                               tomoyo_yesno(config & TOMOYO_CONFIG_WANT_GRANT_LOG),
                               tomoyo_yesno(config & TOMOYO_CONFIG_WANT_REJECT_LOG));
      }
      
      /**
       * tomoyo_read_profile - Read profile table.
       *
       * @head: Pointer to "struct tomoyo_io_buffer".
       *
       * Returns nothing.
       */
      static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
      {
              u8 index;
              struct tomoyo_policy_namespace *ns =
                      container_of(head->r.ns, typeof(*ns), namespace_list);
              const struct tomoyo_profile *profile;
      
              if (head->r.eof)
                      return;
       next:
              index = head->r.index;
              profile = ns->profile_ptr[index];
              switch (head->r.step) {
              case 0:
                      tomoyo_print_namespace(head);
                      tomoyo_io_printf(head, "PROFILE_VERSION=%u\n",
                                       ns->profile_version);
                      head->r.step++;
                      break;
              case 1:
                      for ( ; head->r.index < TOMOYO_MAX_PROFILES;
                            head->r.index++)
                              if (ns->profile_ptr[head->r.index])
                                      break;
                      if (head->r.index == TOMOYO_MAX_PROFILES) {
                              head->r.eof = true;
                              return;
                      }
                      head->r.step++;
                      break;
              case 2:
                      {
                              u8 i;
                              const struct tomoyo_path_info *comment =
                                      profile->comment;
      
                              tomoyo_print_namespace(head);
                              tomoyo_io_printf(head, "%u-COMMENT=", index);
                              tomoyo_set_string(head, comment ? comment->name : "");
                              tomoyo_set_lf(head);
                              tomoyo_print_namespace(head);
                              tomoyo_io_printf(head, "%u-PREFERENCE={ ", index);
                              for (i = 0; i < TOMOYO_MAX_PREF; i++)
                                      tomoyo_io_printf(head, "%s=%u ",
                                                       tomoyo_pref_keywords[i],
                                                       profile->pref[i]);
                              tomoyo_set_string(head, "}\n");
                              head->r.step++;
                      }
                      break;
              case 3:
                      {
                              tomoyo_print_namespace(head);
                              tomoyo_io_printf(head, "%u-%s", index, "CONFIG");
                              tomoyo_print_config(head, profile->default_config);
                              head->r.bit = 0;
                              head->r.step++;
                      }
                      break;
              case 4:
                      for ( ; head->r.bit < TOMOYO_MAX_MAC_INDEX
                                    + TOMOYO_MAX_MAC_CATEGORY_INDEX; head->r.bit++) {
                              const u8 i = head->r.bit;
                              const u8 config = profile->config[i];
      
                              if (config == TOMOYO_CONFIG_USE_DEFAULT)
                                      continue;
                              tomoyo_print_namespace(head);
                              if (i < TOMOYO_MAX_MAC_INDEX)
                                      tomoyo_io_printf(head, "%u-CONFIG::%s::%s",
                                                       index,
                                                       tomoyo_category_keywords
                                                       [tomoyo_index2category[i]],
                                                       tomoyo_mac_keywords[i]);
                              else
                                      tomoyo_io_printf(head, "%u-CONFIG::%s", index,
                                                       tomoyo_mac_keywords[i]);
                              tomoyo_print_config(head, config);
                              head->r.bit++;
                              break;
                      }
                      if (head->r.bit == TOMOYO_MAX_MAC_INDEX
                          + TOMOYO_MAX_MAC_CATEGORY_INDEX) {
                              head->r.index++;
                              head->r.step = 1;
                      }
                      break;
              }