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