1 /* 2 * Network node table 3 * 4 * SELinux must keep a mapping of network nodes 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 since most of these queries happen on 7 * a per-packet basis. 8 * 9 * Author: Paul Moore <paul.moore@hp.com> 10 * 11 * This code is heavily based on the "netif" concept originally developed by 12 * James Morris <jmorris@redhat.com> 13 * (see security/selinux/netif.c for more information) 14 * 15 */ 16 17 /* 18 * (c) Copyright Hewlett-Packard Development Company, L.P., 2007 19 * 20 * This program is free software: you can redistribute it and/or modify 21 * it under the terms of version 2 of the GNU General Public License as 22 * published by the Free Software Foundation. 23 * 24 * This program is distributed in the hope that it will be useful, 25 * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 * GNU General Public License for more details. 28 * 29 */ 30 31 #include <linux/types.h> 32 #include <linux/rcupdate.h> 33 #include <linux/list.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 #include <asm/bug.h> 42 43 #include "objsec.h" 44 45 #define SEL_NETNODE_HASH_SIZE 256 46 #define SEL_NETNODE_HASH_BKT_LIMIT 16 47 48 struct sel_netnode { 49 struct netnode_security_struct nsec; 50 51 struct list_head list; 52 struct rcu_head rcu; 53 }; 54 55 /* NOTE: we are using a combined hash table for both IPv4 and IPv6, the reason 56 * for this is that I suspect most users will not make heavy use of both 57 * address families at the same time so one table will usually end up wasted, 58 * if this becomes a problem we can always add a hash table for each address 59 * family later */ 60 61 static LIST_HEAD(sel_netnode_list); 62 static DEFINE_SPINLOCK(sel_netnode_lock); 63 static struct list_head sel_netnode_hash[SEL_NETNODE_HASH_SIZE]; 64 65 /** 66 * sel_netnode_free - Frees a node entry 67 * @p: the entry's RCU field 68 * 69 * Description: 70 * This function is designed to be used as a callback to the call_rcu() 71 * function so that memory allocated to a hash table node entry can be 72 * released safely. 73 * 74 */ 75 static void sel_netnode_free(struct rcu_head *p) 76 { 77 struct sel_netnode *node = container_of(p, struct sel_netnode, rcu); 78 kfree(node); 79 } 80 81 /** 82 * sel_netnode_hashfn_ipv4 - IPv4 hashing function for the node table 83 * @addr: IPv4 address 84 * 85 * Description: 86 * This is the IPv4 hashing function for the node interface table, it returns 87 * the bucket number for the given IP address. 88 * 89 */ 90 static u32 sel_netnode_hashfn_ipv4(__be32 addr) 91 { 92 /* at some point we should determine if the mismatch in byte order 93 * affects the hash function dramatically */ 94 return (addr & (SEL_NETNODE_HASH_SIZE - 1)); 95 } 96 97 /** 98 * sel_netnode_hashfn_ipv6 - IPv6 hashing function for the node table 99 * @addr: IPv6 address 100 * 101 * Description: 102 * This is the IPv6 hashing function for the node interface table, it returns 103 * the bucket number for the given IP address. 104 * 105 */ 106 static u32 sel_netnode_hashfn_ipv6(const struct in6_addr *addr) 107 { 108 /* just hash the least significant 32 bits to keep things fast (they 109 * are the most likely to be different anyway), we can revisit this 110 * later if needed */ 111 return (addr->s6_addr32[3] & (SEL_NETNODE_HASH_SIZE - 1)); 112 } 113 114 /** 115 * sel_netnode_find - Search for a node record 116 * @addr: IP address 117 * @family: address family 118 * 119 * Description: 120 * Search the network node table and return the record matching @addr. If an 121 * entry can not be found in the table return NULL. 122 * 123 */ 124 static struct sel_netnode *sel_netnode_find(const void *addr, u16 family) 125 { 126 u32 idx; 127 struct sel_netnode *node; 128 129 switch (family) { 130 case PF_INET: 131 idx = sel_netnode_hashfn_ipv4(*(__be32 *)addr); 132 break; 133 case PF_INET6: 134 idx = sel_netnode_hashfn_ipv6(addr); 135 break; 136 default: 137 BUG(); 138 } 139 140 list_for_each_entry_rcu(node, &sel_netnode_hash[idx], list) 141 if (node->nsec.family == family) 142 switch (family) { 143 case PF_INET: 144 if (node->nsec.addr.ipv4 == *(__be32 *)addr) 145 return node; 146 break; 147 case PF_INET6: 148 if (ipv6_addr_equal(&node->nsec.addr.ipv6, 149 addr)) 150 return node; 151 break; 152 } 153 154 return NULL; 155 } 156 157 /** 158 * sel_netnode_insert - Insert a new node into the table 159 * @node: the new node record 160 * 161 * Description: 162 * Add a new node record to the network address hash table. Returns zero on 163 * success, negative values on failure. 164 * 165 */ 166 static int sel_netnode_insert(struct sel_netnode *node) 167 { 168 u32 idx; 169 u32 count = 0; 170 struct sel_netnode *iter; 171 172 switch (node->nsec.family) { 173 case PF_INET: 174 idx = sel_netnode_hashfn_ipv4(node->nsec.addr.ipv4); 175 break; 176 case PF_INET6: 177 idx = sel_netnode_hashfn_ipv6(&node->nsec.addr.ipv6); 178 break; 179 default: 180 BUG(); 181 } 182 list_add_rcu(&node->list, &sel_netnode_hash[idx]); 183 184 /* we need to impose a limit on the growth of the hash table so check 185 * this bucket to make sure it is within the specified bounds */ 186 list_for_each_entry(iter, &sel_netnode_hash[idx], list) 187 if (++count > SEL_NETNODE_HASH_BKT_LIMIT) { 188 list_del_rcu(&iter->list); 189 call_rcu(&iter->rcu, sel_netnode_free); 190 break; 191 } 192 193 return 0; 194 } 195 196 /** 197 * sel_netnode_destroy - Remove a node record from the table 198 * @node: the existing node record 199 * 200 * Description: 201 * Remove an existing node record from the network address table. 202 * 203 */ 204 static void sel_netnode_destroy(struct sel_netnode *node) 205 { 206 list_del_rcu(&node->list); 207 call_rcu(&node->rcu, sel_netnode_free); 208 } 209 210 /** 211 * sel_netnode_sid_slow - Lookup the SID of a network address using the policy 212 * @addr: the IP address 213 * @family: the address family 214 * @sid: node SID 215 * 216 * Description: 217 * This function determines the SID of a network address by quering the 218 * security policy. The result is added to the network address table to 219 * speedup future queries. Returns zero on success, negative values on 220 * failure. 221 * 222 */ 223 static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid) 224 { 225 int ret; 226 struct sel_netnode *node; 227 struct sel_netnode *new = NULL; 228 229 spin_lock_bh(&sel_netnode_lock); 230 node = sel_netnode_find(addr, family); 231 if (node != NULL) { 232 *sid = node->nsec.sid; 233 ret = 0; 234 goto out; 235 } 236 new = kzalloc(sizeof(*new), GFP_ATOMIC); 237 if (new == NULL) { 238 ret = -ENOMEM; 239 goto out; 240 } 241 switch (family) { 242 case PF_INET: 243 ret = security_node_sid(PF_INET, 244 addr, sizeof(struct in_addr), 245 &new->nsec.sid); 246 new->nsec.addr.ipv4 = *(__be32 *)addr; 247 break; 248 case PF_INET6: 249 ret = security_node_sid(PF_INET6, 250 addr, sizeof(struct in6_addr), 251 &new->nsec.sid); 252 ipv6_addr_copy(&new->nsec.addr.ipv6, addr); 253 break; 254 default: 255 BUG(); 256 } 257 if (ret != 0) 258 goto out; 259 new->nsec.family = family; 260 ret = sel_netnode_insert(new); 261 if (ret != 0) 262 goto out; 263 *sid = new->nsec.sid; 264 265 out: 266 spin_unlock_bh(&sel_netnode_lock); 267 if (unlikely(ret)) { 268 printk(KERN_WARNING 269 "SELinux: failure in sel_netnode_sid_slow()," 270 " unable to determine network node label\n"); 271 kfree(new); 272 } 273 return ret; 274 } 275 276 /** 277 * sel_netnode_sid - Lookup the SID of a network address 278 * @addr: the IP address 279 * @family: the address family 280 * @sid: node SID 281 * 282 * Description: 283 * This function determines the SID of a network address using the fastest 284 * method possible. First the address table is queried, but if an entry 285 * can't be found then the policy is queried and the result is added to the 286 * table to speedup future queries. Returns zero on success, negative values 287 * on failure. 288 * 289 */ 290 int sel_netnode_sid(void *addr, u16 family, u32 *sid) 291 { 292 struct sel_netnode *node; 293 294 rcu_read_lock(); 295 node = sel_netnode_find(addr, family); 296 if (node != NULL) { 297 *sid = node->nsec.sid; 298 rcu_read_unlock(); 299 return 0; 300 } 301 rcu_read_unlock(); 302 303 return sel_netnode_sid_slow(addr, family, sid); 304 } 305 306 /** 307 * sel_netnode_flush - Flush the entire network address table 308 * 309 * Description: 310 * Remove all entries from the network address table. 311 * 312 */ 313 static void sel_netnode_flush(void) 314 { 315 u32 idx; 316 struct sel_netnode *node; 317 318 spin_lock_bh(&sel_netnode_lock); 319 for (idx = 0; idx < SEL_NETNODE_HASH_SIZE; idx++) 320 list_for_each_entry(node, &sel_netnode_hash[idx], list) 321 sel_netnode_destroy(node); 322 spin_unlock_bh(&sel_netnode_lock); 323 } 324 325 static int sel_netnode_avc_callback(u32 event, u32 ssid, u32 tsid, 326 u16 class, u32 perms, u32 *retained) 327 { 328 if (event == AVC_CALLBACK_RESET) { 329 sel_netnode_flush(); 330 synchronize_net(); 331 } 332 return 0; 333 } 334 335 static __init int sel_netnode_init(void) 336 { 337 int iter; 338 int ret; 339 340 if (!selinux_enabled) 341 return 0; 342 343 for (iter = 0; iter < SEL_NETNODE_HASH_SIZE; iter++) 344 INIT_LIST_HEAD(&sel_netnode_hash[iter]); 345 346 ret = avc_add_callback(sel_netnode_avc_callback, AVC_CALLBACK_RESET, 347 SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); 348 if (ret != 0) 349 panic("avc_add_callback() failed, error %d\n", ret); 350 351 return ret; 352 } 353 354 __initcall(sel_netnode_init); 355