]> git.itanic.dy.fi Git - linux-stable/blob - drivers/net/wireguard/selftest/ratelimiter.c
wireguard: ratelimiter: disable timings test by default
[linux-stable] / drivers / net / wireguard / selftest / ratelimiter.c
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
10 static 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
23 static __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
33 static __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
97 static __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
118 bool __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; IS_ENABLED(DEBUG_RATELIMITER_TIMINGS);) {
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                         continue;
180                 } else if (ret < 0) {
181                         test += test_count;
182                         goto err;
183                 } else {
184                         test += test_count;
185                         break;
186                 }
187         }
188
189         for (trials = TRIALS_BEFORE_GIVING_UP;;) {
190                 int test_count = 0;
191
192                 if (capacity_test(skb4, hdr4, &test_count) < 0) {
193                         if (!trials--) {
194                                 test += test_count;
195                                 goto err;
196                         }
197                         continue;
198                 }
199                 test += test_count;
200                 break;
201         }
202
203         success = true;
204
205 err:
206         kfree_skb(skb4);
207 #if IS_ENABLED(CONFIG_IPV6)
208         kfree_skb(skb6);
209 #endif
210 err_nofree:
211         wg_ratelimiter_uninit();
212         wg_ratelimiter_uninit();
213         wg_ratelimiter_uninit();
214         /* Uninit one extra time to check underflow detection. */
215         wg_ratelimiter_uninit();
216 out:
217         if (success)
218                 pr_info("ratelimiter self-tests: pass\n");
219         else
220                 pr_err("ratelimiter self-test %d: FAIL\n", test);
221
222         return success;
223 }
224 #endif