Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.0 251 lines 6.4 kB view raw
1/* 2 * Network port table 3 * 4 * SELinux must keep a mapping of network ports to labels/SIDs. This 5 * mapping is maintained as part of the normal policy but a fast cache is 6 * needed to reduce the lookup overhead. 7 * 8 * Author: Paul Moore <paul@paul-moore.com> 9 * 10 * This code is heavily based on the "netif" concept originally developed by 11 * James Morris <jmorris@redhat.com> 12 * (see security/selinux/netif.c for more information) 13 * 14 */ 15 16/* 17 * (c) Copyright Hewlett-Packard Development Company, L.P., 2008 18 * 19 * This program is free software: you can redistribute it and/or modify 20 * it under the terms of version 2 of the GNU General Public License as 21 * published by the Free Software Foundation. 22 * 23 * This program is distributed in the hope that it will be useful, 24 * but WITHOUT ANY WARRANTY; without even the implied warranty of 25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 * GNU General Public License for more details. 27 * 28 */ 29 30#include <linux/types.h> 31#include <linux/rcupdate.h> 32#include <linux/list.h> 33#include <linux/slab.h> 34#include <linux/spinlock.h> 35#include <linux/in.h> 36#include <linux/in6.h> 37#include <linux/ip.h> 38#include <linux/ipv6.h> 39#include <net/ip.h> 40#include <net/ipv6.h> 41 42#include "netport.h" 43#include "objsec.h" 44 45#define SEL_NETPORT_HASH_SIZE 256 46#define SEL_NETPORT_HASH_BKT_LIMIT 16 47 48struct sel_netport_bkt { 49 int size; 50 struct list_head list; 51}; 52 53struct sel_netport { 54 struct netport_security_struct psec; 55 56 struct list_head list; 57 struct rcu_head rcu; 58}; 59 60/* NOTE: we are using a combined hash table for both IPv4 and IPv6, the reason 61 * for this is that I suspect most users will not make heavy use of both 62 * address families at the same time so one table will usually end up wasted, 63 * if this becomes a problem we can always add a hash table for each address 64 * family later */ 65 66static LIST_HEAD(sel_netport_list); 67static DEFINE_SPINLOCK(sel_netport_lock); 68static struct sel_netport_bkt sel_netport_hash[SEL_NETPORT_HASH_SIZE]; 69 70/** 71 * sel_netport_hashfn - Hashing function for the port table 72 * @pnum: port number 73 * 74 * Description: 75 * This is the hashing function for the port table, it returns the bucket 76 * number for the given port. 77 * 78 */ 79static unsigned int sel_netport_hashfn(u16 pnum) 80{ 81 return (pnum & (SEL_NETPORT_HASH_SIZE - 1)); 82} 83 84/** 85 * sel_netport_find - Search for a port record 86 * @protocol: protocol 87 * @port: pnum 88 * 89 * Description: 90 * Search the network port table and return the matching record. If an entry 91 * can not be found in the table return NULL. 92 * 93 */ 94static struct sel_netport *sel_netport_find(u8 protocol, u16 pnum) 95{ 96 unsigned int idx; 97 struct sel_netport *port; 98 99 idx = sel_netport_hashfn(pnum); 100 list_for_each_entry_rcu(port, &sel_netport_hash[idx].list, list) 101 if (port->psec.port == pnum && port->psec.protocol == protocol) 102 return port; 103 104 return NULL; 105} 106 107/** 108 * sel_netport_insert - Insert a new port into the table 109 * @port: the new port record 110 * 111 * Description: 112 * Add a new port record to the network address hash table. 113 * 114 */ 115static void sel_netport_insert(struct sel_netport *port) 116{ 117 unsigned int idx; 118 119 /* we need to impose a limit on the growth of the hash table so check 120 * this bucket to make sure it is within the specified bounds */ 121 idx = sel_netport_hashfn(port->psec.port); 122 list_add_rcu(&port->list, &sel_netport_hash[idx].list); 123 if (sel_netport_hash[idx].size == SEL_NETPORT_HASH_BKT_LIMIT) { 124 struct sel_netport *tail; 125 tail = list_entry( 126 rcu_dereference_protected( 127 sel_netport_hash[idx].list.prev, 128 lockdep_is_held(&sel_netport_lock)), 129 struct sel_netport, list); 130 list_del_rcu(&tail->list); 131 kfree_rcu(tail, rcu); 132 } else 133 sel_netport_hash[idx].size++; 134} 135 136/** 137 * sel_netport_sid_slow - Lookup the SID of a network address using the policy 138 * @protocol: protocol 139 * @pnum: port 140 * @sid: port SID 141 * 142 * Description: 143 * This function determines the SID of a network port by quering the security 144 * policy. The result is added to the network port table to speedup future 145 * queries. Returns zero on success, negative values on failure. 146 * 147 */ 148static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid) 149{ 150 int ret = -ENOMEM; 151 struct sel_netport *port; 152 struct sel_netport *new = NULL; 153 154 spin_lock_bh(&sel_netport_lock); 155 port = sel_netport_find(protocol, pnum); 156 if (port != NULL) { 157 *sid = port->psec.sid; 158 spin_unlock_bh(&sel_netport_lock); 159 return 0; 160 } 161 new = kzalloc(sizeof(*new), GFP_ATOMIC); 162 if (new == NULL) 163 goto out; 164 ret = security_port_sid(&selinux_state, protocol, pnum, sid); 165 if (ret != 0) 166 goto out; 167 168 new->psec.port = pnum; 169 new->psec.protocol = protocol; 170 new->psec.sid = *sid; 171 sel_netport_insert(new); 172 173out: 174 spin_unlock_bh(&sel_netport_lock); 175 if (unlikely(ret)) { 176 pr_warn("SELinux: failure in %s(), unable to determine network port label\n", 177 __func__); 178 kfree(new); 179 } 180 return ret; 181} 182 183/** 184 * sel_netport_sid - Lookup the SID of a network port 185 * @protocol: protocol 186 * @pnum: port 187 * @sid: port SID 188 * 189 * Description: 190 * This function determines the SID of a network port using the fastest method 191 * possible. First the port table is queried, but if an entry can't be found 192 * then the policy is queried and the result is added to the table to speedup 193 * future queries. Returns zero on success, negative values on failure. 194 * 195 */ 196int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid) 197{ 198 struct sel_netport *port; 199 200 rcu_read_lock(); 201 port = sel_netport_find(protocol, pnum); 202 if (port != NULL) { 203 *sid = port->psec.sid; 204 rcu_read_unlock(); 205 return 0; 206 } 207 rcu_read_unlock(); 208 209 return sel_netport_sid_slow(protocol, pnum, sid); 210} 211 212/** 213 * sel_netport_flush - Flush the entire network port table 214 * 215 * Description: 216 * Remove all entries from the network address table. 217 * 218 */ 219void sel_netport_flush(void) 220{ 221 unsigned int idx; 222 struct sel_netport *port, *port_tmp; 223 224 spin_lock_bh(&sel_netport_lock); 225 for (idx = 0; idx < SEL_NETPORT_HASH_SIZE; idx++) { 226 list_for_each_entry_safe(port, port_tmp, 227 &sel_netport_hash[idx].list, list) { 228 list_del_rcu(&port->list); 229 kfree_rcu(port, rcu); 230 } 231 sel_netport_hash[idx].size = 0; 232 } 233 spin_unlock_bh(&sel_netport_lock); 234} 235 236static __init int sel_netport_init(void) 237{ 238 int iter; 239 240 if (!selinux_enabled) 241 return 0; 242 243 for (iter = 0; iter < SEL_NETPORT_HASH_SIZE; iter++) { 244 INIT_LIST_HEAD(&sel_netport_hash[iter].list); 245 sel_netport_hash[iter].size = 0; 246 } 247 248 return 0; 249} 250 251__initcall(sel_netport_init);