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 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 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 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 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 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