From 8b2f89ca029a12412f0482c71f8f2cda3312285a Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Sun, 8 Jul 2018 22:12:15 +0100 Subject: [PATCH] Add fuzz testing for control protocol based on LLVM libFuzzer. --- .gitignore | 2 ++ src/tests/cptests/Makefile | 19 ++++++++++- src/tests/cptests/fuzz.cc | 68 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 src/tests/cptests/fuzz.cc diff --git a/.gitignore b/.gitignore index 725676e..b092140 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ src/tests/loadtests src/tests/includes src/tests/cptests/includes src/tests/cptests/cptests +src/tests/cptests/corpus +src/tests/cptests/fuzz diff --git a/src/tests/cptests/Makefile b/src/tests/cptests/Makefile index a4a1be1..8e48a8e 100644 --- a/src/tests/cptests/Makefile +++ b/src/tests/cptests/Makefile @@ -10,7 +10,7 @@ build-tests: prepare-incdir cptests run-tests: cptests ./cptests - + # Create an "includes" directory populated with a combination of real and mock headers: prepare-incdir: mkdir -p includes @@ -31,5 +31,22 @@ $(parent_objs): %.o: ../../%.cc clean: rm -f *.o *.d cptests + +# Experimental LLVM-libFuzzer based fuzzer. "make fuzz" to build; "fuzz corpus" to run (and store +# interesting test data in "corpus" directory). + +fuzz_parent_test_objects = $(foreach obj,$(notdir $(parent_test_objects)),fuzz-$(obj)) +fuzz_objects = $(foreach obj,$(parent_objs),fuzz-$(obj)) + +fuzz: fuzz.cc $(fuzz_parent_test_objects) $(fuzz_objects) + clang++ -std=c++11 -g -O1 -Iincludes -I../../dasynq -fsanitize=fuzzer,address,undefined,leak fuzz.cc $(fuzz_parent_test_objects) $(fuzz_objects) -o fuzz + +$(fuzz_parent_test_objects): fuzz-%.o: ../%.cc + clang -O1 -fsanitize=address,undefined,fuzzer-no-link,leak -MMD -MP -I../includes -I../../dasynq -c $< -o $@ + +$(fuzz_objects): fuzz-%.o: ../../%.cc + clang -O1 -fsanitize=address,undefined,fuzzer-no-link,leak -MMD -MP -Iincludes -I../../dasynq -c $< -o $@ + + -include $(objects:.o=.d) -include $(parent_objects:.o=.d) diff --git a/src/tests/cptests/fuzz.cc b/src/tests/cptests/fuzz.cc new file mode 100644 index 0000000..df197da --- /dev/null +++ b/src/tests/cptests/fuzz.cc @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include + +#include "dinit.h" +#include "service.h" +#include "baseproc-sys.h" +#include "control.h" + +// Control protocol fuzzing. + + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) +{ + if (Size == 0) return 0; + + service_set sset; + + service_record *s1 = new service_record(&sset, "test-service-1", service_type_t::INTERNAL, {}); + sset.add_service(s1); + service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {}); + sset.add_service(s2); + service_record *s3 = new service_record(&sset, "test-service-3", service_type_t::INTERNAL, {}); + sset.add_service(s3); + + int fd = bp_sys::allocfd(); + auto *cc = new control_conn_t(event_loop, &sset, fd); + + std::vector input_data(Data, Data + Size); + bp_sys::supply_read_data(fd, std::move(input_data)); + + event_loop.regd_bidi_watchers[fd]->read_ready(event_loop, fd); + + // Write will process immediately, so there's no need for this: + //event_loop.regd_bidi_watchers[fd]->write_ready(event_loop, fd); + + // We expect, for each service: + // (1 byte) DINIT_RP_SVCINFO + // (1 byte) service name length + // (1 byte) state + // (1 byte) target state + // (1 byte) flags: has console, waiting for console, start skipped + // (1 byte) stop reason + // (2 bytes) reserved + // (? bytes) exit status (int) / process id (pid_t) + // (N bytes) service name + + delete cc; + + return 0; +} + +/* + +#define RUN_TEST(name, spacing) \ + std::cout << #name "..." spacing; \ + name(); \ + std::cout << "PASSED" << std::endl; + +int main(int argc, char **argv) +{ + RUN_TEST(cptest_queryver, " "); + RUN_TEST(cptest_listservices, ""); + return 0; +} +*/ -- 2.25.1