aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--executor/common_test.h11
-rw-r--r--executor/executor.cc5
-rw-r--r--executor/executor_test.h13
-rw-r--r--pkg/runtest/run_test.go24
-rw-r--r--sys/test/exec.txt1
5 files changed, 49 insertions, 5 deletions
diff --git a/executor/common_test.h b/executor/common_test.h
index dc39fa326..f5f54d9ee 100644
--- a/executor/common_test.h
+++ b/executor/common_test.h
@@ -180,6 +180,17 @@ static long syz_inject_cover(volatile long a, volatile long b)
#endif
#endif
+#if SYZ_EXECUTOR || __NR_syz_inject_remote_cover
+static long syz_inject_remote_cover(volatile long a, volatile long b)
+#if SYZ_EXECUTOR
+ ; // defined in executor_test.h
+#else
+{
+ return 0;
+}
+#endif
+#endif
+
#if SYZ_EXECUTOR || SYZ_SYSCTL
static void setup_sysctl()
{
diff --git a/executor/executor.cc b/executor/executor.cc
index 3a1ce78bd..17de4e87d 100644
--- a/executor/executor.cc
+++ b/executor/executor.cc
@@ -1001,7 +1001,9 @@ void execute_one()
// that we were killed on timeout before we write any.
// Check for extra coverage is very cheap, effectively a memory load.
const uint64 kSleepMs = 100;
- for (uint64 i = 0; i < prog_extra_cover_timeout / kSleepMs; i++) {
+ for (uint64 i = 0; i < prog_extra_cover_timeout / kSleepMs &&
+ output_data->completed.load(std::memory_order_relaxed) < kMaxCalls;
+ i++) {
sleep_ms(kSleepMs);
write_extra_output();
}
@@ -1267,6 +1269,7 @@ void write_extra_output()
if (!extra_cov.size)
return;
write_output(-1, &extra_cov, rpc::CallFlag::NONE, 997, all_extra_signal);
+ cover_reset(&extra_cov);
}
flatbuffers::span<uint8_t> finish_output(OutputData* output, int proc_id, uint64 req_id, uint64 elapsed,
diff --git a/executor/executor_test.h b/executor/executor_test.h
index 5e128d851..c94de09a2 100644
--- a/executor/executor_test.h
+++ b/executor/executor_test.h
@@ -121,9 +121,8 @@ static void cover_unprotect(cover_t* cov)
{
}
-static long syz_inject_cover(volatile long a, volatile long b)
+static long inject_cover(cover_t* cov, long a, long b)
{
- cover_t* cov = &current_thread->cov;
if (cov->data == nullptr)
return ENOENT;
uint32 size = std::min((uint32)b, cov->mmap_alloc_size);
@@ -132,6 +131,16 @@ static long syz_inject_cover(volatile long a, volatile long b)
return 0;
}
+static long syz_inject_cover(volatile long a, volatile long b)
+{
+ return inject_cover(&current_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;
diff --git a/pkg/runtest/run_test.go b/pkg/runtest/run_test.go
index 3da87dd6c..0861b7e2b 100644
--- a/pkg/runtest/run_test.go
+++ b/pkg/runtest/run_test.go
@@ -144,6 +144,7 @@ func TestCover(t *testing.T) {
type CoverTest struct {
Is64Bit bool
+ ExtraCoverage bool
Input []byte
MaxSignal []uint64
CoverFilter []uint64
@@ -356,6 +357,15 @@ func testCover(t *testing.T, target *prog.Target) {
0xc0000020, 0xc0000010, 0xc0000001},
Signal: []uint64{0xc0001100, 0xc0000140, 0xc0000011, 0xc0000001},
},
+ // Extra coverage.
+ {
+ Is64Bit: true,
+ ExtraCoverage: true,
+ Input: makeCover64(0xc0dec0dec0000001, 0xc0dec0dec0000010),
+ Flags: flatrpc.ExecFlagCollectSignal | flatrpc.ExecFlagCollectCover,
+ Cover: []uint64{0xc0dec0dec0000010, 0xc0dec0dec0000001},
+ Signal: []uint64{0xc0dec0dec0000011, 0xc0dec0dec0000001},
+ },
}
executor := csource.BuildExecutor(t, target, "../../")
for i, test := range tests {
@@ -382,7 +392,11 @@ func testCover(t *testing.T, target *prog.Target) {
}
func testCover1(t *testing.T, ctx context.Context, target *prog.Target, test CoverTest, source *queue.PlainQueue) {
- text := fmt.Sprintf(`syz_inject_cover(&AUTO="%s", AUTO)`, hex.EncodeToString(test.Input))
+ callName := "syz_inject_cover"
+ if test.ExtraCoverage {
+ callName = "syz_inject_remote_cover"
+ }
+ text := fmt.Sprintf(`%s(&AUTO="%s", AUTO)`, callName, hex.EncodeToString(test.Input))
p, err := target.Deserialize([]byte(text), prog.Strict)
if err != nil {
t.Fatal(err)
@@ -390,7 +404,7 @@ func testCover1(t *testing.T, ctx context.Context, target *prog.Target, test Cov
req := &queue.Request{
Prog: p,
ExecOpts: flatrpc.ExecOpts{
- EnvFlags: flatrpc.ExecEnvSignal | flatrpc.ExecEnvSandboxNone,
+ EnvFlags: flatrpc.ExecEnvSignal | flatrpc.ExecEnvExtraCover | flatrpc.ExecEnvSandboxNone,
ExecFlags: test.Flags,
},
}
@@ -403,6 +417,12 @@ func testCover1(t *testing.T, ctx context.Context, target *prog.Target, test Cov
t.Fatalf("program execution failed: status=%v err=%v\n%s", res.Status, res.Err, res.Output)
}
call := res.Info.Calls[0]
+ if test.ExtraCoverage {
+ call = res.Info.Extra
+ if call == nil {
+ t.Fatalf("got no extra coverage info")
+ }
+ }
if test.Cover == nil {
test.Cover = []uint64{}
}
diff --git a/sys/test/exec.txt b/sys/test/exec.txt
index fb895bd18..0faef9820 100644
--- a/sys/test/exec.txt
+++ b/sys/test/exec.txt
@@ -13,6 +13,7 @@ syz_compare_zlib(data ptr[in, array[int8]], size bytesize[data], zdata ptr[in, c
# Copies the data into KCOV buffer verbatim.
syz_inject_cover(ptr ptr[in, array[int8]], size bytesize[ptr])
+syz_inject_remote_cover(ptr ptr[in, array[int8]], size bytesize[ptr]) (prog_timeout[1000], remote_cover)
compare_data [
align0 align0