diff options
Diffstat (limited to 'executor')
| -rw-r--r-- | executor/executor.h | 38 | ||||
| -rw-r--r-- | executor/executor_akaros.cc | 5 | ||||
| -rw-r--r-- | executor/executor_freebsd.cc | 5 | ||||
| -rw-r--r-- | executor/executor_fuchsia.cc | 5 | ||||
| -rw-r--r-- | executor/executor_linux.cc | 39 | ||||
| -rw-r--r-- | executor/executor_windows.cc | 5 |
6 files changed, 78 insertions, 19 deletions
diff --git a/executor/executor.h b/executor/executor.h index e4bafc21e..669851e90 100644 --- a/executor/executor.h +++ b/executor/executor.h @@ -26,6 +26,7 @@ const int kOutPipeFd = 251; // remapped from stdout const int kMaxInput = 2 << 20; const int kMaxOutput = 16 << 20; +const int kCoverSize = 64 << 10; const int kMaxArgs = 9; const int kMaxThreads = 16; const int kMaxCommands = 16 << 10; @@ -164,9 +165,8 @@ struct kcov_comparison_t { uint64_t arg2; uint64_t pc; - // Writes the structure using the write_one function for each field. - // Inspired by write_output() function. - void write(uint32_t* (*write_one)(uint32_t)); + bool ignore() const; + void write(); bool operator==(const struct kcov_comparison_t& other) const; bool operator<(const struct kcov_comparison_t& other) const; }; @@ -520,13 +520,19 @@ void handle_completion(thread_t* th) if (flag_collect_comps) { // Collect only the comparisons - comps_size = th->cover_size; + uint32_t ncomps = th->cover_size; kcov_comparison_t* start = (kcov_comparison_t*)th->cover_data; - kcov_comparison_t* end = start + comps_size; + kcov_comparison_t* end = start + ncomps; + if ((uint64_t*)end >= th->cover_data + kCoverSize) + fail("too many comparisons %u", ncomps); std::sort(start, end); - comps_size = std::unique(start, end) - start; - for (uint32_t i = 0; i < comps_size; ++i) - start[i].write(write_output); + ncomps = std::unique(start, end) - start; + for (uint32_t i = 0; i < ncomps; ++i) { + if (start[i].ignore()) + continue; + comps_size++; + start[i].write(); + } } else { // Write out feedback signals. // Currently it is code edges computed as xor of @@ -761,10 +767,10 @@ uint64_t read_input(uint64_t** input_posp, bool peek) return *input_pos; } -void kcov_comparison_t::write(uint32_t* (*write_one)(uint32_t)) +void kcov_comparison_t::write() { // Write order: type arg1 arg2 pc. - write_one((uint32_t)type); + write_output((uint32_t)type); // KCOV converts all arguments of size x first to uintx_t and then to // uint64_t. We want to properly extend signed values, e.g we want @@ -788,15 +794,15 @@ void kcov_comparison_t::write(uint32_t* (*write_one)(uint32_t)) } bool is_size_8 = (type & KCOV_CMP_SIZE_MASK) == KCOV_CMP_SIZE8; if (!is_size_8) { - write_one((uint32_t)arg1); - write_one((uint32_t)arg2); + write_output((uint32_t)arg1); + write_output((uint32_t)arg2); return; } // If we have 64 bits arguments then write them in Little-endian. - write_one((uint32_t)(arg1 & 0xFFFFFFFF)); - write_one((uint32_t)(arg1 >> 32)); - write_one((uint32_t)(arg2 & 0xFFFFFFFF)); - write_one((uint32_t)(arg2 >> 32)); + write_output((uint32_t)(arg1 & 0xFFFFFFFF)); + write_output((uint32_t)(arg1 >> 32)); + write_output((uint32_t)(arg2 & 0xFFFFFFFF)); + write_output((uint32_t)(arg2 >> 32)); } bool kcov_comparison_t::operator==(const struct kcov_comparison_t& other) const diff --git a/executor/executor_akaros.cc b/executor/executor_akaros.cc index f70e83807..8cb87d3d7 100644 --- a/executor/executor_akaros.cc +++ b/executor/executor_akaros.cc @@ -98,3 +98,8 @@ uint32_t* write_output(uint32_t v) void write_completed(uint32_t completed) { } + +bool kcov_comparison_t::ignore() const +{ + return false; +} diff --git a/executor/executor_freebsd.cc b/executor/executor_freebsd.cc index b0d5acdec..925bb3814 100644 --- a/executor/executor_freebsd.cc +++ b/executor/executor_freebsd.cc @@ -166,3 +166,8 @@ void write_completed(uint32_t completed) { __atomic_store_n(output_data, completed, __ATOMIC_RELEASE); } + +bool kcov_comparison_t::ignore() const +{ + return false; +} diff --git a/executor/executor_fuchsia.cc b/executor/executor_fuchsia.cc index a93811928..05ded7857 100644 --- a/executor/executor_fuchsia.cc +++ b/executor/executor_fuchsia.cc @@ -61,3 +61,8 @@ uint32_t* write_output(uint32_t v) void write_completed(uint32_t completed) { } + +bool kcov_comparison_t::ignore() const +{ + return false; +} diff --git a/executor/executor_linux.cc b/executor/executor_linux.cc index d49e7e22b..77316fa12 100644 --- a/executor/executor_linux.cc +++ b/executor/executor_linux.cc @@ -34,8 +34,8 @@ const unsigned long KCOV_TRACE_CMP = 1; const int kInFd = 3; const int kOutFd = 4; -const int kCoverSize = 64 << 10; -const int kPageSize = 4 << 10; + +void* const kOutputDataAddr = (void*)0x1bdbc20000ull; uint32_t* output_data; uint32_t* output_pos; @@ -54,7 +54,6 @@ int main(int argc, char** argv) // If it is corrupted ipc package will fail to parse its contents and panic. // But fuzzer constantly invents new ways of how to currupt the region, // so we map the region at a (hopefully) hard to guess address surrounded by unmapped pages. - void* const kOutputDataAddr = (void*)0x1ddbc20000; output_data = (uint32_t*)mmap(kOutputDataAddr, kMaxOutput, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, kOutFd, 0); if (output_data != kOutputDataAddr) fail("mmap of output file failed"); @@ -292,3 +291,37 @@ void write_completed(uint32_t completed) { __atomic_store_n(output_data, completed, __ATOMIC_RELEASE); } + +bool kcov_comparison_t::ignore() const +{ + // Comparisons with 0 are not interesting, fuzzer should be able to guess 0's without help. + if (arg1 == 0 && (arg2 == 0 || (type & KCOV_CMP_CONST))) + return true; + if ((type & KCOV_CMP_SIZE_MASK) == KCOV_CMP_SIZE8) { + // This can be a pointer (assuming 64-bit kernel). + // First of all, we want avert fuzzer from our output region. + // Without this fuzzer manages to discover and corrupt it. + uint64_t out_start = (uint64_t)kOutputDataAddr; + uint64_t out_end = out_start + kMaxOutput; + if (arg1 >= out_start && arg1 <= out_end) + return true; + if (arg2 >= out_start && arg2 <= out_end) + return true; +#if defined(__i386__) || defined(__x86_64__) + // 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_t kmem_start = (uint64_t)0xffff880000000000ull; + uint64_t kmem_end = (uint64_t)0xffff890000000000ull; + bool kptr1 = arg1 >= kmem_start && arg1 <= kmem_end; + bool kptr2 = arg2 >= kmem_start && arg2 <= kmem_end; + if (kptr1 && kptr2) + return true; + if (kptr1 && arg2 == 0) + return true; + if (kptr2 && arg1 == 0) + return true; +#endif + } + return false; +} diff --git a/executor/executor_windows.cc b/executor/executor_windows.cc index 04f6fe6aa..90091c833 100644 --- a/executor/executor_windows.cc +++ b/executor/executor_windows.cc @@ -63,3 +63,8 @@ uint32_t* write_output(uint32_t v) void write_completed(uint32_t completed) { } + +bool kcov_comparison_t::ignore() const +{ + return false; +} |
