linux/security/selinux/netif.c
<<
>>
Prefs
   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
  32struct sel_netif {
  33        struct list_head list;
  34        struct netif_security_struct nsec;
  35        struct rcu_head rcu_head;
  36};
  37
  38static u32 sel_netif_total;
  39static DEFINE_SPINLOCK(sel_netif_lock);
  40static 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 */
  52static 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 */
  67static inline struct sel_netif *sel_netif_find(const struct net *ns,
  68                                               int ifindex)
  69{
  70        int 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 */
  90static int sel_netif_insert(struct sel_netif *netif)
  91{
  92        int 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 */
 112static 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 */
 132static 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(&selinux_state, dev->name, sid);
 157        if (ret != 0)
 158                goto out;
 159        new = kzalloc(sizeof(*new), GFP_ATOMIC);
 160        if (new) {
 161                new->nsec.ns = ns;
 162                new->nsec.ifindex = ifindex;
 163                new->nsec.sid = *sid;
 164                if (sel_netif_insert(new))
 165                        kfree(new);
 166        }
 167
 168out:
 169        spin_unlock_bh(&sel_netif_lock);
 170        dev_put(dev);
 171        if (unlikely(ret))
 172                pr_warn("SELinux: failure in %s(), unable to determine network interface label (%d)\n",
 173                        __func__, ifindex);
 174        return ret;
 175}
 176
 177/**
 178 * sel_netif_sid - Lookup the SID of a network interface
 179 * @ns: the network namespace
 180 * @ifindex: the network interface
 181 * @sid: interface SID
 182 *
 183 * Description:
 184 * This function determines the SID of a network interface using the fastest
 185 * method possible.  First the interface table is queried, but if an entry
 186 * can't be found then the policy is queried and the result is added to the
 187 * table to speedup future queries.  Returns zero on success, negative values
 188 * on failure.
 189 *
 190 */
 191int sel_netif_sid(struct net *ns, int ifindex, u32 *sid)
 192{
 193        struct sel_netif *netif;
 194
 195        rcu_read_lock();
 196        netif = sel_netif_find(ns, ifindex);
 197        if (likely(netif != NULL)) {
 198                *sid = netif->nsec.sid;
 199                rcu_read_unlock();
 200                return 0;
 201        }
 202        rcu_read_unlock();
 203
 204        return sel_netif_sid_slow(ns, ifindex, sid);
 205}
 206
 207/**
 208 * sel_netif_kill - Remove an entry from the network interface table
 209 * @ns: the network namespace
 210 * @ifindex: the network interface
 211 *
 212 * Description:
 213 * This function removes the entry matching @ifindex from the network interface
 214 * table if it exists.
 215 *
 216 */
 217static void sel_netif_kill(const struct net *ns, int ifindex)
 218{
 219        struct sel_netif *netif;
 220
 221        rcu_read_lock();
 222        spin_lock_bh(&sel_netif_lock);
 223        netif = sel_netif_find(ns, ifindex);
 224        if (netif)
 225                sel_netif_destroy(netif);
 226        spin_unlock_bh(&sel_netif_lock);
 227        rcu_read_unlock();
 228}
 229
 230/**
 231 * sel_netif_flush - Flush the entire network interface table
 232 *
 233 * Description:
 234 * Remove all entries from the network interface table.
 235 *
 236 */
 237void sel_netif_flush(void)
 238{
 239        int idx;
 240        struct sel_netif *netif;
 241
 242        spin_lock_bh(&sel_netif_lock);
 243        for (idx = 0; idx < SEL_NETIF_HASH_SIZE; idx++)
 244                list_for_each_entry(netif, &sel_netif_hash[idx], list)
 245                        sel_netif_destroy(netif);
 246        spin_unlock_bh(&sel_netif_lock);
 247}
 248
 249static int sel_netif_netdev_notifier_handler(struct notifier_block *this,
 250                                             unsigned long event, void *ptr)
 251{
 252        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
 253
 254        if (event == NETDEV_DOWN)
 255                sel_netif_kill(dev_net(dev), dev->ifindex);
 256
 257        return NOTIFY_DONE;
 258}
 259
 260static struct notifier_block sel_netif_netdev_notifier = {
 261        .notifier_call = sel_netif_netdev_notifier_handler,
 262};
 263
 264static __init int sel_netif_init(void)
 265{
 266        int i;
 267
 268        if (!selinux_enabled_boot)
 269                return 0;
 270
 271        for (i = 0; i < SEL_NETIF_HASH_SIZE; i++)
 272                INIT_LIST_HEAD(&sel_netif_hash[i]);
 273
 274        register_netdevice_notifier(&sel_netif_netdev_notifier);
 275
 276        return 0;
 277}
 278
 279__initcall(sel_netif_init);
 280
 281