Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Network node table
0004  *
0005  * SELinux must keep a mapping of network nodes to labels/SIDs.  This
0006  * mapping is maintained as part of the normal policy but a fast cache is
0007  * needed to reduce the lookup overhead since most of these queries happen on
0008  * a per-packet basis.
0009  *
0010  * Author: Paul Moore <paul@paul-moore.com>
0011  *
0012  * This code is heavily based on the "netif" concept originally developed by
0013  * James Morris <jmorris@redhat.com>
0014  *   (see security/selinux/netif.c for more information)
0015  */
0016 
0017 /*
0018  * (c) Copyright Hewlett-Packard Development Company, L.P., 2007
0019  */
0020 
0021 #include <linux/types.h>
0022 #include <linux/rcupdate.h>
0023 #include <linux/list.h>
0024 #include <linux/slab.h>
0025 #include <linux/spinlock.h>
0026 #include <linux/in.h>
0027 #include <linux/in6.h>
0028 #include <linux/ip.h>
0029 #include <linux/ipv6.h>
0030 #include <net/ip.h>
0031 #include <net/ipv6.h>
0032 
0033 #include "netnode.h"
0034 #include "objsec.h"
0035 
0036 #define SEL_NETNODE_HASH_SIZE       256
0037 #define SEL_NETNODE_HASH_BKT_LIMIT   16
0038 
0039 struct sel_netnode_bkt {
0040     unsigned int size;
0041     struct list_head list;
0042 };
0043 
0044 struct sel_netnode {
0045     struct netnode_security_struct nsec;
0046 
0047     struct list_head list;
0048     struct rcu_head rcu;
0049 };
0050 
0051 /* NOTE: we are using a combined hash table for both IPv4 and IPv6, the reason
0052  * for this is that I suspect most users will not make heavy use of both
0053  * address families at the same time so one table will usually end up wasted,
0054  * if this becomes a problem we can always add a hash table for each address
0055  * family later */
0056 
0057 static DEFINE_SPINLOCK(sel_netnode_lock);
0058 static struct sel_netnode_bkt sel_netnode_hash[SEL_NETNODE_HASH_SIZE];
0059 
0060 /**
0061  * sel_netnode_hashfn_ipv4 - IPv4 hashing function for the node table
0062  * @addr: IPv4 address
0063  *
0064  * Description:
0065  * This is the IPv4 hashing function for the node interface table, it returns
0066  * the bucket number for the given IP address.
0067  *
0068  */
0069 static unsigned int sel_netnode_hashfn_ipv4(__be32 addr)
0070 {
0071     /* at some point we should determine if the mismatch in byte order
0072      * affects the hash function dramatically */
0073     return (addr & (SEL_NETNODE_HASH_SIZE - 1));
0074 }
0075 
0076 /**
0077  * sel_netnode_hashfn_ipv6 - IPv6 hashing function for the node table
0078  * @addr: IPv6 address
0079  *
0080  * Description:
0081  * This is the IPv6 hashing function for the node interface table, it returns
0082  * the bucket number for the given IP address.
0083  *
0084  */
0085 static unsigned int sel_netnode_hashfn_ipv6(const struct in6_addr *addr)
0086 {
0087     /* just hash the least significant 32 bits to keep things fast (they
0088      * are the most likely to be different anyway), we can revisit this
0089      * later if needed */
0090     return (addr->s6_addr32[3] & (SEL_NETNODE_HASH_SIZE - 1));
0091 }
0092 
0093 /**
0094  * sel_netnode_find - Search for a node record
0095  * @addr: IP address
0096  * @family: address family
0097  *
0098  * Description:
0099  * Search the network node table and return the record matching @addr.  If an
0100  * entry can not be found in the table return NULL.
0101  *
0102  */
0103 static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)
0104 {
0105     unsigned int idx;
0106     struct sel_netnode *node;
0107 
0108     switch (family) {
0109     case PF_INET:
0110         idx = sel_netnode_hashfn_ipv4(*(const __be32 *)addr);
0111         break;
0112     case PF_INET6:
0113         idx = sel_netnode_hashfn_ipv6(addr);
0114         break;
0115     default:
0116         BUG();
0117         return NULL;
0118     }
0119 
0120     list_for_each_entry_rcu(node, &sel_netnode_hash[idx].list, list)
0121         if (node->nsec.family == family)
0122             switch (family) {
0123             case PF_INET:
0124                 if (node->nsec.addr.ipv4 == *(const __be32 *)addr)
0125                     return node;
0126                 break;
0127             case PF_INET6:
0128                 if (ipv6_addr_equal(&node->nsec.addr.ipv6,
0129                             addr))
0130                     return node;
0131                 break;
0132             }
0133 
0134     return NULL;
0135 }
0136 
0137 /**
0138  * sel_netnode_insert - Insert a new node into the table
0139  * @node: the new node record
0140  *
0141  * Description:
0142  * Add a new node record to the network address hash table.
0143  *
0144  */
0145 static void sel_netnode_insert(struct sel_netnode *node)
0146 {
0147     unsigned int idx;
0148 
0149     switch (node->nsec.family) {
0150     case PF_INET:
0151         idx = sel_netnode_hashfn_ipv4(node->nsec.addr.ipv4);
0152         break;
0153     case PF_INET6:
0154         idx = sel_netnode_hashfn_ipv6(&node->nsec.addr.ipv6);
0155         break;
0156     default:
0157         BUG();
0158         return;
0159     }
0160 
0161     /* we need to impose a limit on the growth of the hash table so check
0162      * this bucket to make sure it is within the specified bounds */
0163     list_add_rcu(&node->list, &sel_netnode_hash[idx].list);
0164     if (sel_netnode_hash[idx].size == SEL_NETNODE_HASH_BKT_LIMIT) {
0165         struct sel_netnode *tail;
0166         tail = list_entry(
0167             rcu_dereference_protected(
0168                 list_tail_rcu(&sel_netnode_hash[idx].list),
0169                 lockdep_is_held(&sel_netnode_lock)),
0170             struct sel_netnode, list);
0171         list_del_rcu(&tail->list);
0172         kfree_rcu(tail, rcu);
0173     } else
0174         sel_netnode_hash[idx].size++;
0175 }
0176 
0177 /**
0178  * sel_netnode_sid_slow - Lookup the SID of a network address using the policy
0179  * @addr: the IP address
0180  * @family: the address family
0181  * @sid: node SID
0182  *
0183  * Description:
0184  * This function determines the SID of a network address by querying the
0185  * security policy.  The result is added to the network address table to
0186  * speedup future queries.  Returns zero on success, negative values on
0187  * failure.
0188  *
0189  */
0190 static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid)
0191 {
0192     int ret;
0193     struct sel_netnode *node;
0194     struct sel_netnode *new;
0195 
0196     spin_lock_bh(&sel_netnode_lock);
0197     node = sel_netnode_find(addr, family);
0198     if (node != NULL) {
0199         *sid = node->nsec.sid;
0200         spin_unlock_bh(&sel_netnode_lock);
0201         return 0;
0202     }
0203 
0204     new = kzalloc(sizeof(*new), GFP_ATOMIC);
0205     switch (family) {
0206     case PF_INET:
0207         ret = security_node_sid(&selinux_state, PF_INET,
0208                     addr, sizeof(struct in_addr), sid);
0209         if (new)
0210             new->nsec.addr.ipv4 = *(__be32 *)addr;
0211         break;
0212     case PF_INET6:
0213         ret = security_node_sid(&selinux_state, PF_INET6,
0214                     addr, sizeof(struct in6_addr), sid);
0215         if (new)
0216             new->nsec.addr.ipv6 = *(struct in6_addr *)addr;
0217         break;
0218     default:
0219         BUG();
0220         ret = -EINVAL;
0221     }
0222     if (ret == 0 && new) {
0223         new->nsec.family = family;
0224         new->nsec.sid = *sid;
0225         sel_netnode_insert(new);
0226     } else
0227         kfree(new);
0228 
0229     spin_unlock_bh(&sel_netnode_lock);
0230     if (unlikely(ret))
0231         pr_warn("SELinux: failure in %s(), unable to determine network node label\n",
0232             __func__);
0233     return ret;
0234 }
0235 
0236 /**
0237  * sel_netnode_sid - Lookup the SID of a network address
0238  * @addr: the IP address
0239  * @family: the address family
0240  * @sid: node SID
0241  *
0242  * Description:
0243  * This function determines the SID of a network address using the fastest
0244  * method possible.  First the address table is queried, but if an entry
0245  * can't be found then the policy is queried and the result is added to the
0246  * table to speedup future queries.  Returns zero on success, negative values
0247  * on failure.
0248  *
0249  */
0250 int sel_netnode_sid(void *addr, u16 family, u32 *sid)
0251 {
0252     struct sel_netnode *node;
0253 
0254     rcu_read_lock();
0255     node = sel_netnode_find(addr, family);
0256     if (node != NULL) {
0257         *sid = node->nsec.sid;
0258         rcu_read_unlock();
0259         return 0;
0260     }
0261     rcu_read_unlock();
0262 
0263     return sel_netnode_sid_slow(addr, family, sid);
0264 }
0265 
0266 /**
0267  * sel_netnode_flush - Flush the entire network address table
0268  *
0269  * Description:
0270  * Remove all entries from the network address table.
0271  *
0272  */
0273 void sel_netnode_flush(void)
0274 {
0275     unsigned int idx;
0276     struct sel_netnode *node, *node_tmp;
0277 
0278     spin_lock_bh(&sel_netnode_lock);
0279     for (idx = 0; idx < SEL_NETNODE_HASH_SIZE; idx++) {
0280         list_for_each_entry_safe(node, node_tmp,
0281                      &sel_netnode_hash[idx].list, list) {
0282                 list_del_rcu(&node->list);
0283                 kfree_rcu(node, rcu);
0284         }
0285         sel_netnode_hash[idx].size = 0;
0286     }
0287     spin_unlock_bh(&sel_netnode_lock);
0288 }
0289 
0290 static __init int sel_netnode_init(void)
0291 {
0292     int iter;
0293 
0294     if (!selinux_enabled_boot)
0295         return 0;
0296 
0297     for (iter = 0; iter < SEL_NETNODE_HASH_SIZE; iter++) {
0298         INIT_LIST_HEAD(&sel_netnode_hash[iter].list);
0299         sel_netnode_hash[iter].size = 0;
0300     }
0301 
0302     return 0;
0303 }
0304 
0305 __initcall(sel_netnode_init);