root/security/selinux/netif.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sel_netif_hashfn
  2. sel_netif_find
  3. sel_netif_insert
  4. sel_netif_destroy
  5. sel_netif_sid_slow
  6. sel_netif_sid
  7. sel_netif_kill
  8. sel_netif_flush
  9. sel_netif_netdev_notifier_handler
  10. sel_netif_init

   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 LIST_HEAD(sel_netif_list);
  40 static DEFINE_SPINLOCK(sel_netif_lock);
  41 static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE];
  42 
  43 /**
  44  * sel_netif_hashfn - Hashing function for the interface table
  45  * @ns: the network namespace
  46  * @ifindex: the network interface
  47  *
  48  * Description:
  49  * This is the hashing function for the network interface table, it returns the
  50  * bucket number for the given interface.
  51  *
  52  */
  53 static inline u32 sel_netif_hashfn(const struct net *ns, int ifindex)
  54 {
  55         return (((uintptr_t)ns + ifindex) & (SEL_NETIF_HASH_SIZE - 1));
  56 }
  57 
  58 /**
  59  * sel_netif_find - Search for an interface record
  60  * @ns: the network namespace
  61  * @ifindex: the network interface
  62  *
  63  * Description:
  64  * Search the network interface table and return the record matching @ifindex.
  65  * If an entry can not be found in the table return NULL.
  66  *
  67  */
  68 static inline struct sel_netif *sel_netif_find(const struct net *ns,
  69                                                int ifindex)
  70 {
  71         int idx = sel_netif_hashfn(ns, ifindex);
  72         struct sel_netif *netif;
  73 
  74         list_for_each_entry_rcu(netif, &sel_netif_hash[idx], list)
  75                 if (net_eq(netif->nsec.ns, ns) &&
  76                     netif->nsec.ifindex == ifindex)
  77                         return netif;
  78 
  79         return NULL;
  80 }
  81 
  82 /**
  83  * sel_netif_insert - Insert a new interface into the table
  84  * @netif: the new interface record
  85  *
  86  * Description:
  87  * Add a new interface record to the network interface hash table.  Returns
  88  * zero on success, negative values on failure.
  89  *
  90  */
  91 static int sel_netif_insert(struct sel_netif *netif)
  92 {
  93         int idx;
  94 
  95         if (sel_netif_total >= SEL_NETIF_HASH_MAX)
  96                 return -ENOSPC;
  97 
  98         idx = sel_netif_hashfn(netif->nsec.ns, netif->nsec.ifindex);
  99         list_add_rcu(&netif->list, &sel_netif_hash[idx]);
 100         sel_netif_total++;
 101 
 102         return 0;
 103 }
 104 
 105 /**
 106  * sel_netif_destroy - Remove an interface record from the table
 107  * @netif: the existing interface record
 108  *
 109  * Description:
 110  * Remove an existing interface record from the network interface table.
 111  *
 112  */
 113 static void sel_netif_destroy(struct sel_netif *netif)
 114 {
 115         list_del_rcu(&netif->list);
 116         sel_netif_total--;
 117         kfree_rcu(netif, rcu_head);
 118 }
 119 
 120 /**
 121  * sel_netif_sid_slow - Lookup the SID of a network interface using the policy
 122  * @ns: the network namespace
 123  * @ifindex: the network interface
 124  * @sid: interface SID
 125  *
 126  * Description:
 127  * This function determines the SID of a network interface by quering the
 128  * security policy.  The result is added to the network interface table to
 129  * speedup future queries.  Returns zero on success, negative values on
 130  * failure.
 131  *
 132  */
 133 static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid)
 134 {
 135         int ret = 0;
 136         struct sel_netif *netif;
 137         struct sel_netif *new;
 138         struct net_device *dev;
 139 
 140         /* NOTE: we always use init's network namespace since we don't
 141          * currently support containers */
 142 
 143         dev = dev_get_by_index(ns, ifindex);
 144         if (unlikely(dev == NULL)) {
 145                 pr_warn("SELinux: failure in %s(), invalid network interface (%d)\n",
 146                         __func__, ifindex);
 147                 return -ENOENT;
 148         }
 149 
 150         spin_lock_bh(&sel_netif_lock);
 151         netif = sel_netif_find(ns, ifindex);
 152         if (netif != NULL) {
 153                 *sid = netif->nsec.sid;
 154                 goto out;
 155         }
 156 
 157         ret = security_netif_sid(&selinux_state, dev->name, sid);
 158         if (ret != 0)
 159                 goto out;
 160         new = kzalloc(sizeof(*new), GFP_ATOMIC);
 161         if (new) {
 162                 new->nsec.ns = ns;
 163                 new->nsec.ifindex = ifindex;
 164                 new->nsec.sid = *sid;
 165                 if (sel_netif_insert(new))
 166                         kfree(new);
 167         }
 168 
 169 out:
 170         spin_unlock_bh(&sel_netif_lock);
 171         dev_put(dev);
 172         if (unlikely(ret))
 173                 pr_warn("SELinux: failure in %s(), unable to determine network interface label (%d)\n",
 174                         __func__, ifindex);
 175         return ret;
 176 }
 177 
 178 /**
 179  * sel_netif_sid - Lookup the SID of a network interface
 180  * @ns: the network namespace
 181  * @ifindex: the network interface
 182  * @sid: interface SID
 183  *
 184  * Description:
 185  * This function determines the SID of a network interface using the fastest
 186  * method possible.  First the interface table is queried, but if an entry
 187  * can't be found then the policy is queried and the result is added to the
 188  * table to speedup future queries.  Returns zero on success, negative values
 189  * on failure.
 190  *
 191  */
 192 int sel_netif_sid(struct net *ns, int ifindex, u32 *sid)
 193 {
 194         struct sel_netif *netif;
 195 
 196         rcu_read_lock();
 197         netif = sel_netif_find(ns, ifindex);
 198         if (likely(netif != NULL)) {
 199                 *sid = netif->nsec.sid;
 200                 rcu_read_unlock();
 201                 return 0;
 202         }
 203         rcu_read_unlock();
 204 
 205         return sel_netif_sid_slow(ns, ifindex, sid);
 206 }
 207 
 208 /**
 209  * sel_netif_kill - Remove an entry from the network interface table
 210  * @ns: the network namespace
 211  * @ifindex: the network interface
 212  *
 213  * Description:
 214  * This function removes the entry matching @ifindex from the network interface
 215  * table if it exists.
 216  *
 217  */
 218 static void sel_netif_kill(const struct net *ns, int ifindex)
 219 {
 220         struct sel_netif *netif;
 221 
 222         rcu_read_lock();
 223         spin_lock_bh(&sel_netif_lock);
 224         netif = sel_netif_find(ns, ifindex);
 225         if (netif)
 226                 sel_netif_destroy(netif);
 227         spin_unlock_bh(&sel_netif_lock);
 228         rcu_read_unlock();
 229 }
 230 
 231 /**
 232  * sel_netif_flush - Flush the entire network interface table
 233  *
 234  * Description:
 235  * Remove all entries from the network interface table.
 236  *
 237  */
 238 void sel_netif_flush(void)
 239 {
 240         int idx;
 241         struct sel_netif *netif;
 242 
 243         spin_lock_bh(&sel_netif_lock);
 244         for (idx = 0; idx < SEL_NETIF_HASH_SIZE; idx++)
 245                 list_for_each_entry(netif, &sel_netif_hash[idx], list)
 246                         sel_netif_destroy(netif);
 247         spin_unlock_bh(&sel_netif_lock);
 248 }
 249 
 250 static int sel_netif_netdev_notifier_handler(struct notifier_block *this,
 251                                              unsigned long event, void *ptr)
 252 {
 253         struct net_device *dev = netdev_notifier_info_to_dev(ptr);
 254 
 255         if (event == NETDEV_DOWN)
 256                 sel_netif_kill(dev_net(dev), dev->ifindex);
 257 
 258         return NOTIFY_DONE;
 259 }
 260 
 261 static struct notifier_block sel_netif_netdev_notifier = {
 262         .notifier_call = sel_netif_netdev_notifier_handler,
 263 };
 264 
 265 static __init int sel_netif_init(void)
 266 {
 267         int i;
 268 
 269         if (!selinux_enabled)
 270                 return 0;
 271 
 272         for (i = 0; i < SEL_NETIF_HASH_SIZE; i++)
 273                 INIT_LIST_HEAD(&sel_netif_hash[i]);
 274 
 275         register_netdevice_notifier(&sel_netif_netdev_notifier);
 276 
 277         return 0;
 278 }
 279 
 280 __initcall(sel_netif_init);
 281 

/* [<][>][^][v][top][bottom][index][help] */