11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Network interface table. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Network interfaces (devices) do not have a security field, so we 51da177e4SLinus Torvalds * maintain a table associating each interface with a SID. 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * Author: James Morris <jmorris@redhat.com> 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> 10e8bfdb9dSPaul Moore * Copyright (C) 2007 Hewlett-Packard Development Company, L.P. 1182c21bfaSPaul Moore * Paul Moore <paul@paul-moore.com> 121da177e4SLinus Torvalds * 131da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 141da177e4SLinus Torvalds * it under the terms of the GNU General Public License version 2, 151da177e4SLinus Torvalds * as published by the Free Software Foundation. 161da177e4SLinus Torvalds */ 171da177e4SLinus Torvalds #include <linux/init.h> 181da177e4SLinus Torvalds #include <linux/types.h> 195a0e3ad6STejun Heo #include <linux/slab.h> 201da177e4SLinus Torvalds #include <linux/stddef.h> 211da177e4SLinus Torvalds #include <linux/kernel.h> 221da177e4SLinus Torvalds #include <linux/list.h> 231da177e4SLinus Torvalds #include <linux/notifier.h> 241da177e4SLinus Torvalds #include <linux/netdevice.h> 251da177e4SLinus Torvalds #include <linux/rcupdate.h> 26e9dc8653SEric W. Biederman #include <net/net_namespace.h> 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds #include "security.h" 291da177e4SLinus Torvalds #include "objsec.h" 301da177e4SLinus Torvalds #include "netif.h" 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds #define SEL_NETIF_HASH_SIZE 64 331da177e4SLinus Torvalds #define SEL_NETIF_HASH_MAX 1024 341da177e4SLinus Torvalds 35338366cbSEric Paris struct sel_netif { 361da177e4SLinus Torvalds struct list_head list; 371da177e4SLinus Torvalds struct netif_security_struct nsec; 381da177e4SLinus Torvalds struct rcu_head rcu_head; 391da177e4SLinus Torvalds }; 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds static u32 sel_netif_total; 421da177e4SLinus Torvalds static LIST_HEAD(sel_netif_list); 431da177e4SLinus Torvalds static DEFINE_SPINLOCK(sel_netif_lock); 441da177e4SLinus Torvalds static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE]; 451da177e4SLinus Torvalds 46e8bfdb9dSPaul Moore /** 47e8bfdb9dSPaul Moore * sel_netif_hashfn - Hashing function for the interface table 48*cbe0d6e8SPaul Moore * @ns: the network namespace 49e8bfdb9dSPaul Moore * @ifindex: the network interface 50e8bfdb9dSPaul Moore * 51e8bfdb9dSPaul Moore * Description: 52e8bfdb9dSPaul Moore * This is the hashing function for the network interface table, it returns the 53e8bfdb9dSPaul Moore * bucket number for the given interface. 54e8bfdb9dSPaul Moore * 551da177e4SLinus Torvalds */ 56*cbe0d6e8SPaul Moore static inline u32 sel_netif_hashfn(const struct net *ns, int ifindex) 571da177e4SLinus Torvalds { 58*cbe0d6e8SPaul Moore return (((uintptr_t)ns + ifindex) & (SEL_NETIF_HASH_SIZE - 1)); 591da177e4SLinus Torvalds } 60e8bfdb9dSPaul Moore 61e8bfdb9dSPaul Moore /** 62e8bfdb9dSPaul Moore * sel_netif_find - Search for an interface record 63*cbe0d6e8SPaul Moore * @ns: the network namespace 64e8bfdb9dSPaul Moore * @ifindex: the network interface 65e8bfdb9dSPaul Moore * 66e8bfdb9dSPaul Moore * Description: 67e8bfdb9dSPaul Moore * Search the network interface table and return the record matching @ifindex. 68e8bfdb9dSPaul Moore * If an entry can not be found in the table return NULL. 69e8bfdb9dSPaul Moore * 70e8bfdb9dSPaul Moore */ 71*cbe0d6e8SPaul Moore static inline struct sel_netif *sel_netif_find(const struct net *ns, 72*cbe0d6e8SPaul Moore int ifindex) 73e8bfdb9dSPaul Moore { 74*cbe0d6e8SPaul Moore int idx = sel_netif_hashfn(ns, ifindex); 75e8bfdb9dSPaul Moore struct sel_netif *netif; 76e8bfdb9dSPaul Moore 77e8bfdb9dSPaul Moore list_for_each_entry_rcu(netif, &sel_netif_hash[idx], list) 78*cbe0d6e8SPaul Moore if (net_eq(netif->nsec.ns, ns) && 79*cbe0d6e8SPaul Moore netif->nsec.ifindex == ifindex) 80e8bfdb9dSPaul Moore return netif; 81e8bfdb9dSPaul Moore 821da177e4SLinus Torvalds return NULL; 831da177e4SLinus Torvalds } 841da177e4SLinus Torvalds 85e8bfdb9dSPaul Moore /** 86e8bfdb9dSPaul Moore * sel_netif_insert - Insert a new interface into the table 87e8bfdb9dSPaul Moore * @netif: the new interface record 88e8bfdb9dSPaul Moore * 89e8bfdb9dSPaul Moore * Description: 90e8bfdb9dSPaul Moore * Add a new interface record to the network interface hash table. Returns 91e8bfdb9dSPaul Moore * zero on success, negative values on failure. 92e8bfdb9dSPaul Moore * 93e8bfdb9dSPaul Moore */ 941da177e4SLinus Torvalds static int sel_netif_insert(struct sel_netif *netif) 951da177e4SLinus Torvalds { 96e8bfdb9dSPaul Moore int idx; 971da177e4SLinus Torvalds 98e8bfdb9dSPaul Moore if (sel_netif_total >= SEL_NETIF_HASH_MAX) 99e8bfdb9dSPaul Moore return -ENOSPC; 1001da177e4SLinus Torvalds 101*cbe0d6e8SPaul Moore idx = sel_netif_hashfn(netif->nsec.ns, netif->nsec.ifindex); 1021da177e4SLinus Torvalds list_add_rcu(&netif->list, &sel_netif_hash[idx]); 1031da177e4SLinus Torvalds sel_netif_total++; 104e8bfdb9dSPaul Moore 105e8bfdb9dSPaul Moore return 0; 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds 108e8bfdb9dSPaul Moore /** 109e8bfdb9dSPaul Moore * sel_netif_destroy - Remove an interface record from the table 110e8bfdb9dSPaul Moore * @netif: the existing interface record 111e8bfdb9dSPaul Moore * 112e8bfdb9dSPaul Moore * Description: 113e8bfdb9dSPaul Moore * Remove an existing interface record from the network interface table. 114e8bfdb9dSPaul Moore * 115e8bfdb9dSPaul Moore */ 1161da177e4SLinus Torvalds static void sel_netif_destroy(struct sel_netif *netif) 1171da177e4SLinus Torvalds { 1181da177e4SLinus Torvalds list_del_rcu(&netif->list); 1191da177e4SLinus Torvalds sel_netif_total--; 120690273fcSLai Jiangshan kfree_rcu(netif, rcu_head); 1211da177e4SLinus Torvalds } 1221da177e4SLinus Torvalds 123e8bfdb9dSPaul Moore /** 124e8bfdb9dSPaul Moore * sel_netif_sid_slow - Lookup the SID of a network interface using the policy 125*cbe0d6e8SPaul Moore * @ns: the network namespace 126e8bfdb9dSPaul Moore * @ifindex: the network interface 127e8bfdb9dSPaul Moore * @sid: interface SID 128e8bfdb9dSPaul Moore * 129e8bfdb9dSPaul Moore * Description: 130e8bfdb9dSPaul Moore * This function determines the SID of a network interface by quering the 131e8bfdb9dSPaul Moore * security policy. The result is added to the network interface table to 132e8bfdb9dSPaul Moore * speedup future queries. Returns zero on success, negative values on 133e8bfdb9dSPaul Moore * failure. 134e8bfdb9dSPaul Moore * 135e8bfdb9dSPaul Moore */ 136*cbe0d6e8SPaul Moore static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid) 1371da177e4SLinus Torvalds { 1381da177e4SLinus Torvalds int ret; 139e8bfdb9dSPaul Moore struct sel_netif *netif; 140e8bfdb9dSPaul Moore struct sel_netif *new = NULL; 141e8bfdb9dSPaul Moore struct net_device *dev; 1421da177e4SLinus Torvalds 143e8bfdb9dSPaul Moore /* NOTE: we always use init's network namespace since we don't 144e8bfdb9dSPaul Moore * currently support containers */ 1451da177e4SLinus Torvalds 146*cbe0d6e8SPaul Moore dev = dev_get_by_index(ns, ifindex); 14771f1cb05SPaul Moore if (unlikely(dev == NULL)) { 14871f1cb05SPaul Moore printk(KERN_WARNING 14971f1cb05SPaul Moore "SELinux: failure in sel_netif_sid_slow()," 15071f1cb05SPaul Moore " invalid network interface (%d)\n", ifindex); 151e8bfdb9dSPaul Moore return -ENOENT; 15271f1cb05SPaul Moore } 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds spin_lock_bh(&sel_netif_lock); 155*cbe0d6e8SPaul Moore netif = sel_netif_find(ns, ifindex); 156e8bfdb9dSPaul Moore if (netif != NULL) { 157e8bfdb9dSPaul Moore *sid = netif->nsec.sid; 158e8bfdb9dSPaul Moore ret = 0; 1591da177e4SLinus Torvalds goto out; 1601da177e4SLinus Torvalds } 161e8bfdb9dSPaul Moore new = kzalloc(sizeof(*new), GFP_ATOMIC); 162e8bfdb9dSPaul Moore if (new == NULL) { 163e8bfdb9dSPaul Moore ret = -ENOMEM; 164e8bfdb9dSPaul Moore goto out; 165e8bfdb9dSPaul Moore } 166e8bfdb9dSPaul Moore ret = security_netif_sid(dev->name, &new->nsec.sid); 167e8bfdb9dSPaul Moore if (ret != 0) 168e8bfdb9dSPaul Moore goto out; 169*cbe0d6e8SPaul Moore new->nsec.ns = ns; 170e8bfdb9dSPaul Moore new->nsec.ifindex = ifindex; 1711da177e4SLinus Torvalds ret = sel_netif_insert(new); 172e8bfdb9dSPaul Moore if (ret != 0) 1731da177e4SLinus Torvalds goto out; 174e8bfdb9dSPaul Moore *sid = new->nsec.sid; 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds out: 177e8bfdb9dSPaul Moore spin_unlock_bh(&sel_netif_lock); 178e8bfdb9dSPaul Moore dev_put(dev); 17971f1cb05SPaul Moore if (unlikely(ret)) { 18071f1cb05SPaul Moore printk(KERN_WARNING 18171f1cb05SPaul Moore "SELinux: failure in sel_netif_sid_slow()," 18271f1cb05SPaul Moore " unable to determine network interface label (%d)\n", 18371f1cb05SPaul Moore ifindex); 184e8bfdb9dSPaul Moore kfree(new); 18571f1cb05SPaul Moore } 1861da177e4SLinus Torvalds return ret; 1871da177e4SLinus Torvalds } 1881da177e4SLinus Torvalds 189e8bfdb9dSPaul Moore /** 190e8bfdb9dSPaul Moore * sel_netif_sid - Lookup the SID of a network interface 191*cbe0d6e8SPaul Moore * @ns: the network namespace 192e8bfdb9dSPaul Moore * @ifindex: the network interface 193e8bfdb9dSPaul Moore * @sid: interface SID 194e8bfdb9dSPaul Moore * 195e8bfdb9dSPaul Moore * Description: 196e8bfdb9dSPaul Moore * This function determines the SID of a network interface using the fastest 197e8bfdb9dSPaul Moore * method possible. First the interface table is queried, but if an entry 198e8bfdb9dSPaul Moore * can't be found then the policy is queried and the result is added to the 199e8bfdb9dSPaul Moore * table to speedup future queries. Returns zero on success, negative values 200e8bfdb9dSPaul Moore * on failure. 201e8bfdb9dSPaul Moore * 202e8bfdb9dSPaul Moore */ 203*cbe0d6e8SPaul Moore int sel_netif_sid(struct net *ns, int ifindex, u32 *sid) 2041da177e4SLinus Torvalds { 2051da177e4SLinus Torvalds struct sel_netif *netif; 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds rcu_read_lock(); 208*cbe0d6e8SPaul Moore netif = sel_netif_find(ns, ifindex); 209e8bfdb9dSPaul Moore if (likely(netif != NULL)) { 210e8bfdb9dSPaul Moore *sid = netif->nsec.sid; 2111da177e4SLinus Torvalds rcu_read_unlock(); 212e8bfdb9dSPaul Moore return 0; 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds rcu_read_unlock(); 215e8bfdb9dSPaul Moore 216*cbe0d6e8SPaul Moore return sel_netif_sid_slow(ns, ifindex, sid); 2171da177e4SLinus Torvalds } 2181da177e4SLinus Torvalds 219e8bfdb9dSPaul Moore /** 220e8bfdb9dSPaul Moore * sel_netif_kill - Remove an entry from the network interface table 221*cbe0d6e8SPaul Moore * @ns: the network namespace 222e8bfdb9dSPaul Moore * @ifindex: the network interface 223e8bfdb9dSPaul Moore * 224e8bfdb9dSPaul Moore * Description: 225e8bfdb9dSPaul Moore * This function removes the entry matching @ifindex from the network interface 226e8bfdb9dSPaul Moore * table if it exists. 227e8bfdb9dSPaul Moore * 228e8bfdb9dSPaul Moore */ 229*cbe0d6e8SPaul Moore static void sel_netif_kill(const struct net *ns, int ifindex) 2301da177e4SLinus Torvalds { 2311da177e4SLinus Torvalds struct sel_netif *netif; 2321da177e4SLinus Torvalds 23361844250SPaul E. McKenney rcu_read_lock(); 2341da177e4SLinus Torvalds spin_lock_bh(&sel_netif_lock); 235*cbe0d6e8SPaul Moore netif = sel_netif_find(ns, ifindex); 2361da177e4SLinus Torvalds if (netif) 2371da177e4SLinus Torvalds sel_netif_destroy(netif); 2381da177e4SLinus Torvalds spin_unlock_bh(&sel_netif_lock); 23961844250SPaul E. McKenney rcu_read_unlock(); 2401da177e4SLinus Torvalds } 2411da177e4SLinus Torvalds 242e8bfdb9dSPaul Moore /** 243e8bfdb9dSPaul Moore * sel_netif_flush - Flush the entire network interface table 244e8bfdb9dSPaul Moore * 245e8bfdb9dSPaul Moore * Description: 246e8bfdb9dSPaul Moore * Remove all entries from the network interface table. 247e8bfdb9dSPaul Moore * 248e8bfdb9dSPaul Moore */ 249615e51fdSPaul Moore void sel_netif_flush(void) 2501da177e4SLinus Torvalds { 2511da177e4SLinus Torvalds int idx; 2521da177e4SLinus Torvalds struct sel_netif *netif; 2531da177e4SLinus Torvalds 254e8bfdb9dSPaul Moore spin_lock_bh(&sel_netif_lock); 255e8bfdb9dSPaul Moore for (idx = 0; idx < SEL_NETIF_HASH_SIZE; idx++) 2561da177e4SLinus Torvalds list_for_each_entry(netif, &sel_netif_hash[idx], list) 2571da177e4SLinus Torvalds sel_netif_destroy(netif); 2581da177e4SLinus Torvalds spin_unlock_bh(&sel_netif_lock); 2591da177e4SLinus Torvalds } 2601da177e4SLinus Torvalds 2611da177e4SLinus Torvalds static int sel_netif_netdev_notifier_handler(struct notifier_block *this, 2621da177e4SLinus Torvalds unsigned long event, void *ptr) 2631da177e4SLinus Torvalds { 264351638e7SJiri Pirko struct net_device *dev = netdev_notifier_info_to_dev(ptr); 2651da177e4SLinus Torvalds 2661da177e4SLinus Torvalds if (event == NETDEV_DOWN) 267*cbe0d6e8SPaul Moore sel_netif_kill(dev_net(dev), dev->ifindex); 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds return NOTIFY_DONE; 2701da177e4SLinus Torvalds } 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds static struct notifier_block sel_netif_netdev_notifier = { 2731da177e4SLinus Torvalds .notifier_call = sel_netif_netdev_notifier_handler, 2741da177e4SLinus Torvalds }; 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds static __init int sel_netif_init(void) 2771da177e4SLinus Torvalds { 278e8bfdb9dSPaul Moore int i, err; 2791da177e4SLinus Torvalds 2801da177e4SLinus Torvalds if (!selinux_enabled) 281e8bfdb9dSPaul Moore return 0; 2821da177e4SLinus Torvalds 2831da177e4SLinus Torvalds for (i = 0; i < SEL_NETIF_HASH_SIZE; i++) 2841da177e4SLinus Torvalds INIT_LIST_HEAD(&sel_netif_hash[i]); 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds register_netdevice_notifier(&sel_netif_netdev_notifier); 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds return err; 2891da177e4SLinus Torvalds } 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds __initcall(sel_netif_init); 2921da177e4SLinus Torvalds 293