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

hash.c (11935B)


      1/*
      2 * Copyright (c) 2016 Citrix Systems Inc.
      3 *
      4 * This program is free software; you can redistribute it and/or
      5 * modify it under the terms of the GNU General Public License version 2
      6 * as published by the Free Softare Foundation; or, when distributed
      7 * separately from the Linux kernel or incorporated into other
      8 * software packages, subject to the following license:
      9 *
     10 * Permission is hereby granted, free of charge, to any person obtaining a copy
     11 * of this source file (the "Software"), to deal in the Software without
     12 * restriction, including without limitation the rights to use, copy, modify,
     13 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
     14 * and to permit persons to whom the Software is furnished to do so, subject to
     15 * the following conditions:
     16 *
     17 * The above copyright notice and this permission notice shall be included in
     18 * all copies or substantial portions of the Software.
     19 *
     20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     26 * IN THE SOFTWARE.
     27 */
     28
     29#define XEN_NETIF_DEFINE_TOEPLITZ
     30
     31#include "common.h"
     32#include <linux/vmalloc.h>
     33#include <linux/rculist.h>
     34
     35static void xenvif_add_hash(struct xenvif *vif, const u8 *tag,
     36			    unsigned int len, u32 val)
     37{
     38	struct xenvif_hash_cache_entry *new, *entry, *oldest;
     39	unsigned long flags;
     40	bool found;
     41
     42	new = kmalloc(sizeof(*entry), GFP_ATOMIC);
     43	if (!new)
     44		return;
     45
     46	memcpy(new->tag, tag, len);
     47	new->len = len;
     48	new->val = val;
     49
     50	spin_lock_irqsave(&vif->hash.cache.lock, flags);
     51
     52	found = false;
     53	oldest = NULL;
     54	list_for_each_entry_rcu(entry, &vif->hash.cache.list, link,
     55				lockdep_is_held(&vif->hash.cache.lock)) {
     56		/* Make sure we don't add duplicate entries */
     57		if (entry->len == len &&
     58		    memcmp(entry->tag, tag, len) == 0)
     59			found = true;
     60		if (!oldest || entry->seq < oldest->seq)
     61			oldest = entry;
     62	}
     63
     64	if (!found) {
     65		new->seq = atomic_inc_return(&vif->hash.cache.seq);
     66		list_add_rcu(&new->link, &vif->hash.cache.list);
     67
     68		if (++vif->hash.cache.count > xenvif_hash_cache_size) {
     69			list_del_rcu(&oldest->link);
     70			vif->hash.cache.count--;
     71			kfree_rcu(oldest, rcu);
     72		}
     73	}
     74
     75	spin_unlock_irqrestore(&vif->hash.cache.lock, flags);
     76
     77	if (found)
     78		kfree(new);
     79}
     80
     81static u32 xenvif_new_hash(struct xenvif *vif, const u8 *data,
     82			   unsigned int len)
     83{
     84	u32 val;
     85
     86	val = xen_netif_toeplitz_hash(vif->hash.key,
     87				      sizeof(vif->hash.key),
     88				      data, len);
     89
     90	if (xenvif_hash_cache_size != 0)
     91		xenvif_add_hash(vif, data, len, val);
     92
     93	return val;
     94}
     95
     96static void xenvif_flush_hash(struct xenvif *vif)
     97{
     98	struct xenvif_hash_cache_entry *entry;
     99	unsigned long flags;
    100
    101	if (xenvif_hash_cache_size == 0)
    102		return;
    103
    104	spin_lock_irqsave(&vif->hash.cache.lock, flags);
    105
    106	list_for_each_entry_rcu(entry, &vif->hash.cache.list, link,
    107				lockdep_is_held(&vif->hash.cache.lock)) {
    108		list_del_rcu(&entry->link);
    109		vif->hash.cache.count--;
    110		kfree_rcu(entry, rcu);
    111	}
    112
    113	spin_unlock_irqrestore(&vif->hash.cache.lock, flags);
    114}
    115
    116static u32 xenvif_find_hash(struct xenvif *vif, const u8 *data,
    117			    unsigned int len)
    118{
    119	struct xenvif_hash_cache_entry *entry;
    120	u32 val;
    121	bool found;
    122
    123	if (len >= XEN_NETBK_HASH_TAG_SIZE)
    124		return 0;
    125
    126	if (xenvif_hash_cache_size == 0)
    127		return xenvif_new_hash(vif, data, len);
    128
    129	rcu_read_lock();
    130
    131	found = false;
    132
    133	list_for_each_entry_rcu(entry, &vif->hash.cache.list, link) {
    134		if (entry->len == len &&
    135		    memcmp(entry->tag, data, len) == 0) {
    136			val = entry->val;
    137			entry->seq = atomic_inc_return(&vif->hash.cache.seq);
    138			found = true;
    139			break;
    140		}
    141	}
    142
    143	rcu_read_unlock();
    144
    145	if (!found)
    146		val = xenvif_new_hash(vif, data, len);
    147
    148	return val;
    149}
    150
    151void xenvif_set_skb_hash(struct xenvif *vif, struct sk_buff *skb)
    152{
    153	struct flow_keys flow;
    154	u32 hash = 0;
    155	enum pkt_hash_types type = PKT_HASH_TYPE_NONE;
    156	u32 flags = vif->hash.flags;
    157	bool has_tcp_hdr;
    158
    159	/* Quick rejection test: If the network protocol doesn't
    160	 * correspond to any enabled hash type then there's no point
    161	 * in parsing the packet header.
    162	 */
    163	switch (skb->protocol) {
    164	case htons(ETH_P_IP):
    165		if (flags & (XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP |
    166			     XEN_NETIF_CTRL_HASH_TYPE_IPV4))
    167			break;
    168
    169		goto done;
    170
    171	case htons(ETH_P_IPV6):
    172		if (flags & (XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP |
    173			     XEN_NETIF_CTRL_HASH_TYPE_IPV6))
    174			break;
    175
    176		goto done;
    177
    178	default:
    179		goto done;
    180	}
    181
    182	memset(&flow, 0, sizeof(flow));
    183	if (!skb_flow_dissect_flow_keys(skb, &flow, 0))
    184		goto done;
    185
    186	has_tcp_hdr = (flow.basic.ip_proto == IPPROTO_TCP) &&
    187		      !(flow.control.flags & FLOW_DIS_IS_FRAGMENT);
    188
    189	switch (skb->protocol) {
    190	case htons(ETH_P_IP):
    191		if (has_tcp_hdr &&
    192		    (flags & XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP)) {
    193			u8 data[12];
    194
    195			memcpy(&data[0], &flow.addrs.v4addrs.src, 4);
    196			memcpy(&data[4], &flow.addrs.v4addrs.dst, 4);
    197			memcpy(&data[8], &flow.ports.src, 2);
    198			memcpy(&data[10], &flow.ports.dst, 2);
    199
    200			hash = xenvif_find_hash(vif, data, sizeof(data));
    201			type = PKT_HASH_TYPE_L4;
    202		} else if (flags & XEN_NETIF_CTRL_HASH_TYPE_IPV4) {
    203			u8 data[8];
    204
    205			memcpy(&data[0], &flow.addrs.v4addrs.src, 4);
    206			memcpy(&data[4], &flow.addrs.v4addrs.dst, 4);
    207
    208			hash = xenvif_find_hash(vif, data, sizeof(data));
    209			type = PKT_HASH_TYPE_L3;
    210		}
    211
    212		break;
    213
    214	case htons(ETH_P_IPV6):
    215		if (has_tcp_hdr &&
    216		    (flags & XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP)) {
    217			u8 data[36];
    218
    219			memcpy(&data[0], &flow.addrs.v6addrs.src, 16);
    220			memcpy(&data[16], &flow.addrs.v6addrs.dst, 16);
    221			memcpy(&data[32], &flow.ports.src, 2);
    222			memcpy(&data[34], &flow.ports.dst, 2);
    223
    224			hash = xenvif_find_hash(vif, data, sizeof(data));
    225			type = PKT_HASH_TYPE_L4;
    226		} else if (flags & XEN_NETIF_CTRL_HASH_TYPE_IPV6) {
    227			u8 data[32];
    228
    229			memcpy(&data[0], &flow.addrs.v6addrs.src, 16);
    230			memcpy(&data[16], &flow.addrs.v6addrs.dst, 16);
    231
    232			hash = xenvif_find_hash(vif, data, sizeof(data));
    233			type = PKT_HASH_TYPE_L3;
    234		}
    235
    236		break;
    237	}
    238
    239done:
    240	if (type == PKT_HASH_TYPE_NONE)
    241		skb_clear_hash(skb);
    242	else
    243		__skb_set_sw_hash(skb, hash, type == PKT_HASH_TYPE_L4);
    244}
    245
    246u32 xenvif_set_hash_alg(struct xenvif *vif, u32 alg)
    247{
    248	switch (alg) {
    249	case XEN_NETIF_CTRL_HASH_ALGORITHM_NONE:
    250	case XEN_NETIF_CTRL_HASH_ALGORITHM_TOEPLITZ:
    251		break;
    252
    253	default:
    254		return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
    255	}
    256
    257	vif->hash.alg = alg;
    258
    259	return XEN_NETIF_CTRL_STATUS_SUCCESS;
    260}
    261
    262u32 xenvif_get_hash_flags(struct xenvif *vif, u32 *flags)
    263{
    264	if (vif->hash.alg == XEN_NETIF_CTRL_HASH_ALGORITHM_NONE)
    265		return XEN_NETIF_CTRL_STATUS_NOT_SUPPORTED;
    266
    267	*flags = XEN_NETIF_CTRL_HASH_TYPE_IPV4 |
    268		 XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP |
    269		 XEN_NETIF_CTRL_HASH_TYPE_IPV6 |
    270		 XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP;
    271
    272	return XEN_NETIF_CTRL_STATUS_SUCCESS;
    273}
    274
    275u32 xenvif_set_hash_flags(struct xenvif *vif, u32 flags)
    276{
    277	if (flags & ~(XEN_NETIF_CTRL_HASH_TYPE_IPV4 |
    278		      XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP |
    279		      XEN_NETIF_CTRL_HASH_TYPE_IPV6 |
    280		      XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP))
    281		return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
    282
    283	if (vif->hash.alg == XEN_NETIF_CTRL_HASH_ALGORITHM_NONE)
    284		return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
    285
    286	vif->hash.flags = flags;
    287
    288	return XEN_NETIF_CTRL_STATUS_SUCCESS;
    289}
    290
    291u32 xenvif_set_hash_key(struct xenvif *vif, u32 gref, u32 len)
    292{
    293	u8 *key = vif->hash.key;
    294	struct gnttab_copy copy_op = {
    295		.source.u.ref = gref,
    296		.source.domid = vif->domid,
    297		.dest.u.gmfn = virt_to_gfn(key),
    298		.dest.domid = DOMID_SELF,
    299		.dest.offset = xen_offset_in_page(key),
    300		.len = len,
    301		.flags = GNTCOPY_source_gref
    302	};
    303
    304	if (len > XEN_NETBK_MAX_HASH_KEY_SIZE)
    305		return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
    306
    307	if (copy_op.len != 0) {
    308		gnttab_batch_copy(&copy_op, 1);
    309
    310		if (copy_op.status != GNTST_okay)
    311			return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
    312	}
    313
    314	/* Clear any remaining key octets */
    315	if (len < XEN_NETBK_MAX_HASH_KEY_SIZE)
    316		memset(key + len, 0, XEN_NETBK_MAX_HASH_KEY_SIZE - len);
    317
    318	xenvif_flush_hash(vif);
    319
    320	return XEN_NETIF_CTRL_STATUS_SUCCESS;
    321}
    322
    323u32 xenvif_set_hash_mapping_size(struct xenvif *vif, u32 size)
    324{
    325	if (size > XEN_NETBK_MAX_HASH_MAPPING_SIZE)
    326		return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
    327
    328	vif->hash.size = size;
    329	memset(vif->hash.mapping[vif->hash.mapping_sel], 0,
    330	       sizeof(u32) * size);
    331
    332	return XEN_NETIF_CTRL_STATUS_SUCCESS;
    333}
    334
    335u32 xenvif_set_hash_mapping(struct xenvif *vif, u32 gref, u32 len,
    336			    u32 off)
    337{
    338	u32 *mapping = vif->hash.mapping[!vif->hash.mapping_sel];
    339	unsigned int nr = 1;
    340	struct gnttab_copy copy_op[2] = {{
    341		.source.u.ref = gref,
    342		.source.domid = vif->domid,
    343		.dest.domid = DOMID_SELF,
    344		.len = len * sizeof(*mapping),
    345		.flags = GNTCOPY_source_gref
    346	}};
    347
    348	if ((off + len < off) || (off + len > vif->hash.size) ||
    349	    len > XEN_PAGE_SIZE / sizeof(*mapping))
    350		return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
    351
    352	copy_op[0].dest.u.gmfn = virt_to_gfn(mapping + off);
    353	copy_op[0].dest.offset = xen_offset_in_page(mapping + off);
    354	if (copy_op[0].dest.offset + copy_op[0].len > XEN_PAGE_SIZE) {
    355		copy_op[1] = copy_op[0];
    356		copy_op[1].source.offset = XEN_PAGE_SIZE - copy_op[0].dest.offset;
    357		copy_op[1].dest.u.gmfn = virt_to_gfn(mapping + off + len);
    358		copy_op[1].dest.offset = 0;
    359		copy_op[1].len = copy_op[0].len - copy_op[1].source.offset;
    360		copy_op[0].len = copy_op[1].source.offset;
    361		nr = 2;
    362	}
    363
    364	memcpy(mapping, vif->hash.mapping[vif->hash.mapping_sel],
    365	       vif->hash.size * sizeof(*mapping));
    366
    367	if (copy_op[0].len != 0) {
    368		gnttab_batch_copy(copy_op, nr);
    369
    370		if (copy_op[0].status != GNTST_okay ||
    371		    copy_op[nr - 1].status != GNTST_okay)
    372			return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
    373	}
    374
    375	while (len-- != 0)
    376		if (mapping[off++] >= vif->num_queues)
    377			return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
    378
    379	vif->hash.mapping_sel = !vif->hash.mapping_sel;
    380
    381	return XEN_NETIF_CTRL_STATUS_SUCCESS;
    382}
    383
    384#ifdef CONFIG_DEBUG_FS
    385void xenvif_dump_hash_info(struct xenvif *vif, struct seq_file *m)
    386{
    387	unsigned int i;
    388
    389	switch (vif->hash.alg) {
    390	case XEN_NETIF_CTRL_HASH_ALGORITHM_TOEPLITZ:
    391		seq_puts(m, "Hash Algorithm: TOEPLITZ\n");
    392		break;
    393
    394	case XEN_NETIF_CTRL_HASH_ALGORITHM_NONE:
    395		seq_puts(m, "Hash Algorithm: NONE\n");
    396		fallthrough;
    397	default:
    398		return;
    399	}
    400
    401	if (vif->hash.flags) {
    402		seq_puts(m, "\nHash Flags:\n");
    403
    404		if (vif->hash.flags & XEN_NETIF_CTRL_HASH_TYPE_IPV4)
    405			seq_puts(m, "- IPv4\n");
    406		if (vif->hash.flags & XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP)
    407			seq_puts(m, "- IPv4 + TCP\n");
    408		if (vif->hash.flags & XEN_NETIF_CTRL_HASH_TYPE_IPV6)
    409			seq_puts(m, "- IPv6\n");
    410		if (vif->hash.flags & XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP)
    411			seq_puts(m, "- IPv6 + TCP\n");
    412	}
    413
    414	seq_puts(m, "\nHash Key:\n");
    415
    416	for (i = 0; i < XEN_NETBK_MAX_HASH_KEY_SIZE; ) {
    417		unsigned int j, n;
    418
    419		n = 8;
    420		if (i + n >= XEN_NETBK_MAX_HASH_KEY_SIZE)
    421			n = XEN_NETBK_MAX_HASH_KEY_SIZE - i;
    422
    423		seq_printf(m, "[%2u - %2u]: ", i, i + n - 1);
    424
    425		for (j = 0; j < n; j++, i++)
    426			seq_printf(m, "%02x ", vif->hash.key[i]);
    427
    428		seq_puts(m, "\n");
    429	}
    430
    431	if (vif->hash.size != 0) {
    432		const u32 *mapping = vif->hash.mapping[vif->hash.mapping_sel];
    433
    434		seq_puts(m, "\nHash Mapping:\n");
    435
    436		for (i = 0; i < vif->hash.size; ) {
    437			unsigned int j, n;
    438
    439			n = 8;
    440			if (i + n >= vif->hash.size)
    441				n = vif->hash.size - i;
    442
    443			seq_printf(m, "[%4u - %4u]: ", i, i + n - 1);
    444
    445			for (j = 0; j < n; j++, i++)
    446				seq_printf(m, "%4u ", mapping[i]);
    447
    448			seq_puts(m, "\n");
    449		}
    450	}
    451}
    452#endif /* CONFIG_DEBUG_FS */
    453
    454void xenvif_init_hash(struct xenvif *vif)
    455{
    456	if (xenvif_hash_cache_size == 0)
    457		return;
    458
    459	BUG_ON(vif->hash.cache.count);
    460
    461	spin_lock_init(&vif->hash.cache.lock);
    462	INIT_LIST_HEAD(&vif->hash.cache.list);
    463}
    464
    465void xenvif_deinit_hash(struct xenvif *vif)
    466{
    467	xenvif_flush_hash(vif);
    468}