1 /*-
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright (C) 2015-2021 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
5 * Copyright (C) 2019-2021 Matt Dunwoodie <ncon@noconroy.net>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject
13 * to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27 #define T_MESSAGE_LEN 64
28 #define T_FAILED_ITER(test) do { \
29 kprintf("%s %s: FAIL, iter: %d\n", __func__, test, i); \
30 goto cleanup; \
31 } while (0)
32 #define T_FAILED(test) do { \
33 kprintf("%s %s: FAIL\n", __func__, test); \
34 goto cleanup; \
35 } while (0)
36 #define T_PASSED kprintf("%s: pass\n", __func__)
37
38 static const struct expected_results {
39 int result;
40 uint64_t sleep_time; /* nanoseconds */
41 } rl_expected[] = {
42 /* [0 ... INITIATIONS_BURSTABLE-1] entries are implied zero. */
43 [INITIATIONS_BURSTABLE] = { ECONNREFUSED, 0 },
44 [INITIATIONS_BURSTABLE + 1] = { 0, INITIATION_COST },
45 [INITIATIONS_BURSTABLE + 2] = { ECONNREFUSED, 0 },
46 [INITIATIONS_BURSTABLE + 3] = { 0, INITIATION_COST * 2 },
47 [INITIATIONS_BURSTABLE + 4] = { 0, 0 },
48 [INITIATIONS_BURSTABLE + 5] = { ECONNREFUSED, 0 },
49 };
50
51 static struct ratelimit rl_test;
52
53 static bool
cookie_ratelimit_timings_test(void)54 cookie_ratelimit_timings_test(void)
55 {
56 struct sockaddr_in sin = { .sin_family = AF_INET };
57 #ifdef INET6
58 struct sockaddr_in6 sin6 = { .sin6_family = AF_INET6 };
59 #endif
60 uint64_t t;
61 int i;
62 bool ret = false;
63
64 ratelimit_init(&rl_test);
65
66 for (i = 0; i < nitems(rl_expected); i++) {
67 if ((t = rl_expected[i].sleep_time) != 0) {
68 tsleep(&rl_test, 0, "rl_test",
69 (int)(t * hz / NSEC_PER_SEC));
70 }
71
72 /*
73 * The first v4 ratelimit_allow is against a constant address,
74 * and should be indifferent to the port.
75 */
76 sin.sin_addr.s_addr = 0x01020304;
77 sin.sin_port = karc4random();
78
79 if (ratelimit_allow(&rl_test, sintosa(&sin))
80 != rl_expected[i].result)
81 T_FAILED_ITER("malicious v4");
82
83 /*
84 * The second ratelimit_allow is to test that an arbitrary
85 * address is still allowed.
86 */
87 sin.sin_addr.s_addr += i + 1;
88 sin.sin_port = karc4random();
89
90 if (ratelimit_allow(&rl_test, sintosa(&sin)) != 0)
91 T_FAILED_ITER("non-malicious v4");
92
93 #ifdef INET6
94 /*
95 * The first v6 ratelimit_allow is against a constant address,
96 * and should be indifferent to the port. We also mutate the
97 * lower 64 bits of the address as we want to ensure ratelimit
98 * occurs against the higher 64 bits (/64 network).
99 */
100 sin6.sin6_addr.s6_addr32[0] = 0x01020304;
101 sin6.sin6_addr.s6_addr32[1] = 0x05060708;
102 sin6.sin6_addr.s6_addr32[2] = i;
103 sin6.sin6_addr.s6_addr32[3] = i;
104 sin6.sin6_port = karc4random();
105
106 if (ratelimit_allow(&rl_test, sin6tosa(&sin6))
107 != rl_expected[i].result)
108 T_FAILED_ITER("malicious v6");
109
110 /*
111 * Again, test that an address different to above is still
112 * allowed.
113 */
114 sin6.sin6_addr.s6_addr32[0] += i + 1;
115 sin6.sin6_port = karc4random();
116
117 if (ratelimit_allow(&rl_test, sintosa(&sin)) != 0)
118 T_FAILED_ITER("non-malicious v6");
119 #endif
120 }
121 T_PASSED;
122 ret = true;
123
124 cleanup:
125 ratelimit_deinit(&rl_test);
126 return (ret);
127 }
128
129 static bool
cookie_ratelimit_capacity_test(void)130 cookie_ratelimit_capacity_test(void)
131 {
132 struct sockaddr_in sin;
133 int i;
134 bool ret = false;
135
136 ratelimit_init(&rl_test);
137
138 sin.sin_family = AF_INET;
139 sin.sin_port = 1234;
140
141 /*
142 * Test that the ratelimiter has an upper bound on the number of
143 * addresses to be limited.
144 */
145 for (i = 0; i <= RATELIMIT_SIZE_MAX; i++) {
146 sin.sin_addr.s_addr = i;
147 if (i == RATELIMIT_SIZE_MAX) {
148 if (ratelimit_allow(&rl_test, sintosa(&sin))
149 != ECONNREFUSED)
150 T_FAILED_ITER("reject");
151 } else {
152 if (ratelimit_allow(&rl_test, sintosa(&sin)) != 0)
153 T_FAILED_ITER("allow");
154 }
155 }
156 T_PASSED;
157 ret = true;
158
159 cleanup:
160 ratelimit_deinit(&rl_test);
161 return (ret);
162 }
163
164 static bool
cookie_ratelimit_gc_test(void)165 cookie_ratelimit_gc_test(void)
166 {
167 struct sockaddr_in sin;
168 int i;
169 bool ret = false;
170
171 ratelimit_init(&rl_test);
172
173 sin.sin_family = AF_INET;
174 sin.sin_port = 1234;
175
176 /* Test that the garbage collect routine will run. */
177 if (rl_test.rl_table_num != 0)
178 T_FAILED("init not empty");
179
180 for (i = 0; i < RATELIMIT_SIZE_MAX / 2; i++) {
181 sin.sin_addr.s_addr = i;
182 if (ratelimit_allow(&rl_test, sintosa(&sin)) != 0)
183 T_FAILED_ITER("insert");
184 }
185
186 if (rl_test.rl_table_num != RATELIMIT_SIZE_MAX / 2)
187 T_FAILED("insert 1 not full");
188
189 tsleep(&rl_test, 0, "rl_test", ELEMENT_TIMEOUT * hz / 2);
190
191 for (i = 0; i < RATELIMIT_SIZE_MAX / 2; i++) {
192 sin.sin_addr.s_addr = i;
193 if (ratelimit_allow(&rl_test, sintosa(&sin)) != 0)
194 T_FAILED_ITER("insert");
195 }
196
197 if (rl_test.rl_table_num != RATELIMIT_SIZE_MAX / 2)
198 T_FAILED("insert 2 not full");
199
200 tsleep(&rl_test, 0, "rl_test", ELEMENT_TIMEOUT * hz * 2);
201
202 if (rl_test.rl_table_num != 0)
203 T_FAILED("gc");
204
205 T_PASSED;
206 ret = true;
207
208 cleanup:
209 ratelimit_deinit(&rl_test);
210 return (ret);
211 }
212
213 static bool
cookie_mac_test(void)214 cookie_mac_test(void)
215 {
216 struct cookie_checker *checker;
217 struct cookie_maker *maker;
218 struct cookie_macs cm;
219 struct sockaddr_in sin;
220 uint8_t nonce[COOKIE_NONCE_SIZE];
221 uint8_t cookie[COOKIE_ENCRYPTED_SIZE];
222 uint8_t shared[COOKIE_INPUT_SIZE];
223 uint8_t message[T_MESSAGE_LEN];
224 int res, i;
225 bool ret = false;
226
227 karc4random_buf(shared, COOKIE_INPUT_SIZE);
228 karc4random_buf(message, T_MESSAGE_LEN);
229
230 /* Init cookie_maker. */
231 maker = cookie_maker_alloc(shared);
232
233 checker = cookie_checker_alloc();
234 cookie_checker_update(checker, shared);
235
236 /* Create dummy sockaddr. */
237 sin.sin_family = AF_INET;
238 sin.sin_len = sizeof(sin);
239 sin.sin_addr.s_addr = 1;
240 sin.sin_port = 51820;
241
242 /* MAC message. */
243 cookie_maker_mac(maker, &cm, message, T_MESSAGE_LEN);
244
245 /* Check we have a null mac2. */
246 for (i = 0; i < sizeof(cm.mac2); i++) {
247 if (cm.mac2[i] != 0)
248 T_FAILED("validate_macs_noload_mac2_zeroed");
249 }
250
251 /* Validate all bytes are checked in mac1. */
252 for (i = 0; i < sizeof(cm.mac1); i++) {
253 cm.mac1[i] = ~cm.mac1[i];
254 if (cookie_checker_validate_macs(checker, &cm, message,
255 T_MESSAGE_LEN, 0,
256 sintosa(&sin)) != EINVAL)
257 T_FAILED("validate_macs_noload_munge");
258 cm.mac1[i] = ~cm.mac1[i];
259 }
260
261 /* Check mac2 is zeroed. */
262 res = 0;
263 for (i = 0; i < sizeof(cm.mac2); i++)
264 res |= cm.mac2[i];
265 if (res != 0)
266 T_FAILED("validate_macs_mac2_checkzero");
267
268
269 /* Check we can successfully validate the MAC. */
270 if (cookie_checker_validate_macs(checker, &cm, message, T_MESSAGE_LEN,
271 0, sintosa(&sin)) != 0)
272 T_FAILED("validate_macs_noload_normal");
273
274 /* Check we get a EAGAIN if no mac2 and under load. */
275 if (cookie_checker_validate_macs(checker, &cm, message, T_MESSAGE_LEN,
276 1, sintosa(&sin)) != EAGAIN)
277 T_FAILED("validate_macs_load_normal");
278
279 /* Simulate a cookie message. */
280 cookie_checker_create_payload(checker, &cm, nonce, cookie,
281 sintosa(&sin));
282
283 /* Validate all bytes are checked in cookie. */
284 for (i = 0; i < sizeof(cookie); i++) {
285 cookie[i] = ~cookie[i];
286 if (cookie_maker_consume_payload(maker, nonce, cookie)
287 != EINVAL)
288 T_FAILED("consume_payload_munge");
289 cookie[i] = ~cookie[i];
290 }
291
292 /* Check we can actually consume the payload. */
293 if (cookie_maker_consume_payload(maker, nonce, cookie) != 0)
294 T_FAILED("consume_payload_normal");
295
296 /* Check replay isn't allowed. */
297 if (cookie_maker_consume_payload(maker, nonce, cookie) != ETIMEDOUT)
298 T_FAILED("consume_payload_normal_replay");
299
300 /* MAC message again, with MAC2. */
301 cookie_maker_mac(maker, &cm, message, T_MESSAGE_LEN);
302
303 /* Check we added a mac2. */
304 res = 0;
305 for (i = 0; i < sizeof(cm.mac2); i++)
306 res |= cm.mac2[i];
307 if (res == 0)
308 T_FAILED("validate_macs_make_mac2");
309
310 /* Check we get OK if mac2 and under load */
311 if (cookie_checker_validate_macs(checker, &cm, message, T_MESSAGE_LEN,
312 1, sintosa(&sin)) != 0)
313 T_FAILED("validate_macs_load_normal_mac2");
314
315 /* Check we get EAGAIN if we munge the source IP. */
316 sin.sin_addr.s_addr = ~sin.sin_addr.s_addr;
317 if (cookie_checker_validate_macs(checker, &cm, message, T_MESSAGE_LEN,
318 1, sintosa(&sin)) != EAGAIN)
319 T_FAILED("validate_macs_load_spoofip_mac2");
320 sin.sin_addr.s_addr = ~sin.sin_addr.s_addr;
321
322 /* Check we get OK if mac2 and under load */
323 if (cookie_checker_validate_macs(checker, &cm, message, T_MESSAGE_LEN,
324 1, sintosa(&sin)) != 0)
325 T_FAILED("validate_macs_load_normal_mac2_retry");
326
327 T_PASSED;
328 ret = true;
329
330 cleanup:
331 cookie_checker_free(checker);
332 cookie_maker_free(maker);
333 return (ret);
334 }
335
336 bool
cookie_selftest(void)337 cookie_selftest(void)
338 {
339 bool ret = true;
340
341 ret &= cookie_ratelimit_timings_test();
342 ret &= cookie_ratelimit_capacity_test();
343 ret &= cookie_ratelimit_gc_test();
344 ret &= cookie_mac_test();
345
346 kprintf("%s: %s\n", __func__, ret ? "pass" : "FAIL");
347 return (ret);
348 }
349
350 #undef T_MESSAGE_LEN
351 #undef T_FAILED_ITER
352 #undef T_FAILED
353 #undef T_PASSED
354