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