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

ratelimiter.c (5347B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
      4 */
      5
      6#ifdef DEBUG
      7
      8#include <linux/jiffies.h>
      9
     10static const struct {
     11	bool result;
     12	unsigned int msec_to_sleep_before;
     13} expected_results[] __initconst = {
     14	[0 ... PACKETS_BURSTABLE - 1] = { true, 0 },
     15	[PACKETS_BURSTABLE] = { false, 0 },
     16	[PACKETS_BURSTABLE + 1] = { true, MSEC_PER_SEC / PACKETS_PER_SECOND },
     17	[PACKETS_BURSTABLE + 2] = { false, 0 },
     18	[PACKETS_BURSTABLE + 3] = { true, (MSEC_PER_SEC / PACKETS_PER_SECOND) * 2 },
     19	[PACKETS_BURSTABLE + 4] = { true, 0 },
     20	[PACKETS_BURSTABLE + 5] = { false, 0 }
     21};
     22
     23static __init unsigned int maximum_jiffies_at_index(int index)
     24{
     25	unsigned int total_msecs = 2 * MSEC_PER_SEC / PACKETS_PER_SECOND / 3;
     26	int i;
     27
     28	for (i = 0; i <= index; ++i)
     29		total_msecs += expected_results[i].msec_to_sleep_before;
     30	return msecs_to_jiffies(total_msecs);
     31}
     32
     33static __init int timings_test(struct sk_buff *skb4, struct iphdr *hdr4,
     34			       struct sk_buff *skb6, struct ipv6hdr *hdr6,
     35			       int *test)
     36{
     37	unsigned long loop_start_time;
     38	int i;
     39
     40	wg_ratelimiter_gc_entries(NULL);
     41	rcu_barrier();
     42	loop_start_time = jiffies;
     43
     44	for (i = 0; i < ARRAY_SIZE(expected_results); ++i) {
     45		if (expected_results[i].msec_to_sleep_before)
     46			msleep(expected_results[i].msec_to_sleep_before);
     47
     48		if (time_is_before_jiffies(loop_start_time +
     49					   maximum_jiffies_at_index(i)))
     50			return -ETIMEDOUT;
     51		if (wg_ratelimiter_allow(skb4, &init_net) !=
     52					expected_results[i].result)
     53			return -EXFULL;
     54		++(*test);
     55
     56		hdr4->saddr = htonl(ntohl(hdr4->saddr) + i + 1);
     57		if (time_is_before_jiffies(loop_start_time +
     58					   maximum_jiffies_at_index(i)))
     59			return -ETIMEDOUT;
     60		if (!wg_ratelimiter_allow(skb4, &init_net))
     61			return -EXFULL;
     62		++(*test);
     63
     64		hdr4->saddr = htonl(ntohl(hdr4->saddr) - i - 1);
     65
     66#if IS_ENABLED(CONFIG_IPV6)
     67		hdr6->saddr.in6_u.u6_addr32[2] = htonl(i);
     68		hdr6->saddr.in6_u.u6_addr32[3] = htonl(i);
     69		if (time_is_before_jiffies(loop_start_time +
     70					   maximum_jiffies_at_index(i)))
     71			return -ETIMEDOUT;
     72		if (wg_ratelimiter_allow(skb6, &init_net) !=
     73					expected_results[i].result)
     74			return -EXFULL;
     75		++(*test);
     76
     77		hdr6->saddr.in6_u.u6_addr32[0] =
     78			htonl(ntohl(hdr6->saddr.in6_u.u6_addr32[0]) + i + 1);
     79		if (time_is_before_jiffies(loop_start_time +
     80					   maximum_jiffies_at_index(i)))
     81			return -ETIMEDOUT;
     82		if (!wg_ratelimiter_allow(skb6, &init_net))
     83			return -EXFULL;
     84		++(*test);
     85
     86		hdr6->saddr.in6_u.u6_addr32[0] =
     87			htonl(ntohl(hdr6->saddr.in6_u.u6_addr32[0]) - i - 1);
     88
     89		if (time_is_before_jiffies(loop_start_time +
     90					   maximum_jiffies_at_index(i)))
     91			return -ETIMEDOUT;
     92#endif
     93	}
     94	return 0;
     95}
     96
     97static __init int capacity_test(struct sk_buff *skb4, struct iphdr *hdr4,
     98				int *test)
     99{
    100	int i;
    101
    102	wg_ratelimiter_gc_entries(NULL);
    103	rcu_barrier();
    104
    105	if (atomic_read(&total_entries))
    106		return -EXFULL;
    107	++(*test);
    108
    109	for (i = 0; i <= max_entries; ++i) {
    110		hdr4->saddr = htonl(i);
    111		if (wg_ratelimiter_allow(skb4, &init_net) != (i != max_entries))
    112			return -EXFULL;
    113		++(*test);
    114	}
    115	return 0;
    116}
    117
    118bool __init wg_ratelimiter_selftest(void)
    119{
    120	enum { TRIALS_BEFORE_GIVING_UP = 5000 };
    121	bool success = false;
    122	int test = 0, trials;
    123	struct sk_buff *skb4, *skb6 = NULL;
    124	struct iphdr *hdr4;
    125	struct ipv6hdr *hdr6 = NULL;
    126
    127	if (IS_ENABLED(CONFIG_KASAN) || IS_ENABLED(CONFIG_UBSAN))
    128		return true;
    129
    130	BUILD_BUG_ON(MSEC_PER_SEC % PACKETS_PER_SECOND != 0);
    131
    132	if (wg_ratelimiter_init())
    133		goto out;
    134	++test;
    135	if (wg_ratelimiter_init()) {
    136		wg_ratelimiter_uninit();
    137		goto out;
    138	}
    139	++test;
    140	if (wg_ratelimiter_init()) {
    141		wg_ratelimiter_uninit();
    142		wg_ratelimiter_uninit();
    143		goto out;
    144	}
    145	++test;
    146
    147	skb4 = alloc_skb(sizeof(struct iphdr), GFP_KERNEL);
    148	if (unlikely(!skb4))
    149		goto err_nofree;
    150	skb4->protocol = htons(ETH_P_IP);
    151	hdr4 = (struct iphdr *)skb_put(skb4, sizeof(*hdr4));
    152	hdr4->saddr = htonl(8182);
    153	skb_reset_network_header(skb4);
    154	++test;
    155
    156#if IS_ENABLED(CONFIG_IPV6)
    157	skb6 = alloc_skb(sizeof(struct ipv6hdr), GFP_KERNEL);
    158	if (unlikely(!skb6)) {
    159		kfree_skb(skb4);
    160		goto err_nofree;
    161	}
    162	skb6->protocol = htons(ETH_P_IPV6);
    163	hdr6 = (struct ipv6hdr *)skb_put(skb6, sizeof(*hdr6));
    164	hdr6->saddr.in6_u.u6_addr32[0] = htonl(1212);
    165	hdr6->saddr.in6_u.u6_addr32[1] = htonl(289188);
    166	skb_reset_network_header(skb6);
    167	++test;
    168#endif
    169
    170	for (trials = TRIALS_BEFORE_GIVING_UP;;) {
    171		int test_count = 0, ret;
    172
    173		ret = timings_test(skb4, hdr4, skb6, hdr6, &test_count);
    174		if (ret == -ETIMEDOUT) {
    175			if (!trials--) {
    176				test += test_count;
    177				goto err;
    178			}
    179			msleep(500);
    180			continue;
    181		} else if (ret < 0) {
    182			test += test_count;
    183			goto err;
    184		} else {
    185			test += test_count;
    186			break;
    187		}
    188	}
    189
    190	for (trials = TRIALS_BEFORE_GIVING_UP;;) {
    191		int test_count = 0;
    192
    193		if (capacity_test(skb4, hdr4, &test_count) < 0) {
    194			if (!trials--) {
    195				test += test_count;
    196				goto err;
    197			}
    198			msleep(50);
    199			continue;
    200		}
    201		test += test_count;
    202		break;
    203	}
    204
    205	success = true;
    206
    207err:
    208	kfree_skb(skb4);
    209#if IS_ENABLED(CONFIG_IPV6)
    210	kfree_skb(skb6);
    211#endif
    212err_nofree:
    213	wg_ratelimiter_uninit();
    214	wg_ratelimiter_uninit();
    215	wg_ratelimiter_uninit();
    216	/* Uninit one extra time to check underflow detection. */
    217	wg_ratelimiter_uninit();
    218out:
    219	if (success)
    220		pr_info("ratelimiter self-tests: pass\n");
    221	else
    222		pr_err("ratelimiter self-test %d: FAIL\n", test);
    223
    224	return success;
    225}
    226#endif