From 5f02070655b3c1f2ab50a82fd5f466aaeb7af44a Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Mon, 10 Jun 2024 11:06:30 +0200 Subject: executor: add end-to-end coverage/signal/comparisons test --- executor/common_test.h | 11 +++++++++++ executor/executor.cc | 20 +++++++------------- executor/executor_bsd.h | 5 +++++ executor/executor_darwin.h | 5 +++++ executor/executor_linux.h | 11 +++++++++++ executor/executor_test.h | 25 +++++++++++++++++++++++-- executor/nocover.h | 5 +++++ 7 files changed, 67 insertions(+), 15 deletions(-) (limited to 'executor') diff --git a/executor/common_test.h b/executor/common_test.h index 971108df8..67585be9a 100644 --- a/executor/common_test.h +++ b/executor/common_test.h @@ -153,3 +153,14 @@ static long syz_test_fuzzer1(volatile long a, volatile long b, volatile long c) } #endif + +#if SYZ_EXECUTOR || __NR_syz_inject_cover +static long syz_inject_cover(volatile long a, volatile long b, volatile long c) +#if SYZ_EXECUTOR + ; // defined in executor_test.h +#else +{ + return 0; +} +#endif +#endif diff --git a/executor/executor.cc b/executor/executor.cc index 88a0963c8..a8cc2259f 100644 --- a/executor/executor.cc +++ b/executor/executor.cc @@ -218,8 +218,8 @@ const uint64 binary_format_stroct = 4; const uint64 no_copyout = -1; static int running; -uint32 completed; -bool is_kernel_64_bit = true; +static uint32 completed; +static bool is_kernel_64_bit = true; static uint8* input_data; @@ -1278,11 +1278,14 @@ void execute_call(thread_t* th) static uint32 hash(uint32 a) { + // For test OS we disable hashing for determinism and testability. +#if !GOOS_test a = (a ^ 61) ^ (a >> 16); a = a + (a << 3); a = a ^ (a >> 4); a = a * 0x27d4eb2d; a = a ^ (a >> 15); +#endif return a; } @@ -1577,21 +1580,12 @@ bool kcov_comparison_t::ignore() const return true; if (arg2 >= out_start && arg2 <= out_end) return true; -#if defined(GOOS_linux) // Filter out kernel physical memory addresses. // These are internal kernel comparisons and should not be interesting. - // The range covers first 1TB of physical mapping. - uint64 kmem_start = (uint64)0xffff880000000000ull; - uint64 kmem_end = (uint64)0xffff890000000000ull; - bool kptr1 = arg1 >= kmem_start && arg1 <= kmem_end; - bool kptr2 = arg2 >= kmem_start && arg2 <= kmem_end; + bool kptr1 = is_kernel_data(arg1) || arg1 == 0; + bool kptr2 = is_kernel_data(arg2) || arg2 == 0; if (kptr1 && kptr2) return true; - if (kptr1 && arg2 == 0) - return true; - if (kptr2 && arg1 == 0) - return true; -#endif } return !coverage_filter(pc); } diff --git a/executor/executor_bsd.h b/executor/executor_bsd.h index 43c2a19a9..1f54e0f41 100644 --- a/executor/executor_bsd.h +++ b/executor/executor_bsd.h @@ -179,6 +179,11 @@ static void cover_collect(cover_t* cov) cov->size = *(uint64*)cov->data; } +static bool is_kernel_data(uint64 addr) +{ + return false; +} + static bool use_cover_edges(uint64 pc) { return true; diff --git a/executor/executor_darwin.h b/executor/executor_darwin.h index aeba30a1d..83fe90c45 100644 --- a/executor/executor_darwin.h +++ b/executor/executor_darwin.h @@ -122,6 +122,11 @@ static void cover_collect(cover_t* cov) cov->pc_offset = trace->offset; } +static bool is_kernel_data(uint64 addr) +{ + return false; +} + static bool use_cover_edges(uint64 pc) { return true; diff --git a/executor/executor_linux.h b/executor/executor_linux.h index bfd81776f..445a278e2 100644 --- a/executor/executor_linux.h +++ b/executor/executor_linux.h @@ -182,6 +182,17 @@ static bool use_cover_edges(uint32 pc) return true; } +static bool is_kernel_data(uint64 addr) +{ +#if GOARCH_386 || GOARCH_amd64 + // This range corresponds to the first 1TB of the physical memory mapping, + // see Documentation/arch/x86/x86_64/mm.rst. + return addr >= 0xffff880000000000ull && addr < 0xffff890000000000ull; +#else + return false; +#endif +} + static bool use_cover_edges(uint64 pc) { #if GOARCH_amd64 || GOARCH_arm64 diff --git a/executor/executor_test.h b/executor/executor_test.h index dd133e422..f796aed04 100644 --- a/executor/executor_test.h +++ b/executor/executor_test.h @@ -54,12 +54,15 @@ static void cover_enable(cover_t* cov, bool collect_comps, bool extra) static void cover_reset(cover_t* cov) { - *(unsigned long*)(cov->data) = 0; + *(uint64*)(cov->data) = 0; } static void cover_collect(cover_t* cov) { - cov->size = *(unsigned long*)(cov->data); + if (is_kernel_64_bit) + cov->size = *(uint64*)cov->data; + else + cov->size = *(uint32*)cov->data; } static void cover_protect(cover_t* cov) @@ -87,7 +90,25 @@ static void cover_unprotect(cover_t* cov) { } +static bool is_kernel_data(uint64 addr) +{ + return addr >= 0xda1a0000 && addr <= 0xda1a1000; +} + static bool use_cover_edges(uint64 pc) { return true; } + +static long syz_inject_cover(volatile long a, volatile long b, volatile long c) +{ + cover_t* cov = ¤t_thread->cov; + if (cov->data == nullptr) + return ENOENT; + is_kernel_64_bit = a; + cov->data_offset = is_kernel_64_bit ? sizeof(uint64_t) : sizeof(uint32_t); + uint32 size = std::min((uint32)c, cov->mmap_alloc_size); + memcpy(cov->data, (void*)b, size); + memset(cov->data + size, 0xcd, std::min(100, cov->mmap_alloc_size - size)); + return 0; +} diff --git a/executor/nocover.h b/executor/nocover.h index 0ba7a56cc..ba26dd1d5 100644 --- a/executor/nocover.h +++ b/executor/nocover.h @@ -29,6 +29,11 @@ static void cover_unprotect(cover_t* cov) { } +static bool is_kernel_data(uint64 addr) +{ + return false; +} + static bool use_cover_edges(uint64 pc) { return true; -- cgit mrf-deployment