Fuzzer is supposed to stop when first bug is found and report failure. Present fuzzers fork new child at each iteration to isolate side-effects. But child's exit code is ignored, i.e. libfuzzer does not see any crashes.
Right now virtio-net fuzzer instantly falls on assert in iov_copy and dumps crash-*, but fuzzing continues and ends successfully if global timeout is set. Let's put required logic into helper function "fork_fuzzer_and_wait". Signed-off-by: Konstantin Khlebnikov <khlebni...@yandex-team.ru> --- tests/qtest/fuzz/fork_fuzz.c | 26 ++++++++++++++++++++++++++ tests/qtest/fuzz/fork_fuzz.h | 1 + tests/qtest/fuzz/generic_fuzz.c | 3 +-- tests/qtest/fuzz/i440fx_fuzz.c | 3 +-- tests/qtest/fuzz/virtio_blk_fuzz.c | 6 ++---- tests/qtest/fuzz/virtio_net_fuzz.c | 6 ++---- tests/qtest/fuzz/virtio_scsi_fuzz.c | 6 ++---- 7 files changed, 35 insertions(+), 16 deletions(-) diff --git a/tests/qtest/fuzz/fork_fuzz.c b/tests/qtest/fuzz/fork_fuzz.c index 6ffb2a7937..6e3a3867bf 100644 --- a/tests/qtest/fuzz/fork_fuzz.c +++ b/tests/qtest/fuzz/fork_fuzz.c @@ -38,4 +38,30 @@ void counter_shm_init(void) free(copy); } +/* Returns true in child process */ +bool fork_fuzzer_and_wait(void) +{ + pid_t pid; + int wstatus; + + pid = fork(); + if (pid < 0) { + perror("fork"); + abort(); + } + + if (pid == 0) { + return true; + } + if (waitpid(pid, &wstatus, 0) < 0) { + perror("waitpid"); + abort(); + } + + if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0) { + abort(); + } + + return false; +} diff --git a/tests/qtest/fuzz/fork_fuzz.h b/tests/qtest/fuzz/fork_fuzz.h index 9ecb8b58ef..792e922731 100644 --- a/tests/qtest/fuzz/fork_fuzz.h +++ b/tests/qtest/fuzz/fork_fuzz.h @@ -18,6 +18,7 @@ extern uint8_t __FUZZ_COUNTERS_START; extern uint8_t __FUZZ_COUNTERS_END; void counter_shm_init(void); +bool fork_fuzzer_and_wait(void); #endif diff --git a/tests/qtest/fuzz/generic_fuzz.c b/tests/qtest/fuzz/generic_fuzz.c index dd7e25851c..f0e25b39ea 100644 --- a/tests/qtest/fuzz/generic_fuzz.c +++ b/tests/qtest/fuzz/generic_fuzz.c @@ -667,7 +667,7 @@ static void generic_fuzz(QTestState *s, const unsigned char *Data, size_t Size) size_t cmd_len; uint8_t op; - if (fork() == 0) { + if (fork_fuzzer_and_wait()) { struct sigaction sact; struct itimerval timer; sigset_t set; @@ -723,7 +723,6 @@ static void generic_fuzz(QTestState *s, const unsigned char *Data, size_t Size) _Exit(0); } else { flush_events(s); - wait(0); } } diff --git a/tests/qtest/fuzz/i440fx_fuzz.c b/tests/qtest/fuzz/i440fx_fuzz.c index 86796bff2b..0b927f4b3a 100644 --- a/tests/qtest/fuzz/i440fx_fuzz.c +++ b/tests/qtest/fuzz/i440fx_fuzz.c @@ -147,12 +147,11 @@ static void i440fx_fuzz_qos(QTestState *s, static void i440fx_fuzz_qos_fork(QTestState *s, const unsigned char *Data, size_t Size) { - if (fork() == 0) { + if (fork_fuzzer_and_wait()) { i440fx_fuzz_qos(s, Data, Size); _Exit(0); } else { flush_events(s); - wait(NULL); } } diff --git a/tests/qtest/fuzz/virtio_blk_fuzz.c b/tests/qtest/fuzz/virtio_blk_fuzz.c index 623a756fd4..9532dc1fa7 100644 --- a/tests/qtest/fuzz/virtio_blk_fuzz.c +++ b/tests/qtest/fuzz/virtio_blk_fuzz.c @@ -136,13 +136,12 @@ static void virtio_blk_fork_fuzz(QTestState *s, if (!queues) { queues = qvirtio_blk_init(blk->vdev, 0); } - if (fork() == 0) { + if (fork_fuzzer_and_wait()) { virtio_blk_fuzz(s, queues, Data, Size); flush_events(s); _Exit(0); } else { flush_events(s); - wait(NULL); } } @@ -152,7 +151,7 @@ static void virtio_blk_with_flag_fuzz(QTestState *s, QVirtioBlk *blk = fuzz_qos_obj; static QVirtioBlkQueues *queues; - if (fork() == 0) { + if (fork_fuzzer_and_wait()) { if (Size >= sizeof(uint64_t)) { queues = qvirtio_blk_init(blk->vdev, *(uint64_t *)Data); virtio_blk_fuzz(s, queues, @@ -162,7 +161,6 @@ static void virtio_blk_with_flag_fuzz(QTestState *s, _Exit(0); } else { flush_events(s); - wait(NULL); } } diff --git a/tests/qtest/fuzz/virtio_net_fuzz.c b/tests/qtest/fuzz/virtio_net_fuzz.c index 0e873ab8e2..6b492ef9e7 100644 --- a/tests/qtest/fuzz/virtio_net_fuzz.c +++ b/tests/qtest/fuzz/virtio_net_fuzz.c @@ -118,26 +118,24 @@ static void virtio_net_fuzz_multi(QTestState *s, static void virtio_net_fork_fuzz(QTestState *s, const unsigned char *Data, size_t Size) { - if (fork() == 0) { + if (fork_fuzzer_and_wait()) { virtio_net_fuzz_multi(s, Data, Size, false); flush_events(s); _Exit(0); } else { flush_events(s); - wait(NULL); } } static void virtio_net_fork_fuzz_check_used(QTestState *s, const unsigned char *Data, size_t Size) { - if (fork() == 0) { + if (fork_fuzzer_and_wait()) { virtio_net_fuzz_multi(s, Data, Size, true); flush_events(s); _Exit(0); } else { flush_events(s); - wait(NULL); } } diff --git a/tests/qtest/fuzz/virtio_scsi_fuzz.c b/tests/qtest/fuzz/virtio_scsi_fuzz.c index 6ff6fabe4a..c7eaf3242b 100644 --- a/tests/qtest/fuzz/virtio_scsi_fuzz.c +++ b/tests/qtest/fuzz/virtio_scsi_fuzz.c @@ -140,13 +140,12 @@ static void virtio_scsi_fork_fuzz(QTestState *s, if (!queues) { queues = qvirtio_scsi_init(scsi->vdev, 0); } - if (fork() == 0) { + if (fork_fuzzer_and_wait()) { virtio_scsi_fuzz(s, queues, Data, Size); flush_events(s); _Exit(0); } else { flush_events(s); - wait(NULL); } } @@ -156,7 +155,7 @@ static void virtio_scsi_with_flag_fuzz(QTestState *s, QVirtioSCSI *scsi = fuzz_qos_obj; static QVirtioSCSIQueues *queues; - if (fork() == 0) { + if (fork_fuzzer_and_wait()) { if (Size >= sizeof(uint64_t)) { queues = qvirtio_scsi_init(scsi->vdev, *(uint64_t *)Data); virtio_scsi_fuzz(s, queues, @@ -166,7 +165,6 @@ static void virtio_scsi_with_flag_fuzz(QTestState *s, _Exit(0); } else { flush_events(s); - wait(NULL); } }