// Copyright 2018 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. #include #include #include #ifdef __linux__ #include #endif // sys/targets also know about these consts. static uint64 kernel_text_start = 0xc0dec0dec0000000; static uint64 kernel_text_mask = 0xffffff; static void os_init(int argc, char** argv, void* data, size_t data_size) { #ifdef __linux__ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); // There's a risk that the parent has exited before we get to call prctl(). // In that case, let's assume that the child must have been reassigned to PID=1. if (getppid() == 1) exitf("the parent process was killed"); #endif void* got = mmap(data, data_size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE | MAP_FIXED_EXCLUSIVE, -1, 0); if (data != got) failmsg("mmap of data segment failed", "want %p, got %p", data, got); is_kernel_64_bit = sizeof(unsigned long) == 8; } #ifdef __clang__ #define notrace #else #define notrace __attribute__((no_sanitize_coverage)) #endif extern "C" notrace void __sanitizer_cov_trace_pc(void) { if (current_thread == nullptr || current_thread->cov.data == nullptr || current_thread->cov.collect_comps) return; uint64 pc = (uint64)__builtin_return_address(0); // Convert to what is_kernel_pc will accept as valid coverage; pc = kernel_text_start | (pc & kernel_text_mask); // Note: we duplicate the following code instead of using a template function // because it must not be instrumented which is hard to achieve for all compiler // if the code is in a separate function. if (is_kernel_64_bit) { uint64* start = (uint64*)current_thread->cov.data; uint64* end = (uint64*)current_thread->cov.data_end; uint64 pos = start[0]; if (start + pos + 1 < end) { start[0] = pos + 1; start[pos + 1] = pc; } } else { uint32* start = (uint32*)current_thread->cov.data; uint32* end = (uint32*)current_thread->cov.data_end; uint32 pos = start[0]; if (start + pos + 1 < end) { start[0] = pos + 1; start[pos + 1] = pc; } } } static intptr_t execute_syscall(const call_t* c, intptr_t a[kMaxArgs]) { // Inject coverage PC even when built w/o coverage instrumentation. // This allows to pass machine check with coverage enabled. // pkg/fuzzer tests with coverage instrumentation shouldn't be distracted by the additional PC, // and syz_inject_cover overwrites the whole array so will remote it. __sanitizer_cov_trace_pc(); return c->call(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); } static void cover_open(cover_t* cov, bool extra) { cov->data_size = kCoverSize * sizeof(unsigned long); } static void cover_enable(cover_t* cov, bool collect_comps, bool extra) { cov->collect_comps = collect_comps; } static void cover_reset(cover_t* cov) { *(uint64*)(cov->data) = 0; } static void cover_collect(cover_t* cov) { if (is_kernel_64_bit) cov->size = *(uint64*)cov->data; else cov->size = *(uint32*)cov->data; } static void cover_protect(cover_t* cov) { } static void cover_mmap(cover_t* cov) { if (cov->mmap_alloc_ptr != NULL) fail("cover_mmap invoked on an already mmapped cover_t object"); if (cov->data_size == 0) fail("cover_t structure is corrupted"); cov->mmap_alloc_size = cov->data_size; cov->mmap_alloc_ptr = (char*)mmap(NULL, cov->mmap_alloc_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); if (cov->mmap_alloc_ptr == MAP_FAILED) exitf("cover mmap failed"); cov->data = cov->mmap_alloc_ptr; cov->data_end = cov->data + cov->mmap_alloc_size; cov->data_offset = is_kernel_64_bit ? sizeof(uint64_t) : sizeof(uint32_t); // We don't care about the specific PC values for now. // Once we do, we might want to consider ASLR here. cov->pc_offset = 0; } static void cover_unprotect(cover_t* cov) { } static long inject_cover(cover_t* cov, long a, long b) { if (cov->data == nullptr) return ENOENT; uint32 size = std::min((uint32)b, cov->data_size); memcpy(cov->data, (void*)a, size); memset(cov->data + size, 0xcd, std::min(100, cov->data_size - size)); return 0; } static long syz_inject_cover(volatile long a, volatile long b) { return inject_cover(¤t_thread->cov, a, b); } static long syz_inject_remote_cover(volatile long a, volatile long b) { return inject_cover(&extra_cov, a, b); } static const char* setup_fault() { return nullptr; } static const char* setup_leak() { return "leak detection is not supported"; } // Test various ways how feature setup can fail. // We don't care about these features for test OS, // this is just to test the feature support detection code. #define SYZ_HAVE_FEATURES 1 static feature_t features[] = { {rpc::Feature::Fault, setup_fault}, {rpc::Feature::Leak, setup_leak}, };