1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * Network interface table. 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Network interfaces (devices) do not have a security field, so we 61da177e4SLinus Torvalds * maintain a table associating each interface with a SID. 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Author: James Morris <jmorris@redhat.com> 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> 11e8bfdb9dSPaul Moore * Copyright (C) 2007 Hewlett-Packard Development Company, L.P. 1282c21bfaSPaul Moore * Paul Moore <paul@paul-moore.com> 131da177e4SLinus Torvalds */ 141da177e4SLinus Torvalds #include <linux/init.h> 151da177e4SLinus Torvalds #include <linux/types.h> 165a0e3ad6STejun Heo #include <linux/slab.h> 171da177e4SLinus Torvalds #include <linux/stddef.h> 181da177e4SLinus Torvalds #include <linux/kernel.h> 191da177e4SLinus Torvalds #include <linux/list.h> 201da177e4SLinus Torvalds #include <linux/notifier.h> 211da177e4SLinus Torvalds #include <linux/netdevice.h> 221da177e4SLinus Torvalds #include <linux/rcupdate.h> 23e9dc8653SEric W. Biederman #include <net/net_namespace.h> 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds #include "security.h" 261da177e4SLinus Torvalds #include "objsec.h" 271da177e4SLinus Torvalds #include "netif.h" 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds #define SEL_NETIF_HASH_SIZE 64 301da177e4SLinus Torvalds #define SEL_NETIF_HASH_MAX 1024 311da177e4SLinus Torvalds 32338366cbSEric Paris struct sel_netif { 331da177e4SLinus Torvalds struct list_head list; 341da177e4SLinus Torvalds struct netif_security_struct nsec; 351da177e4SLinus Torvalds struct rcu_head rcu_head; 361da177e4SLinus Torvalds }; 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds static u32 sel_netif_total; 391da177e4SLinus Torvalds static DEFINE_SPINLOCK(sel_netif_lock); 401da177e4SLinus Torvalds static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE]; 411da177e4SLinus Torvalds 42e8bfdb9dSPaul Moore /** 43e8bfdb9dSPaul Moore * sel_netif_hashfn - Hashing function for the interface table 44cbe0d6e8SPaul Moore * @ns: the network namespace 45e8bfdb9dSPaul Moore * @ifindex: the network interface 46e8bfdb9dSPaul Moore * 47e8bfdb9dSPaul Moore * Description: 48e8bfdb9dSPaul Moore * This is the hashing function for the network interface table, it returns the 49e8bfdb9dSPaul Moore * bucket number for the given interface. 50e8bfdb9dSPaul Moore * 511da177e4SLinus Torvalds */ 52cbe0d6e8SPaul Moore static inline u32 sel_netif_hashfn(const struct net *ns, int ifindex) 531da177e4SLinus Torvalds { 54cbe0d6e8SPaul Moore return (((uintptr_t)ns + ifindex) & (SEL_NETIF_HASH_SIZE - 1)); 551da177e4SLinus Torvalds } 56e8bfdb9dSPaul Moore 57e8bfdb9dSPaul Moore /** 58e8bfdb9dSPaul Moore * sel_netif_find - Search for an interface record 59cbe0d6e8SPaul Moore * @ns: the network namespace 60e8bfdb9dSPaul Moore * @ifindex: the network interface 61e8bfdb9dSPaul Moore * 62e8bfdb9dSPaul Moore * Description: 63e8bfdb9dSPaul Moore * Search the network interface table and return the record matching @ifindex. 64e8bfdb9dSPaul Moore * If an entry can not be found in the table return NULL. 65e8bfdb9dSPaul Moore * 66e8bfdb9dSPaul Moore */ 67cbe0d6e8SPaul Moore static inline struct sel_netif *sel_netif_find(const struct net *ns, 68cbe0d6e8SPaul Moore int ifindex) 69e8bfdb9dSPaul Moore { 70*777ea29cSChristian Göttsche u32 idx = sel_netif_hashfn(ns, ifindex); 71e8bfdb9dSPaul Moore struct sel_netif *netif; 72e8bfdb9dSPaul Moore 73e8bfdb9dSPaul Moore list_for_each_entry_rcu(netif, &sel_netif_hash[idx], list) 74cbe0d6e8SPaul Moore if (net_eq(netif->nsec.ns, ns) && 75cbe0d6e8SPaul Moore netif->nsec.ifindex == ifindex) 76e8bfdb9dSPaul Moore return netif; 77e8bfdb9dSPaul Moore 781da177e4SLinus Torvalds return NULL; 791da177e4SLinus Torvalds } 801da177e4SLinus Torvalds 81e8bfdb9dSPaul Moore /** 82e8bfdb9dSPaul Moore * sel_netif_insert - Insert a new interface into the table 83e8bfdb9dSPaul Moore * @netif: the new interface record 84e8bfdb9dSPaul Moore * 85e8bfdb9dSPaul Moore * Description: 86e8bfdb9dSPaul Moore * Add a new interface record to the network interface hash table. Returns 87e8bfdb9dSPaul Moore * zero on success, negative values on failure. 88e8bfdb9dSPaul Moore * 89e8bfdb9dSPaul Moore */ 901da177e4SLinus Torvalds static int sel_netif_insert(struct sel_netif *netif) 911da177e4SLinus Torvalds { 92*777ea29cSChristian Göttsche u32 idx; 931da177e4SLinus Torvalds 94e8bfdb9dSPaul Moore if (sel_netif_total >= SEL_NETIF_HASH_MAX) 95e8bfdb9dSPaul Moore return -ENOSPC; 961da177e4SLinus Torvalds 97cbe0d6e8SPaul Moore idx = sel_netif_hashfn(netif->nsec.ns, netif->nsec.ifindex); 981da177e4SLinus Torvalds list_add_rcu(&netif->list, &sel_netif_hash[idx]); 991da177e4SLinus Torvalds sel_netif_total++; 100e8bfdb9dSPaul Moore 101e8bfdb9dSPaul Moore return 0; 1021da177e4SLinus Torvalds } 1031da177e4SLinus Torvalds 104e8bfdb9dSPaul Moore /** 105e8bfdb9dSPaul Moore * sel_netif_destroy - Remove an interface record from the table 106e8bfdb9dSPaul Moore * @netif: the existing interface record 107e8bfdb9dSPaul Moore * 108e8bfdb9dSPaul Moore * Description: 109e8bfdb9dSPaul Moore * Remove an existing interface record from the network interface table. 110e8bfdb9dSPaul Moore * 111e8bfdb9dSPaul Moore */ 1121da177e4SLinus Torvalds static void sel_netif_destroy(struct sel_netif *netif) 1131da177e4SLinus Torvalds { 1141da177e4SLinus Torvalds list_del_rcu(&netif->list); 1151da177e4SLinus Torvalds sel_netif_total--; 116690273fcSLai Jiangshan kfree_rcu(netif, rcu_head); 1171da177e4SLinus Torvalds } 1181da177e4SLinus Torvalds 119e8bfdb9dSPaul Moore /** 120e8bfdb9dSPaul Moore * sel_netif_sid_slow - Lookup the SID of a network interface using the policy 121cbe0d6e8SPaul Moore * @ns: the network namespace 122e8bfdb9dSPaul Moore * @ifindex: the network interface 123e8bfdb9dSPaul Moore * @sid: interface SID 124e8bfdb9dSPaul Moore * 125e8bfdb9dSPaul Moore * Description: 1262c3d8dfeSlihao * This function determines the SID of a network interface by querying the 127e8bfdb9dSPaul Moore * security policy. The result is added to the network interface table to 128e8bfdb9dSPaul Moore * speedup future queries. Returns zero on success, negative values on 129e8bfdb9dSPaul Moore * failure. 130e8bfdb9dSPaul Moore * 131e8bfdb9dSPaul Moore */ 132cbe0d6e8SPaul Moore static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid) 1331da177e4SLinus Torvalds { 1349b80c363SPaul Moore int ret = 0; 135e8bfdb9dSPaul Moore struct sel_netif *netif; 1369b80c363SPaul Moore struct sel_netif *new; 137e8bfdb9dSPaul Moore struct net_device *dev; 1381da177e4SLinus Torvalds 139e8bfdb9dSPaul Moore /* NOTE: we always use init's network namespace since we don't 140e8bfdb9dSPaul Moore * currently support containers */ 1411da177e4SLinus Torvalds 142cbe0d6e8SPaul Moore dev = dev_get_by_index(ns, ifindex); 14371f1cb05SPaul Moore if (unlikely(dev == NULL)) { 1440d3a1154Speter enderborg pr_warn("SELinux: failure in %s(), invalid network interface (%d)\n", 1450d3a1154Speter enderborg __func__, ifindex); 146e8bfdb9dSPaul Moore return -ENOENT; 14771f1cb05SPaul Moore } 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds spin_lock_bh(&sel_netif_lock); 150cbe0d6e8SPaul Moore netif = sel_netif_find(ns, ifindex); 151e8bfdb9dSPaul Moore if (netif != NULL) { 152e8bfdb9dSPaul Moore *sid = netif->nsec.sid; 1531da177e4SLinus Torvalds goto out; 1541da177e4SLinus Torvalds } 1559b80c363SPaul Moore 156e67b7985SStephen Smalley ret = security_netif_sid(dev->name, sid); 157e8bfdb9dSPaul Moore if (ret != 0) 158e8bfdb9dSPaul Moore goto out; 1599b80c363SPaul Moore new = kzalloc(sizeof(*new), GFP_ATOMIC); 1609b80c363SPaul Moore if (new) { 161cbe0d6e8SPaul Moore new->nsec.ns = ns; 162e8bfdb9dSPaul Moore new->nsec.ifindex = ifindex; 1639b80c363SPaul Moore new->nsec.sid = *sid; 1649b80c363SPaul Moore if (sel_netif_insert(new)) 1659b80c363SPaul Moore kfree(new); 1669b80c363SPaul Moore } 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds out: 169e8bfdb9dSPaul Moore spin_unlock_bh(&sel_netif_lock); 170e8bfdb9dSPaul Moore dev_put(dev); 1719b80c363SPaul Moore if (unlikely(ret)) 1720d3a1154Speter enderborg pr_warn("SELinux: failure in %s(), unable to determine network interface label (%d)\n", 1730d3a1154Speter enderborg __func__, ifindex); 1741da177e4SLinus Torvalds return ret; 1751da177e4SLinus Torvalds } 1761da177e4SLinus Torvalds 177e8bfdb9dSPaul Moore /** 178e8bfdb9dSPaul Moore * sel_netif_sid - Lookup the SID of a network interface 179cbe0d6e8SPaul Moore * @ns: the network namespace 180e8bfdb9dSPaul Moore * @ifindex: the network interface 181e8bfdb9dSPaul Moore * @sid: interface SID 182e8bfdb9dSPaul Moore * 183e8bfdb9dSPaul Moore * Description: 184e8bfdb9dSPaul Moore * This function determines the SID of a network interface using the fastest 185e8bfdb9dSPaul Moore * method possible. First the interface table is queried, but if an entry 186e8bfdb9dSPaul Moore * can't be found then the policy is queried and the result is added to the 187e8bfdb9dSPaul Moore * table to speedup future queries. Returns zero on success, negative values 188e8bfdb9dSPaul Moore * on failure. 189e8bfdb9dSPaul Moore * 190e8bfdb9dSPaul Moore */ 191cbe0d6e8SPaul Moore int sel_netif_sid(struct net *ns, int ifindex, u32 *sid) 1921da177e4SLinus Torvalds { 1931da177e4SLinus Torvalds struct sel_netif *netif; 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds rcu_read_lock(); 196cbe0d6e8SPaul Moore netif = sel_netif_find(ns, ifindex); 197e8bfdb9dSPaul Moore if (likely(netif != NULL)) { 198e8bfdb9dSPaul Moore *sid = netif->nsec.sid; 1991da177e4SLinus Torvalds rcu_read_unlock(); 200e8bfdb9dSPaul Moore return 0; 2011da177e4SLinus Torvalds } 2021da177e4SLinus Torvalds rcu_read_unlock(); 203e8bfdb9dSPaul Moore 204cbe0d6e8SPaul Moore return sel_netif_sid_slow(ns, ifindex, sid); 2051da177e4SLinus Torvalds } 2061da177e4SLinus Torvalds 207e8bfdb9dSPaul Moore /** 208e8bfdb9dSPaul Moore * sel_netif_kill - Remove an entry from the network interface table 209cbe0d6e8SPaul Moore * @ns: the network namespace 210e8bfdb9dSPaul Moore * @ifindex: the network interface 211e8bfdb9dSPaul Moore * 212e8bfdb9dSPaul Moore * Description: 213e8bfdb9dSPaul Moore * This function removes the entry matching @ifindex from the network interface 214e8bfdb9dSPaul Moore * table if it exists. 215e8bfdb9dSPaul Moore * 216e8bfdb9dSPaul Moore */ 217cbe0d6e8SPaul Moore static void sel_netif_kill(const struct net *ns, int ifindex) 2181da177e4SLinus Torvalds { 2191da177e4SLinus Torvalds struct sel_netif *netif; 2201da177e4SLinus Torvalds 22161844250SPaul E. McKenney rcu_read_lock(); 2221da177e4SLinus Torvalds spin_lock_bh(&sel_netif_lock); 223cbe0d6e8SPaul Moore netif = sel_netif_find(ns, ifindex); 2241da177e4SLinus Torvalds if (netif) 2251da177e4SLinus Torvalds sel_netif_destroy(netif); 2261da177e4SLinus Torvalds spin_unlock_bh(&sel_netif_lock); 22761844250SPaul E. McKenney rcu_read_unlock(); 2281da177e4SLinus Torvalds } 2291da177e4SLinus Torvalds 230e8bfdb9dSPaul Moore /** 231e8bfdb9dSPaul Moore * sel_netif_flush - Flush the entire network interface table 232e8bfdb9dSPaul Moore * 233e8bfdb9dSPaul Moore * Description: 234e8bfdb9dSPaul Moore * Remove all entries from the network interface table. 235e8bfdb9dSPaul Moore * 236e8bfdb9dSPaul Moore */ 237615e51fdSPaul Moore void sel_netif_flush(void) 2381da177e4SLinus Torvalds { 2391da177e4SLinus Torvalds int idx; 2401da177e4SLinus Torvalds struct sel_netif *netif; 2411da177e4SLinus Torvalds 242e8bfdb9dSPaul Moore spin_lock_bh(&sel_netif_lock); 243e8bfdb9dSPaul Moore for (idx = 0; idx < SEL_NETIF_HASH_SIZE; idx++) 2441da177e4SLinus Torvalds list_for_each_entry(netif, &sel_netif_hash[idx], list) 2451da177e4SLinus Torvalds sel_netif_destroy(netif); 2461da177e4SLinus Torvalds spin_unlock_bh(&sel_netif_lock); 2471da177e4SLinus Torvalds } 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds static int sel_netif_netdev_notifier_handler(struct notifier_block *this, 2501da177e4SLinus Torvalds unsigned long event, void *ptr) 2511da177e4SLinus Torvalds { 252351638e7SJiri Pirko struct net_device *dev = netdev_notifier_info_to_dev(ptr); 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvalds if (event == NETDEV_DOWN) 255cbe0d6e8SPaul Moore sel_netif_kill(dev_net(dev), dev->ifindex); 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds return NOTIFY_DONE; 2581da177e4SLinus Torvalds } 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds static struct notifier_block sel_netif_netdev_notifier = { 2611da177e4SLinus Torvalds .notifier_call = sel_netif_netdev_notifier_handler, 2621da177e4SLinus Torvalds }; 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds static __init int sel_netif_init(void) 2651da177e4SLinus Torvalds { 266942ba364SPaul Moore int i; 2671da177e4SLinus Torvalds 2686c5a682eSStephen Smalley if (!selinux_enabled_boot) 269e8bfdb9dSPaul Moore return 0; 2701da177e4SLinus Torvalds 2711da177e4SLinus Torvalds for (i = 0; i < SEL_NETIF_HASH_SIZE; i++) 2721da177e4SLinus Torvalds INIT_LIST_HEAD(&sel_netif_hash[i]); 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds register_netdevice_notifier(&sel_netif_netdev_notifier); 2751da177e4SLinus Torvalds 276942ba364SPaul Moore return 0; 2771da177e4SLinus Torvalds } 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds __initcall(sel_netif_init); 2801da177e4SLinus Torvalds 281