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.moore@hp.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/spinlock.h> 34 #include <linux/in.h> 35 #include <linux/in6.h> 36 #include <linux/ip.h> 37 #include <linux/ipv6.h> 38 #include <net/ip.h> 39 #include <net/ipv6.h> 40 #include <asm/bug.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 48 struct sel_netport_bkt { 49 int size; 50 struct list_head list; 51 }; 52 53 struct 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 66 static LIST_HEAD(sel_netport_list); 67 static DEFINE_SPINLOCK(sel_netport_lock); 68 static struct sel_netport_bkt sel_netport_hash[SEL_NETPORT_HASH_SIZE]; 69 70 /** 71 * sel_netport_free - Frees a port entry 72 * @p: the entry's RCU field 73 * 74 * Description: 75 * This function is designed to be used as a callback to the call_rcu() 76 * function so that memory allocated to a hash table port entry can be 77 * released safely. 78 * 79 */ 80 static void sel_netport_free(struct rcu_head *p) 81 { 82 struct sel_netport *port = container_of(p, struct sel_netport, rcu); 83 kfree(port); 84 } 85 86 /** 87 * sel_netport_hashfn - Hashing function for the port table 88 * @pnum: port number 89 * 90 * Description: 91 * This is the hashing function for the port table, it returns the bucket 92 * number for the given port. 93 * 94 */ 95 static unsigned int sel_netport_hashfn(u16 pnum) 96 { 97 return (pnum & (SEL_NETPORT_HASH_SIZE - 1)); 98 } 99 100 /** 101 * sel_netport_find - Search for a port record 102 * @protocol: protocol 103 * @port: pnum 104 * 105 * Description: 106 * Search the network port table and return the matching record. If an entry 107 * can not be found in the table return NULL. 108 * 109 */ 110 static struct sel_netport *sel_netport_find(u8 protocol, u16 pnum) 111 { 112 unsigned int idx; 113 struct sel_netport *port; 114 115 idx = sel_netport_hashfn(pnum); 116 list_for_each_entry_rcu(port, &sel_netport_hash[idx].list, list) 117 if (port->psec.port == pnum && 118 port->psec.protocol == protocol) 119 return port; 120 121 return NULL; 122 } 123 124 /** 125 * sel_netport_insert - Insert a new port into the table 126 * @port: the new port record 127 * 128 * Description: 129 * Add a new port record to the network address hash table. Returns zero on 130 * success, negative values on failure. 131 * 132 */ 133 static int sel_netport_insert(struct sel_netport *port) 134 { 135 unsigned int idx; 136 137 /* we need to impose a limit on the growth of the hash table so check 138 * this bucket to make sure it is within the specified bounds */ 139 idx = sel_netport_hashfn(port->psec.port); 140 list_add_rcu(&port->list, &sel_netport_hash[idx].list); 141 if (sel_netport_hash[idx].size == SEL_NETPORT_HASH_BKT_LIMIT) { 142 struct sel_netport *tail; 143 tail = list_entry(port->list.prev, struct sel_netport, list); 144 list_del_rcu(port->list.prev); 145 call_rcu(&tail->rcu, sel_netport_free); 146 } else 147 sel_netport_hash[idx].size++; 148 149 return 0; 150 } 151 152 /** 153 * sel_netport_sid_slow - Lookup the SID of a network address using the policy 154 * @protocol: protocol 155 * @pnum: port 156 * @sid: port SID 157 * 158 * Description: 159 * This function determines the SID of a network port by quering the security 160 * policy. The result is added to the network port table to speedup future 161 * queries. Returns zero on success, negative values on failure. 162 * 163 */ 164 static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid) 165 { 166 int ret; 167 struct sel_netport *port; 168 struct sel_netport *new = NULL; 169 170 spin_lock_bh(&sel_netport_lock); 171 port = sel_netport_find(protocol, pnum); 172 if (port != NULL) { 173 *sid = port->psec.sid; 174 ret = 0; 175 goto out; 176 } 177 new = kzalloc(sizeof(*new), GFP_ATOMIC); 178 if (new == NULL) { 179 ret = -ENOMEM; 180 goto out; 181 } 182 ret = security_port_sid(protocol, pnum, &new->psec.sid); 183 if (ret != 0) 184 goto out; 185 new->psec.port = pnum; 186 new->psec.protocol = protocol; 187 ret = sel_netport_insert(new); 188 if (ret != 0) 189 goto out; 190 *sid = new->psec.sid; 191 192 out: 193 spin_unlock_bh(&sel_netport_lock); 194 if (unlikely(ret)) { 195 printk(KERN_WARNING 196 "SELinux: failure in sel_netport_sid_slow()," 197 " unable to determine network port label\n"); 198 kfree(new); 199 } 200 return ret; 201 } 202 203 /** 204 * sel_netport_sid - Lookup the SID of a network port 205 * @protocol: protocol 206 * @pnum: port 207 * @sid: port SID 208 * 209 * Description: 210 * This function determines the SID of a network port using the fastest method 211 * possible. First the port table is queried, but if an entry can't be found 212 * then the policy is queried and the result is added to the table to speedup 213 * future queries. Returns zero on success, negative values on failure. 214 * 215 */ 216 int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid) 217 { 218 struct sel_netport *port; 219 220 rcu_read_lock(); 221 port = sel_netport_find(protocol, pnum); 222 if (port != NULL) { 223 *sid = port->psec.sid; 224 rcu_read_unlock(); 225 return 0; 226 } 227 rcu_read_unlock(); 228 229 return sel_netport_sid_slow(protocol, pnum, sid); 230 } 231 232 /** 233 * sel_netport_flush - Flush the entire network port table 234 * 235 * Description: 236 * Remove all entries from the network address table. 237 * 238 */ 239 static void sel_netport_flush(void) 240 { 241 unsigned int idx; 242 struct sel_netport *port; 243 244 spin_lock_bh(&sel_netport_lock); 245 for (idx = 0; idx < SEL_NETPORT_HASH_SIZE; idx++) { 246 list_for_each_entry(port, &sel_netport_hash[idx].list, list) { 247 list_del_rcu(&port->list); 248 call_rcu(&port->rcu, sel_netport_free); 249 } 250 sel_netport_hash[idx].size = 0; 251 } 252 spin_unlock_bh(&sel_netport_lock); 253 } 254 255 static int sel_netport_avc_callback(u32 event, u32 ssid, u32 tsid, 256 u16 class, u32 perms, u32 *retained) 257 { 258 if (event == AVC_CALLBACK_RESET) { 259 sel_netport_flush(); 260 synchronize_net(); 261 } 262 return 0; 263 } 264 265 static __init int sel_netport_init(void) 266 { 267 int iter; 268 int ret; 269 270 if (!selinux_enabled) 271 return 0; 272 273 for (iter = 0; iter < SEL_NETPORT_HASH_SIZE; iter++) { 274 INIT_LIST_HEAD(&sel_netport_hash[iter].list); 275 sel_netport_hash[iter].size = 0; 276 } 277 278 ret = avc_add_callback(sel_netport_avc_callback, AVC_CALLBACK_RESET, 279 SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); 280 if (ret != 0) 281 panic("avc_add_callback() failed, error %d\n", ret); 282 283 return ret; 284 } 285 286 __initcall(sel_netport_init); 287