// Copyright 2017 syzkaller project authors. All rights reserved. // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. #if GOOS_linux && (GOARCH_amd64 || GOARCH_ppc64 || GOARCH_ppc64le || GOARCH_arm64) #include "test_linux.h" #endif #include #include #include #include static int test_copyin() { static uint16 buf[3]; STORE_BY_BITMASK(uint16, htole16, &buf[1], 0x1234, 0, 16); unsigned char x[sizeof(buf)]; memcpy(x, buf, sizeof(x)); if (x[0] != 0 || x[1] != 0 || x[2] != 0x34 || x[3] != 0x12 || x[4] != 0 || x[5] != 0) { printf("bad result of STORE_BY_BITMASK(le16, 0x1234, 0, 16): %x %x %x %x %x %x\n", x[0], x[1], x[2], x[3], x[4], x[5]); return 1; } STORE_BY_BITMASK(uint16, htole16, &buf[1], 0x555a, 5, 4); memcpy(x, buf, sizeof(x)); if (x[0] != 0 || x[1] != 0 || x[2] != 0x54 || x[3] != 0x13 || x[4] != 0 || x[5] != 0) { printf("bad result of STORE_BY_BITMASK(le16, 0x555a, 5, 4): %x %x %x %x %x %x\n", x[0], x[1], x[2], x[3], x[4], x[5]); return 1; } STORE_BY_BITMASK(uint16, htobe16, &buf[1], 0x4567, 13, 3); memcpy(x, buf, sizeof(x)); if (x[0] != 0 || x[1] != 0 || x[2] != 0xf4 || x[3] != 0x13 || x[4] != 0 || x[5] != 0) { printf("bad result of STORE_BY_BITMASK(be16, 0x4567, 13, 3): %x %x %x %x %x %x\n", x[0], x[1], x[2], x[3], x[4], x[5]); return 1; } return 0; } static int test_csum_inet() { struct csum_inet_test { const char* data; size_t length; uint16 csum; }; struct csum_inet_test tests[] = { {// 0 "", 0, le16toh(0xffff)}, { // 1 "\x00", 1, le16toh(0xffff), }, { // 2 "\x00\x00", 2, le16toh(0xffff), }, { // 3 "\x00\x00\xff\xff", 4, le16toh(0x0000), }, { // 4 "\xfc", 1, le16toh(0xff03), }, { // 5 "\xfc\x12", 2, le16toh(0xed03), }, { // 6 "\xfc\x12\x3e", 3, le16toh(0xecc5), }, { // 7 "\xfc\x12\x3e\x00\xc5\xec", 6, le16toh(0x0000), }, { // 8 "\x42\x00\x00\x43\x44\x00\x00\x00\x45\x00\x00\x00\xba\xaa\xbb\xcc\xdd", 17, le16toh(0x43e1), }, { // 9 "\x42\x00\x00\x43\x44\x00\x00\x00\x45\x00\x00\x00\xba\xaa\xbb\xcc\xdd\x00", 18, le16toh(0x43e1), }, { // 10 "\x00\x00\x42\x00\x00\x43\x44\x00\x00\x00\x45\x00\x00\x00\xba\xaa\xbb\xcc\xdd", 19, le16toh(0x43e1), }, { // 11 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\xab\xcd", 15, le16toh(0x5032), }, { // 12 "\x00\x00\x12\x34\x56\x78", 6, le16toh(0x5397), }, { // 13 "\x00\x00\x12\x34\x00\x00\x56\x78\x00\x06\x00\x04\xab\xcd", 14, le16toh(0x7beb), }, { // 14 "\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", 44, le16toh(0x2854), }, { // 15 "\x00\x00\x12\x34\x00\x00\x56\x78\x00\x11\x00\x04\xab\xcd", 14, le16toh(0x70eb), }, { // 16 "\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", 44, le16toh(0x1d54), }, { // 17 "\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", 44, le16toh(0xf453), }}; for (unsigned i = 0; i < ARRAY_SIZE(tests); i++) { struct csum_inet csum; csum_inet_init(&csum); csum_inet_update(&csum, (const uint8*)tests[i].data, tests[i].length); if (csum_inet_digest(&csum) != tests[i].csum) { fprintf(stderr, "bad checksum in test #%u, want: %hx, got: %hx\n", i, tests[i].csum, csum_inet_digest(&csum)); return 1; } } return 0; } static int rand_int_range(int start, int end) { return rand() % (end + 1 - start) + start; } static int test_csum_inet_acc() { uint8 buffer[128]; for (int test = 0; test < 256; test++) { int size = rand_int_range(1, 128); int step = rand_int_range(1, 8) * 2; for (int i = 0; i < size; i++) buffer[i] = rand_int_range(0, 255); struct csum_inet csum_acc; csum_inet_init(&csum_acc); for (int i = 0; i < size / step; i++) csum_inet_update(&csum_acc, &buffer[i * step], step); if (size % step != 0) csum_inet_update(&csum_acc, &buffer[size - size % step], size % step); struct csum_inet csum; csum_inet_init(&csum); csum_inet_update(&csum, &buffer[0], size); if (csum_inet_digest(&csum_acc) != csum_inet_digest(&csum)) return 1; } return 0; } static int test_cover_filter() { CoverFilter filter; CoverFilter child(filter.FD()); std::vector pcs = { 100, 111, 200, (1 << 20) - 1, 1 << 20, (1 << 30) - 1, 100ull << 30, (100ull << 30) + 100, 200ull << 30, (1ull << 62) + 100, }; // These we don't insert, but they are also present due to truncation of low 3 bits. std::vector also_contain = { 96, 103, 104, 207, (1 << 20) - 7, (1 << 20) + 7, (1ull << 62) + 96, (1ull << 62) + 103, }; std::vector dont_contain = { 0, 1, 95, 112, 199, 208, 100 << 10, (1 << 20) - 9, (1 << 20) + 8, (2ull << 30) - 1, 2ull << 30, (2ull << 30) + 1, (100ull << 30) + 108, 150ull << 30, 1ull << 40, 1ull << 63, ~0ull, }; int ret = 0; for (auto pc : pcs) filter.Insert(pc); pcs.insert(pcs.end(), also_contain.begin(), also_contain.end()); for (auto pc : pcs) { if (!filter.Contains(pc) || !child.Contains(pc)) { printf("filter doesn't contain %llu (0x%llx)\n", pc, pc); ret = 1; } } for (auto pc : dont_contain) { if (filter.Contains(pc) || child.Contains(pc)) { printf("filter contains %llu (0x%llx)\n", pc, pc); ret = 1; } } return ret; } static bool test_one_glob(const char* pattern, std::vector want) { std::vector got = Glob(pattern); std::sort(want.begin(), want.end()); std::sort(got.begin(), got.end()); if (got == want) return true; printf("pattern '%s', want %zu files:\n", pattern, want.size()); for (const auto& f : want) printf("\t'%s'\n", f.c_str()); printf("got %zu files:\n", got.size()); for (const auto& f : got) printf("\t'%s'\n", f.c_str()); return false; } static void must_mkdir(const char* dir) { if (mkdir(dir, 0700)) failmsg("mkdir failed", "dir=%s", dir); } static void must_creat(const char* file) { int fd = open(file, O_CREAT | O_EXCL, 0700); if (fd == -1) failmsg("open failed", "file=%s", file); close(fd); } static void must_link(const char* oldpath, const char* linkpath) { if (link(oldpath, linkpath)) failmsg("link failed", "oldpath=%s linkpath=%s", oldpath, linkpath); } static void must_symlink(const char* oldpath, const char* linkpath) { if (symlink(oldpath, linkpath)) failmsg("symlink failed", "oldpath=%s linkpath=%s", oldpath, linkpath); } static int test_glob() { #if GOARCH_arm // When running a 32-bit ARM binary on a 64-bit system under QEMU, readdir() fails // with EOVERFLOW, resulting in Glob() returning 0 files. // Tracking QEMU bug: https://gitlab.com/qemu-project/qemu/-/issues/263. return -1; #endif // Note: pkg/runtest.TestExecutor creates a temp dir for the test, // so we create files in cwd and don't clean up. if (!test_one_glob("glob/*", {})) return 1; must_mkdir("glob"); if (!test_one_glob("glob/*", {})) return 1; must_mkdir("glob/dir1"); must_creat("glob/file1"); must_mkdir("glob/dir2"); must_creat("glob/dir2/file21"); must_mkdir("glob/dir3"); must_creat("glob/dir3/file31"); must_link("glob/dir3/file31", "glob/dir3/file32"); must_symlink("file31", "glob/dir3/file33"); must_symlink("deadlink", "glob/dir3/file34"); must_symlink("../../glob", "glob/dir3/dir31"); must_mkdir("glob/dir4"); must_mkdir("glob/dir4/dir41"); must_creat("glob/dir4/dir41/file411"); must_symlink("dir4", "glob/dir5"); must_mkdir("glob/dir6"); must_mkdir("glob/dir6/dir61"); must_creat("glob/dir6/dir61/file611"); must_symlink("dir6/dir61", "glob/self"); // Directories are not includes + not recursive (yet). if (!test_one_glob("glob/*", { "glob/file1", })) return 1; if (!test_one_glob("glob/*/*", { "glob/dir2/file21", "glob/dir3/file31", "glob/dir3/file32", // hard links are included "glob/self/file611", // symlinks via name "self" are included })) return 1; return 0; } static struct { const char* name; int (*f)(); } tests[] = { {"test_copyin", test_copyin}, {"test_csum_inet", test_csum_inet}, {"test_csum_inet_acc", test_csum_inet_acc}, #if GOOS_linux && (GOARCH_amd64 || GOARCH_ppc64 || GOARCH_ppc64le || GOARCH_arm64) {"test_kvm", test_kvm}, #endif #if GOOS_linux && GOARCH_arm64 {"test_syzos", test_syzos}, #endif {"test_cover_filter", test_cover_filter}, {"test_glob", test_glob}, }; static int run_tests(const char* test) { int ret = 0; for (size_t i = 0; i < ARRAY_SIZE(tests); i++) { const char* name = tests[i].name; if (test && strcmp(test, name)) continue; printf("=== RUN %s\n", name); int res = tests[i].f(); ret |= res > 0; const char* strres = res < 0 ? "SKIP" : (res > 0 ? "FAIL" : "OK"); printf("--- %-4s %s\n", strres, name); } return ret; }