cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

netif.c (6886B)


      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