From 134afc7288461bf0ef0506dfd5430bf28de0880c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Petr=20=C5=A0tetiar?= Date: Tue, 13 Oct 2020 14:36:44 +0200 Subject: [PATCH] tests: add libFuzzer based fuzzing MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit LibFuzzer is in-process, coverage-guided, evolutionary fuzzing engine. LibFuzzer is linked with the library under test, and feeds fuzzed inputs to the library via a specific fuzzing entrypoint (aka "target function"); the fuzzer then tracks which areas of the code are reached, and generates mutations on the corpus of input data in order to maximize the code coverage. So lets use libFuzzer to fuzz dns_handle_packet for the start. Ref: https://llvm.org/docs/LibFuzzer.html Signed-off-by: Petr Å tetiar --- CMakeLists.txt | 5 ++++ tests/CMakeLists.txt | 3 ++ tests/fuzz/CMakeLists.txt | 18 ++++++++++++ tests/fuzz/dict/mdns.dict | 6 ++++ tests/fuzz/inputs/query_qu.pcap | Bin 0 -> 128 bytes tests/fuzz/test-fuzz.c | 48 ++++++++++++++++++++++++++++++++ 6 files changed, 80 insertions(+) create mode 100644 tests/CMakeLists.txt create mode 100644 tests/fuzz/CMakeLists.txt create mode 100644 tests/fuzz/dict/mdns.dict create mode 100644 tests/fuzz/inputs/query_qu.pcap create mode 100644 tests/fuzz/test-fuzz.c diff --git a/CMakeLists.txt b/CMakeLists.txt index e087203..80d1cf5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,11 @@ TARGET_LINK_LIBRARIES(umdns-lib ${LIBS}) ADD_EXECUTABLE(umdns main.c) TARGET_LINK_LIBRARIES(umdns umdns-lib) +IF(UNIT_TESTING) + ENABLE_TESTING() + ADD_SUBDIRECTORY(tests) +ENDIF() + INSTALL(TARGETS umdns RUNTIME DESTINATION sbin ) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..02b121c --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,3 @@ +IF(CMAKE_C_COMPILER_ID STREQUAL "Clang") + ADD_SUBDIRECTORY(fuzz) +ENDIF() diff --git a/tests/fuzz/CMakeLists.txt b/tests/fuzz/CMakeLists.txt new file mode 100644 index 0000000..e2f9873 --- /dev/null +++ b/tests/fuzz/CMakeLists.txt @@ -0,0 +1,18 @@ +FILE(GLOB test_cases "test-*.c") + +MACRO(ADD_FUZZER_TEST name) + ADD_EXECUTABLE(${name} ${name}.c) + TARGET_COMPILE_OPTIONS(${name} PRIVATE -g -O1 -fno-omit-frame-pointer -fsanitize=fuzzer,address,leak,undefined) + TARGET_INCLUDE_DIRECTORIES(${name} PRIVATE ${PROJECT_SOURCE_DIR}) + TARGET_LINK_OPTIONS(${name} PRIVATE -stdlib=libc++ -fsanitize=fuzzer,address,leak,undefined) + TARGET_LINK_LIBRARIES(${name} umdns-lib-san ${LIBS}) + ADD_TEST( + NAME ${name} + COMMAND ${name} -max_len=256 -timeout=10 -max_total_time=300 ${CMAKE_CURRENT_SOURCE_DIR}/corpus + ) +ENDMACRO(ADD_FUZZER_TEST) + +FOREACH(test_case ${test_cases}) + GET_FILENAME_COMPONENT(test_case ${test_case} NAME_WE) + ADD_FUZZER_TEST(${test_case}) +ENDFOREACH(test_case) diff --git a/tests/fuzz/dict/mdns.dict b/tests/fuzz/dict/mdns.dict new file mode 100644 index 0000000..f8f80c1 --- /dev/null +++ b/tests/fuzz/dict/mdns.dict @@ -0,0 +1,6 @@ +"\x0c" +"\x78" +"\xc0\xb0" +"\x80\x01" +"." +"_" diff --git a/tests/fuzz/inputs/query_qu.pcap b/tests/fuzz/inputs/query_qu.pcap new file mode 100644 index 0000000000000000000000000000000000000000..b1857a963a4f3efb0af43ee6714d96f07e04c198 GIT binary patch literal 128 zcmca|c+)~A1{MYcU}0bca;#!n84i^_!)B~WL$V-uz3}#=K0TqLkg8^rJacWUnW^!sVdwfb>v2Jk+OMGcc0c%cv Ma$*hx15X1Z0A`FJT>t<8 literal 0 HcmV?d00001 diff --git a/tests/fuzz/test-fuzz.c b/tests/fuzz/test-fuzz.c new file mode 100644 index 0000000..ca6caa1 --- /dev/null +++ b/tests/fuzz/test-fuzz.c @@ -0,0 +1,48 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "dns.h" +#include "cache.c" +#include "interface.h" + +int cfg_proto = 0; +int cfg_no_subnet = 0; + +static void fuzz_dns_handle_packet(uint8_t *input, size_t size) +{ + struct sockaddr from; + struct interface iface; + struct cache_service *s, *t; + + memset(&from, 0, sizeof(from)); + memset(&iface, 0, sizeof(iface)); + + cache_init(); + dns_handle_packet(&iface, &from, 1922, input, size); + + avl_for_each_element_safe(&services, s, avl, t) + cache_service_free(s); +} + +int LLVMFuzzerTestOneInput(const uint8_t *input, size_t size) +{ + uint8_t *buf = calloc(1, size); + if (!buf) + return 0; + + memcpy(buf, input, size); + fuzz_dns_handle_packet(buf, size); + free(buf); + + return 0; +} -- 2.30.2