Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Network port table
0004  *
0005  * SELinux must keep a mapping of network ports 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.
0008  *
0009  * Author: Paul Moore <paul@paul-moore.com>
0010  *
0011  * This code is heavily based on the "netif" concept originally developed by
0012  * James Morris <jmorris@redhat.com>
0013  *   (see security/selinux/netif.c for more information)
0014  */
0015 
0016 /*
0017  * (c) Copyright Hewlett-Packard Development Company, L.P., 2008
0018  */
0019 
0020 #include <linux/types.h>
0021 #include <linux/rcupdate.h>
0022 #include <linux/list.h>
0023 #include <linux/slab.h>
0024 #include <linux/spinlock.h>
0025 #include <linux/in.h>
0026 #include <linux/in6.h>
0027 #include <linux/ip.h>
0028 #include <linux/ipv6.h>
0029 #include <net/ip.h>
0030 #include <net/ipv6.h>
0031 
0032 #include "netport.h"
0033 #include "objsec.h"
0034 
0035 #define SEL_NETPORT_HASH_SIZE       256
0036 #define SEL_NETPORT_HASH_BKT_LIMIT   16
0037 
0038 struct sel_netport_bkt {
0039     int size;
0040     struct list_head list;
0041 };
0042 
0043 struct sel_netport {
0044     struct netport_security_struct psec;
0045 
0046     struct list_head list;
0047     struct rcu_head rcu;
0048 };
0049 
0050 /* NOTE: we are using a combined hash table for both IPv4 and IPv6, the reason
0051  * for this is that I suspect most users will not make heavy use of both
0052  * address families at the same time so one table will usually end up wasted,
0053  * if this becomes a problem we can always add a hash table for each address
0054  * family later */
0055 
0056 static DEFINE_SPINLOCK(sel_netport_lock);
0057 static struct sel_netport_bkt sel_netport_hash[SEL_NETPORT_HASH_SIZE];
0058 
0059 /**
0060  * sel_netport_hashfn - Hashing function for the port table
0061  * @pnum: port number
0062  *
0063  * Description:
0064  * This is the hashing function for the port table, it returns the bucket
0065  * number for the given port.
0066  *
0067  */
0068 static unsigned int sel_netport_hashfn(u16 pnum)
0069 {
0070     return (pnum & (SEL_NETPORT_HASH_SIZE - 1));
0071 }
0072 
0073 /**
0074  * sel_netport_find - Search for a port record
0075  * @protocol: protocol
0076  * @pnum: port
0077  *
0078  * Description:
0079  * Search the network port table and return the matching record.  If an entry
0080  * can not be found in the table return NULL.
0081  *
0082  */
0083 static struct sel_netport *sel_netport_find(u8 protocol, u16 pnum)
0084 {
0085     unsigned int idx;
0086     struct sel_netport *port;
0087 
0088     idx = sel_netport_hashfn(pnum);
0089     list_for_each_entry_rcu(port, &sel_netport_hash[idx].list, list)
0090         if (port->psec.port == pnum && port->psec.protocol == protocol)
0091             return port;
0092 
0093     return NULL;
0094 }
0095 
0096 /**
0097  * sel_netport_insert - Insert a new port into the table
0098  * @port: the new port record
0099  *
0100  * Description:
0101  * Add a new port record to the network address hash table.
0102  *
0103  */
0104 static void sel_netport_insert(struct sel_netport *port)
0105 {
0106     unsigned int idx;
0107 
0108     /* we need to impose a limit on the growth of the hash table so check
0109      * this bucket to make sure it is within the specified bounds */
0110     idx = sel_netport_hashfn(port->psec.port);
0111     list_add_rcu(&port->list, &sel_netport_hash[idx].list);
0112     if (sel_netport_hash[idx].size == SEL_NETPORT_HASH_BKT_LIMIT) {
0113         struct sel_netport *tail;
0114         tail = list_entry(
0115             rcu_dereference_protected(
0116                 list_tail_rcu(&sel_netport_hash[idx].list),
0117                 lockdep_is_held(&sel_netport_lock)),
0118             struct sel_netport, list);
0119         list_del_rcu(&tail->list);
0120         kfree_rcu(tail, rcu);
0121     } else
0122         sel_netport_hash[idx].size++;
0123 }
0124 
0125 /**
0126  * sel_netport_sid_slow - Lookup the SID of a network address using the policy
0127  * @protocol: protocol
0128  * @pnum: port
0129  * @sid: port SID
0130  *
0131  * Description:
0132  * This function determines the SID of a network port by querying the security
0133  * policy.  The result is added to the network port table to speedup future
0134  * queries.  Returns zero on success, negative values on failure.
0135  *
0136  */
0137 static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid)
0138 {
0139     int ret;
0140     struct sel_netport *port;
0141     struct sel_netport *new;
0142 
0143     spin_lock_bh(&sel_netport_lock);
0144     port = sel_netport_find(protocol, pnum);
0145     if (port != NULL) {
0146         *sid = port->psec.sid;
0147         spin_unlock_bh(&sel_netport_lock);
0148         return 0;
0149     }
0150 
0151     ret = security_port_sid(&selinux_state, protocol, pnum, sid);
0152     if (ret != 0)
0153         goto out;
0154     new = kzalloc(sizeof(*new), GFP_ATOMIC);
0155     if (new) {
0156         new->psec.port = pnum;
0157         new->psec.protocol = protocol;
0158         new->psec.sid = *sid;
0159         sel_netport_insert(new);
0160     }
0161 
0162 out:
0163     spin_unlock_bh(&sel_netport_lock);
0164     if (unlikely(ret))
0165         pr_warn("SELinux: failure in %s(), unable to determine network port label\n",
0166             __func__);
0167     return ret;
0168 }
0169 
0170 /**
0171  * sel_netport_sid - Lookup the SID of a network port
0172  * @protocol: protocol
0173  * @pnum: port
0174  * @sid: port SID
0175  *
0176  * Description:
0177  * This function determines the SID of a network port using the fastest method
0178  * possible.  First the port table is queried, but if an entry can't be found
0179  * then the policy is queried and the result is added to the table to speedup
0180  * future queries.  Returns zero on success, negative values on failure.
0181  *
0182  */
0183 int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid)
0184 {
0185     struct sel_netport *port;
0186 
0187     rcu_read_lock();
0188     port = sel_netport_find(protocol, pnum);
0189     if (port != NULL) {
0190         *sid = port->psec.sid;
0191         rcu_read_unlock();
0192         return 0;
0193     }
0194     rcu_read_unlock();
0195 
0196     return sel_netport_sid_slow(protocol, pnum, sid);
0197 }
0198 
0199 /**
0200  * sel_netport_flush - Flush the entire network port table
0201  *
0202  * Description:
0203  * Remove all entries from the network address table.
0204  *
0205  */
0206 void sel_netport_flush(void)
0207 {
0208     unsigned int idx;
0209     struct sel_netport *port, *port_tmp;
0210 
0211     spin_lock_bh(&sel_netport_lock);
0212     for (idx = 0; idx < SEL_NETPORT_HASH_SIZE; idx++) {
0213         list_for_each_entry_safe(port, port_tmp,
0214                      &sel_netport_hash[idx].list, list) {
0215             list_del_rcu(&port->list);
0216             kfree_rcu(port, rcu);
0217         }
0218         sel_netport_hash[idx].size = 0;
0219     }
0220     spin_unlock_bh(&sel_netport_lock);
0221 }
0222 
0223 static __init int sel_netport_init(void)
0224 {
0225     int iter;
0226 
0227     if (!selinux_enabled_boot)
0228         return 0;
0229 
0230     for (iter = 0; iter < SEL_NETPORT_HASH_SIZE; iter++) {
0231         INIT_LIST_HEAD(&sel_netport_hash[iter].list);
0232         sel_netport_hash[iter].size = 0;
0233     }
0234 
0235     return 0;
0236 }
0237 
0238 __initcall(sel_netport_init);