github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/executor/test.h (about) 1 // Copyright 2017 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 #if GOOS_linux && (GOARCH_amd64 || GOARCH_ppc64 || GOARCH_ppc64le || GOARCH_arm64) 5 #include "test_linux.h" 6 #endif 7 8 #include <algorithm> 9 #include <fcntl.h> 10 #include <sys/stat.h> 11 #include <unistd.h> 12 13 static int test_copyin() 14 { 15 static uint16 buf[3]; 16 STORE_BY_BITMASK(uint16, htole16, &buf[1], 0x1234, 0, 16); 17 unsigned char x[sizeof(buf)]; 18 memcpy(x, buf, sizeof(x)); 19 if (x[0] != 0 || x[1] != 0 || 20 x[2] != 0x34 || x[3] != 0x12 || 21 x[4] != 0 || x[5] != 0) { 22 printf("bad result of STORE_BY_BITMASK(le16, 0x1234, 0, 16): %x %x %x %x %x %x\n", 23 x[0], x[1], x[2], x[3], x[4], x[5]); 24 return 1; 25 } 26 STORE_BY_BITMASK(uint16, htole16, &buf[1], 0x555a, 5, 4); 27 memcpy(x, buf, sizeof(x)); 28 if (x[0] != 0 || x[1] != 0 || 29 x[2] != 0x54 || x[3] != 0x13 || 30 x[4] != 0 || x[5] != 0) { 31 printf("bad result of STORE_BY_BITMASK(le16, 0x555a, 5, 4): %x %x %x %x %x %x\n", 32 x[0], x[1], x[2], x[3], x[4], x[5]); 33 return 1; 34 } 35 STORE_BY_BITMASK(uint16, htobe16, &buf[1], 0x4567, 13, 3); 36 memcpy(x, buf, sizeof(x)); 37 if (x[0] != 0 || x[1] != 0 || 38 x[2] != 0xf4 || x[3] != 0x13 || 39 x[4] != 0 || x[5] != 0) { 40 printf("bad result of STORE_BY_BITMASK(be16, 0x4567, 13, 3): %x %x %x %x %x %x\n", 41 x[0], x[1], x[2], x[3], x[4], x[5]); 42 return 1; 43 } 44 return 0; 45 } 46 47 static int test_csum_inet() 48 { 49 struct csum_inet_test { 50 const char* data; 51 size_t length; 52 uint16 csum; 53 }; 54 struct csum_inet_test tests[] = { 55 {// 0 56 "", 57 0, 58 le16toh(0xffff)}, 59 { 60 // 1 61 "\x00", 62 1, 63 le16toh(0xffff), 64 }, 65 { 66 // 2 67 "\x00\x00", 68 2, 69 le16toh(0xffff), 70 }, 71 { 72 // 3 73 "\x00\x00\xff\xff", 74 4, 75 le16toh(0x0000), 76 }, 77 { 78 // 4 79 "\xfc", 80 1, 81 le16toh(0xff03), 82 }, 83 { 84 // 5 85 "\xfc\x12", 86 2, 87 le16toh(0xed03), 88 }, 89 { 90 // 6 91 "\xfc\x12\x3e", 92 3, 93 le16toh(0xecc5), 94 }, 95 { 96 // 7 97 "\xfc\x12\x3e\x00\xc5\xec", 98 6, 99 le16toh(0x0000), 100 }, 101 { 102 // 8 103 "\x42\x00\x00\x43\x44\x00\x00\x00\x45\x00\x00\x00\xba\xaa\xbb\xcc\xdd", 104 17, 105 le16toh(0x43e1), 106 }, 107 { 108 // 9 109 "\x42\x00\x00\x43\x44\x00\x00\x00\x45\x00\x00\x00\xba\xaa\xbb\xcc\xdd\x00", 110 18, 111 le16toh(0x43e1), 112 }, 113 { 114 // 10 115 "\x00\x00\x42\x00\x00\x43\x44\x00\x00\x00\x45\x00\x00\x00\xba\xaa\xbb\xcc\xdd", 116 19, 117 le16toh(0x43e1), 118 }, 119 { 120 // 11 121 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\xab\xcd", 122 15, 123 le16toh(0x5032), 124 }, 125 { 126 // 12 127 "\x00\x00\x12\x34\x56\x78", 128 6, 129 le16toh(0x5397), 130 }, 131 { 132 // 13 133 "\x00\x00\x12\x34\x00\x00\x56\x78\x00\x06\x00\x04\xab\xcd", 134 14, 135 le16toh(0x7beb), 136 }, 137 { 138 // 14 139 "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\xff\xee\xdd\xcc\xbb\xaa\x99\x88\x77\x66\x55\x44\x33\x22\x11\x00\x00\x00\x00\x04\x00\x00\x00\x06\x00\x00\xab\xcd", 140 44, 141 le16toh(0x2854), 142 }, 143 { 144 // 15 145 "\x00\x00\x12\x34\x00\x00\x56\x78\x00\x11\x00\x04\xab\xcd", 146 14, 147 le16toh(0x70eb), 148 }, 149 { 150 // 16 151 "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\xff\xee\xdd\xcc\xbb\xaa\x99\x88\x77\x66\x55\x44\x33\x22\x11\x00\x00\x00\x00\x04\x00\x00\x00\x11\x00\x00\xab\xcd", 152 44, 153 le16toh(0x1d54), 154 }, 155 { 156 // 17 157 "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\xff\xee\xdd\xcc\xbb\xaa\x99\x88\x77\x66\x55\x44\x33\x22\x11\x00\x00\x00\x00\x04\x00\x00\x00\x3a\x00\x00\xab\xcd", 158 44, 159 le16toh(0xf453), 160 }}; 161 162 for (unsigned i = 0; i < ARRAY_SIZE(tests); i++) { 163 struct csum_inet csum; 164 csum_inet_init(&csum); 165 csum_inet_update(&csum, (const uint8*)tests[i].data, tests[i].length); 166 if (csum_inet_digest(&csum) != tests[i].csum) { 167 fprintf(stderr, "bad checksum in test #%u, want: %hx, got: %hx\n", i, tests[i].csum, csum_inet_digest(&csum)); 168 return 1; 169 } 170 } 171 172 return 0; 173 } 174 175 static int rand_int_range(int start, int end) 176 { 177 return rand() % (end + 1 - start) + start; 178 } 179 180 static int test_csum_inet_acc() 181 { 182 uint8 buffer[128]; 183 184 for (int test = 0; test < 256; test++) { 185 int size = rand_int_range(1, 128); 186 int step = rand_int_range(1, 8) * 2; 187 188 for (int i = 0; i < size; i++) 189 buffer[i] = rand_int_range(0, 255); 190 191 struct csum_inet csum_acc; 192 csum_inet_init(&csum_acc); 193 194 for (int i = 0; i < size / step; i++) 195 csum_inet_update(&csum_acc, &buffer[i * step], step); 196 if (size % step != 0) 197 csum_inet_update(&csum_acc, &buffer[size - size % step], size % step); 198 199 struct csum_inet csum; 200 csum_inet_init(&csum); 201 csum_inet_update(&csum, &buffer[0], size); 202 203 if (csum_inet_digest(&csum_acc) != csum_inet_digest(&csum)) 204 return 1; 205 } 206 return 0; 207 } 208 209 static int test_cover_filter() 210 { 211 CoverFilter filter; 212 CoverFilter child(filter.FD()); 213 214 std::vector<uint64> pcs = { 215 100, 216 111, 217 200, 218 (1 << 20) - 1, 219 1 << 20, 220 (1 << 30) - 1, 221 100ull << 30, 222 (100ull << 30) + 100, 223 200ull << 30, 224 (1ull << 62) + 100, 225 }; 226 227 // These we don't insert, but they are also present due to truncation of low 3 bits. 228 std::vector<uint64> also_contain = { 229 96, 230 103, 231 104, 232 207, 233 (1 << 20) - 7, 234 (1 << 20) + 7, 235 (1ull << 62) + 96, 236 (1ull << 62) + 103, 237 }; 238 239 std::vector<uint64> dont_contain = { 240 0, 241 1, 242 95, 243 112, 244 199, 245 208, 246 100 << 10, 247 (1 << 20) - 9, 248 (1 << 20) + 8, 249 (2ull << 30) - 1, 250 2ull << 30, 251 (2ull << 30) + 1, 252 (100ull << 30) + 108, 253 150ull << 30, 254 1ull << 40, 255 1ull << 63, 256 ~0ull, 257 }; 258 259 int ret = 0; 260 for (auto pc : pcs) 261 filter.Insert(pc); 262 pcs.insert(pcs.end(), also_contain.begin(), also_contain.end()); 263 for (auto pc : pcs) { 264 if (!filter.Contains(pc) || !child.Contains(pc)) { 265 printf("filter doesn't contain %llu (0x%llx)\n", pc, pc); 266 ret = 1; 267 } 268 } 269 for (auto pc : dont_contain) { 270 if (filter.Contains(pc) || child.Contains(pc)) { 271 printf("filter contains %llu (0x%llx)\n", pc, pc); 272 ret = 1; 273 } 274 } 275 return ret; 276 } 277 278 static bool test_one_glob(const char* pattern, std::vector<std::string> want) 279 { 280 std::vector<std::string> got = Glob(pattern); 281 std::sort(want.begin(), want.end()); 282 std::sort(got.begin(), got.end()); 283 if (got == want) 284 return true; 285 printf("pattern '%s', want %zu files:\n", pattern, want.size()); 286 for (const auto& f : want) 287 printf("\t'%s'\n", f.c_str()); 288 printf("got %zu files:\n", got.size()); 289 for (const auto& f : got) 290 printf("\t'%s'\n", f.c_str()); 291 return false; 292 } 293 294 static void must_mkdir(const char* dir) 295 { 296 if (mkdir(dir, 0700)) 297 failmsg("mkdir failed", "dir=%s", dir); 298 } 299 300 static void must_creat(const char* file) 301 { 302 int fd = open(file, O_CREAT | O_EXCL, 0700); 303 if (fd == -1) 304 failmsg("open failed", "file=%s", file); 305 close(fd); 306 } 307 308 static void must_link(const char* oldpath, const char* linkpath) 309 { 310 if (link(oldpath, linkpath)) 311 failmsg("link failed", "oldpath=%s linkpath=%s", oldpath, linkpath); 312 } 313 314 static void must_symlink(const char* oldpath, const char* linkpath) 315 { 316 if (symlink(oldpath, linkpath)) 317 failmsg("symlink failed", "oldpath=%s linkpath=%s", oldpath, linkpath); 318 } 319 320 static int test_glob() 321 { 322 #if GOARCH_arm 323 // When running a 32-bit ARM binary on a 64-bit system under QEMU, readdir() fails 324 // with EOVERFLOW, resulting in Glob() returning 0 files. 325 // Tracking QEMU bug: https://gitlab.com/qemu-project/qemu/-/issues/263. 326 return -1; 327 #endif 328 // Note: pkg/runtest.TestExecutor creates a temp dir for the test, 329 // so we create files in cwd and don't clean up. 330 if (!test_one_glob("glob/*", {})) 331 return 1; 332 must_mkdir("glob"); 333 if (!test_one_glob("glob/*", {})) 334 return 1; 335 must_mkdir("glob/dir1"); 336 must_creat("glob/file1"); 337 must_mkdir("glob/dir2"); 338 must_creat("glob/dir2/file21"); 339 must_mkdir("glob/dir3"); 340 must_creat("glob/dir3/file31"); 341 must_link("glob/dir3/file31", "glob/dir3/file32"); 342 must_symlink("file31", "glob/dir3/file33"); 343 must_symlink("deadlink", "glob/dir3/file34"); 344 must_symlink("../../glob", "glob/dir3/dir31"); 345 must_mkdir("glob/dir4"); 346 must_mkdir("glob/dir4/dir41"); 347 must_creat("glob/dir4/dir41/file411"); 348 must_symlink("dir4", "glob/dir5"); 349 must_mkdir("glob/dir6"); 350 must_mkdir("glob/dir6/dir61"); 351 must_creat("glob/dir6/dir61/file611"); 352 must_symlink("dir6/dir61", "glob/self"); 353 // Directories are not includes + not recursive (yet). 354 if (!test_one_glob("glob/*", { 355 "glob/file1", 356 })) 357 return 1; 358 if (!test_one_glob("glob/*/*", { 359 "glob/dir2/file21", 360 "glob/dir3/file31", 361 "glob/dir3/file32", // hard links are included 362 "glob/self/file611", // symlinks via name "self" are included 363 })) 364 return 1; 365 return 0; 366 } 367 368 static struct { 369 const char* name; 370 int (*f)(); 371 } tests[] = { 372 {"test_copyin", test_copyin}, 373 {"test_csum_inet", test_csum_inet}, 374 {"test_csum_inet_acc", test_csum_inet_acc}, 375 #if GOOS_linux && (GOARCH_amd64 || GOARCH_ppc64 || GOARCH_ppc64le || GOARCH_arm64) 376 {"test_kvm", test_kvm}, 377 #endif 378 #if GOOS_linux && GOARCH_arm64 379 {"test_syzos", test_syzos}, 380 #endif 381 {"test_cover_filter", test_cover_filter}, 382 {"test_glob", test_glob}, 383 }; 384 385 static int run_tests(const char* test) 386 { 387 int ret = 0; 388 for (size_t i = 0; i < ARRAY_SIZE(tests); i++) { 389 const char* name = tests[i].name; 390 if (test && strcmp(test, name)) 391 continue; 392 printf("=== RUN %s\n", name); 393 int res = tests[i].f(); 394 ret |= res > 0; 395 const char* strres = res < 0 ? "SKIP" : (res > 0 ? "FAIL" : "OK"); 396 printf("--- %-4s %s\n", strres, name); 397 } 398 return ret; 399 }