aboutsummaryrefslogtreecommitdiffstats
path: root/executor
diff options
context:
space:
mode:
Diffstat (limited to 'executor')
-rw-r--r--executor/cov_filter.h58
-rw-r--r--executor/executor.cc11
-rw-r--r--executor/test.h34
3 files changed, 101 insertions, 2 deletions
diff --git a/executor/cov_filter.h b/executor/cov_filter.h
new file mode 100644
index 000000000..66cb0bcdc
--- /dev/null
+++ b/executor/cov_filter.h
@@ -0,0 +1,58 @@
+// Copyright 2020 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 <fcntl.h>
+#include <stdio.h>
+
+#if GOOS_linux || GOOS_freebsd || GOOS_netbsd || GOOS_openbsd || GOOS_akaros
+#include <sys/mman.h>
+#include <sys/stat.h>
+#endif
+
+struct cov_filter_t {
+ uint32 pcstart;
+ uint32 pcsize;
+ uint8 bitmap[];
+};
+
+static cov_filter_t* cov_filter;
+
+static void init_coverage_filter()
+{
+#if SYZ_EXECUTOR_USES_SHMEM
+ int f = open("/syz-cover-bitmap", O_RDONLY);
+ if (f < 0) {
+ // We don't fail here because we don't know yet if we should use coverage filter or not.
+ // We will receive the flag only in execute flags and will fail in coverage_filter if necessary.
+ debug("bitmap is no found, coverage filter disabled\n");
+ return;
+ }
+ struct stat st;
+ if (fstat(f, &st))
+ fail("faied to stat coverage filter");
+ // A random address for bitmap. Don't corrupt output_data.
+ void* preferred = (void*)0x110f230000ull;
+ cov_filter = (cov_filter_t*)mmap(preferred, st.st_size, PROT_READ, MAP_PRIVATE, f, 0);
+ if (cov_filter != preferred)
+ fail("failed to initialize coverage filter bitmap at %p", preferred);
+ if ((uint32)st.st_size != sizeof(uint32) * 2 + ((cov_filter->pcsize >> 4) + 7) / 8)
+ fail("bad coverage filter bitmap size");
+ close(f);
+#endif
+}
+
+static bool coverage_filter(uint64 pc)
+{
+ if (cov_filter == NULL)
+ fail("coverage filter was enabled but bitmap initialization failed");
+ // Prevent out of bound while searching bitmap.
+ uint32 pc32 = (uint32)(pc & 0xffffffff);
+ if (pc32 < cov_filter->pcstart || pc32 > cov_filter->pcstart + cov_filter->pcsize)
+ return false;
+ // For minimizing the size of bitmap, the lowest 4-bit will be dropped.
+ pc32 -= cov_filter->pcstart;
+ pc32 = pc32 >> 4;
+ uint32 idx = pc32 / 8;
+ uint32 shift = pc32 % 8;
+ return (cov_filter->bitmap[idx] & (1 << shift)) > 0;
+}
diff --git a/executor/executor.cc b/executor/executor.cc
index 2f90e4092..7c31f9cc2 100644
--- a/executor/executor.cc
+++ b/executor/executor.cc
@@ -141,6 +141,7 @@ static bool flag_collect_cover;
static bool flag_dedup_cover;
static bool flag_threaded;
static bool flag_collide;
+static bool flag_coverage_filter;
// If true, then executor should write the comparisons data to fuzzer.
static bool flag_comparisons;
@@ -350,6 +351,8 @@ static void setup_features(char** enable, int n);
#error "unknown OS"
#endif
+#include "cov_filter.h"
+
#include "test.h"
int main(int argc, char** argv)
@@ -428,6 +431,7 @@ int main(int argc, char** argv)
// Don't enable comps because we don't use them in the fuzzer yet.
cover_enable(&extra_cov, false, true);
}
+ init_coverage_filter();
}
int status = 0;
@@ -547,14 +551,15 @@ void receive_execute()
flag_comparisons = req.exec_flags & (1 << 3);
flag_threaded = req.exec_flags & (1 << 4);
flag_collide = req.exec_flags & (1 << 5);
+ flag_coverage_filter = req.exec_flags & (1 << 6);
flag_fault_call = req.fault_call;
flag_fault_nth = req.fault_nth;
if (!flag_threaded)
flag_collide = false;
- debug("[%llums] exec opts: procid=%llu threaded=%d collide=%d cover=%d comps=%d dedup=%d fault=%d/%d/%d prog=%llu\n",
+ debug("[%llums] exec opts: procid=%llu threaded=%d collide=%d cover=%d comps=%d dedup=%d fault=%d/%d/%d prog=%llu filter=%d\n",
current_time_ms() - start_time_ms, procid, flag_threaded, flag_collide,
flag_collect_cover, flag_comparisons, flag_dedup_cover, flag_fault,
- flag_fault_call, flag_fault_nth, req.prog_size);
+ flag_fault_call, flag_fault_nth, req.prog_size, flag_coverage_filter);
if (SYZ_EXECUTOR_USES_SHMEM) {
if (req.prog_size)
fail("need_prog: no program");
@@ -873,6 +878,8 @@ void write_coverage_signal(cover_t* cov, uint32* signal_count_pos, uint32* cover
}
cover_data_t sig = pc ^ prev;
prev = hash(pc);
+ if (flag_coverage_filter && !coverage_filter((uint64)pc))
+ continue;
if (dedup(sig))
continue;
write_output(sig);
diff --git a/executor/test.h b/executor/test.h
index 37d03b65a..c8492ed73 100644
--- a/executor/test.h
+++ b/executor/test.h
@@ -201,6 +201,39 @@ static int test_csum_inet_acc()
return 0;
}
+static int test_coverage_filter()
+{
+ struct tmp_cov_filter_t {
+ uint32 pcstart;
+ uint32 pcsize;
+ uint8 bitmap[((0x1000 >> 4) + 7) / 8];
+ };
+ static struct tmp_cov_filter_t tmp_cov_filter;
+ tmp_cov_filter.pcstart = 0x81000000;
+ tmp_cov_filter.pcsize = 0x1000;
+ memset(tmp_cov_filter.bitmap, 0, ((0x1000 >> 4) + 7) / 8);
+ cov_filter = (cov_filter_t*)&tmp_cov_filter;
+
+ uint64 full_enable_pc = 0xffffffff81000765;
+ uint64 full_disable_pc = 0xffffffff81000627;
+ uint64 full_out_pc = 0xffffffff82000000;
+
+ uint32 enable_pc = (uint32)full_enable_pc & 0xffffffff;
+ uint32 idx = ((enable_pc - cov_filter->pcstart) >> 4) / 8;
+ uint32 shift = ((enable_pc - cov_filter->pcstart) >> 4) % 8;
+ cov_filter->bitmap[idx] |= (1 << shift);
+
+ if (!coverage_filter(full_enable_pc))
+ return 1;
+ if (coverage_filter(full_disable_pc))
+ return 1;
+ if (coverage_filter(full_out_pc))
+ return 1;
+
+ cov_filter = NULL;
+ return 0;
+}
+
static struct {
const char* name;
int (*f)();
@@ -211,6 +244,7 @@ static struct {
#if GOOS_linux && (GOARCH_amd64 || GOARCH_ppc64 || GOARCH_ppc64le)
{"test_kvm", test_kvm},
#endif
+ {"test_coverage_filter", test_coverage_filter},
};
static int run_tests()