1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Network interface table. 4 * 5 * Network interfaces (devices) do not have a security field, so we 6 * maintain a table associating each interface with a SID. 7 * 8 * Author: James Morris <jmorris@redhat.com> 9 * 10 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> 11 * Copyright (C) 2007 Hewlett-Packard Development Company, L.P. 12 * Paul Moore <paul@paul-moore.com> 13 */ 14 #include <linux/init.h> 15 #include <linux/types.h> 16 #include <linux/slab.h> 17 #include <linux/stddef.h> 18 #include <linux/kernel.h> 19 #include <linux/list.h> 20 #include <linux/notifier.h> 21 #include <linux/netdevice.h> 22 #include <linux/rcupdate.h> 23 #include <net/net_namespace.h> 24 25 #include "security.h" 26 #include "objsec.h" 27 #include "netif.h" 28 29 #define SEL_NETIF_HASH_SIZE 64 30 #define SEL_NETIF_HASH_MAX 1024 31 32 struct sel_netif { 33 struct list_head list; 34 struct netif_security_struct nsec; 35 struct rcu_head rcu_head; 36 }; 37 38 static u32 sel_netif_total; 39 static DEFINE_SPINLOCK(sel_netif_lock); 40 static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE]; 41 42 /** 43 * sel_netif_hashfn - Hashing function for the interface table 44 * @ns: the network namespace 45 * @ifindex: the network interface 46 * 47 * Description: 48 * This is the hashing function for the network interface table, it returns the 49 * bucket number for the given interface. 50 * 51 */ 52 static inline u32 sel_netif_hashfn(const struct net *ns, int ifindex) 53 { 54 return (((uintptr_t)ns + ifindex) & (SEL_NETIF_HASH_SIZE - 1)); 55 } 56 57 /** 58 * sel_netif_find - Search for an interface record 59 * @ns: the network namespace 60 * @ifindex: the network interface 61 * 62 * Description: 63 * Search the network interface table and return the record matching @ifindex. 64 * If an entry can not be found in the table return NULL. 65 * 66 */ 67 static inline struct sel_netif *sel_netif_find(const struct net *ns, 68 int ifindex) 69 { 70 u32 idx = sel_netif_hashfn(ns, ifindex); 71 struct sel_netif *netif; 72 73 list_for_each_entry_rcu(netif, &sel_netif_hash[idx], list) 74 if (net_eq(netif->nsec.ns, ns) && 75 netif->nsec.ifindex == ifindex) 76 return netif; 77 78 return NULL; 79 } 80 81 /** 82 * sel_netif_insert - Insert a new interface into the table 83 * @netif: the new interface record 84 * 85 * Description: 86 * Add a new interface record to the network interface hash table. Returns 87 * zero on success, negative values on failure. 88 * 89 */ 90 static int sel_netif_insert(struct sel_netif *netif) 91 { 92 u32 idx; 93 94 if (sel_netif_total >= SEL_NETIF_HASH_MAX) 95 return -ENOSPC; 96 97 idx = sel_netif_hashfn(netif->nsec.ns, netif->nsec.ifindex); 98 list_add_rcu(&netif->list, &sel_netif_hash[idx]); 99 sel_netif_total++; 100 101 return 0; 102 } 103 104 /** 105 * sel_netif_destroy - Remove an interface record from the table 106 * @netif: the existing interface record 107 * 108 * Description: 109 * Remove an existing interface record from the network interface table. 110 * 111 */ 112 static void sel_netif_destroy(struct sel_netif *netif) 113 { 114 list_del_rcu(&netif->list); 115 sel_netif_total--; 116 kfree_rcu(netif, rcu_head); 117 } 118 119 /** 120 * sel_netif_sid_slow - Lookup the SID of a network interface using the policy 121 * @ns: the network namespace 122 * @ifindex: the network interface 123 * @sid: interface SID 124 * 125 * Description: 126 * This function determines the SID of a network interface by querying the 127 * security policy. The result is added to the network interface table to 128 * speedup future queries. Returns zero on success, negative values on 129 * failure. 130 * 131 */ 132 static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid) 133 { 134 int ret = 0; 135 struct sel_netif *netif; 136 struct sel_netif *new; 137 struct net_device *dev; 138 139 /* NOTE: we always use init's network namespace since we don't 140 * currently support containers */ 141 142 dev = dev_get_by_index(ns, ifindex); 143 if (unlikely(dev == NULL)) { 144 pr_warn("SELinux: failure in %s(), invalid network interface (%d)\n", 145 __func__, ifindex); 146 return -ENOENT; 147 } 148 149 spin_lock_bh(&sel_netif_lock); 150 netif = sel_netif_find(ns, ifindex); 151 if (netif != NULL) { 152 *sid = netif->nsec.sid; 153 goto out; 154 } 155 156 ret = security_netif_sid(dev->name, sid); 157 if (ret != 0) 158 goto out; 159 160 /* If this memory allocation fails still return 0. The SID 161 * is valid, it just won't be added to the cache. 162 */ 163 new = kmalloc(sizeof(*new), GFP_ATOMIC); 164 if (new) { 165 new->nsec.ns = ns; 166 new->nsec.ifindex = ifindex; 167 new->nsec.sid = *sid; 168 if (sel_netif_insert(new)) 169 kfree(new); 170 } 171 172 out: 173 spin_unlock_bh(&sel_netif_lock); 174 dev_put(dev); 175 if (unlikely(ret)) 176 pr_warn("SELinux: failure in %s(), unable to determine network interface label (%d)\n", 177 __func__, ifindex); 178 return ret; 179 } 180 181 /** 182 * sel_netif_sid - Lookup the SID of a network interface 183 * @ns: the network namespace 184 * @ifindex: the network interface 185 * @sid: interface SID 186 * 187 * Description: 188 * This function determines the SID of a network interface using the fastest 189 * method possible. First the interface table is queried, but if an entry 190 * can't be found then the policy is queried and the result is added to the 191 * table to speedup future queries. Returns zero on success, negative values 192 * on failure. 193 * 194 */ 195 int sel_netif_sid(struct net *ns, int ifindex, u32 *sid) 196 { 197 struct sel_netif *netif; 198 199 rcu_read_lock(); 200 netif = sel_netif_find(ns, ifindex); 201 if (likely(netif != NULL)) { 202 *sid = netif->nsec.sid; 203 rcu_read_unlock(); 204 return 0; 205 } 206 rcu_read_unlock(); 207 208 return sel_netif_sid_slow(ns, ifindex, sid); 209 } 210 211 /** 212 * sel_netif_kill - Remove an entry from the network interface table 213 * @ns: the network namespace 214 * @ifindex: the network interface 215 * 216 * Description: 217 * This function removes the entry matching @ifindex from the network interface 218 * table if it exists. 219 * 220 */ 221 static void sel_netif_kill(const struct net *ns, int ifindex) 222 { 223 struct sel_netif *netif; 224 225 rcu_read_lock(); 226 spin_lock_bh(&sel_netif_lock); 227 netif = sel_netif_find(ns, ifindex); 228 if (netif) 229 sel_netif_destroy(netif); 230 spin_unlock_bh(&sel_netif_lock); 231 rcu_read_unlock(); 232 } 233 234 /** 235 * sel_netif_flush - Flush the entire network interface table 236 * 237 * Description: 238 * Remove all entries from the network interface table. 239 * 240 */ 241 void sel_netif_flush(void) 242 { 243 int idx; 244 struct sel_netif *netif; 245 246 spin_lock_bh(&sel_netif_lock); 247 for (idx = 0; idx < SEL_NETIF_HASH_SIZE; idx++) 248 list_for_each_entry(netif, &sel_netif_hash[idx], list) 249 sel_netif_destroy(netif); 250 spin_unlock_bh(&sel_netif_lock); 251 } 252 253 static int sel_netif_netdev_notifier_handler(struct notifier_block *this, 254 unsigned long event, void *ptr) 255 { 256 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 257 258 if (event == NETDEV_DOWN) 259 sel_netif_kill(dev_net(dev), dev->ifindex); 260 261 return NOTIFY_DONE; 262 } 263 264 static struct notifier_block sel_netif_netdev_notifier = { 265 .notifier_call = sel_netif_netdev_notifier_handler, 266 }; 267 268 static __init int sel_netif_init(void) 269 { 270 int i; 271 272 if (!selinux_enabled_boot) 273 return 0; 274 275 for (i = 0; i < SEL_NETIF_HASH_SIZE; i++) 276 INIT_LIST_HEAD(&sel_netif_hash[i]); 277 278 register_netdevice_notifier(&sel_netif_netdev_notifier); 279 280 return 0; 281 } 282 283 __initcall(sel_netif_init); 284 285