diff mbox series

[cgi-io,05/12] Add fuzzing of multipart_parser

Message ID 20201012123718.25623-6-ynezz@true.cz
State Accepted
Delegated to: Petr Štetiar
Headers show
Series fixes and improvements | expand

Commit Message

Petr Štetiar Oct. 12, 2020, 12:37 p.m. UTC
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.

Lets use libFuzzer to fuzz multipart_parser for the start.

Ref: https://llvm.org/docs/LibFuzzer.html
Signed-off-by: Petr Štetiar <ynezz@true.cz>
---
 CMakeLists.txt                                |  4 ++
 tests/CMakeLists.txt                          |  3 ++
 tests/fuzz-multipart-parser/CMakeLists.txt    | 18 ++++++++
 tests/fuzz-multipart-parser/corpus/.keep      |  0
 tests/fuzz-multipart-parser/dict/parser.dict  | 10 +++++
 tests/fuzz-multipart-parser/inputs/input1.txt |  6 +++
 tests/fuzz-multipart-parser/inputs/input2.txt | 10 +++++
 .../test-fuzz-multipart-parser.c              | 43 +++++++++++++++++++
 8 files changed, 94 insertions(+)
 create mode 100644 tests/CMakeLists.txt
 create mode 100644 tests/fuzz-multipart-parser/CMakeLists.txt
 create mode 100644 tests/fuzz-multipart-parser/corpus/.keep
 create mode 100644 tests/fuzz-multipart-parser/dict/parser.dict
 create mode 100644 tests/fuzz-multipart-parser/inputs/input1.txt
 create mode 100644 tests/fuzz-multipart-parser/inputs/input2.txt
 create mode 100644 tests/fuzz-multipart-parser/test-fuzz-multipart-parser.c
diff mbox series

Patch

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 693830a85274..b60d08e96e3c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -24,5 +24,9 @@  ADD_LIBRARY(cgi-lib STATIC multipart_parser.c util.c)
 ADD_EXECUTABLE(cgi-io main.c)
 TARGET_LINK_LIBRARIES(cgi-io cgi-lib ${ubox} ${ubus})
 
+IF(UNIT_TESTING)
+  ENABLE_TESTING()
+  ADD_SUBDIRECTORY(tests)
+ENDIF()
 
 INSTALL(TARGETS cgi-io RUNTIME DESTINATION sbin)
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644
index 000000000000..8bb2a59412da
--- /dev/null
+++ b/tests/CMakeLists.txt
@@ -0,0 +1,3 @@ 
+IF(CMAKE_C_COMPILER_ID STREQUAL "Clang")
+  ADD_SUBDIRECTORY(fuzz-multipart-parser)
+ENDIF()
diff --git a/tests/fuzz-multipart-parser/CMakeLists.txt b/tests/fuzz-multipart-parser/CMakeLists.txt
new file mode 100644
index 000000000000..0a3a9893fc70
--- /dev/null
+++ b/tests/fuzz-multipart-parser/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} cgi-lib)
+  ADD_TEST(
+    NAME ${name}
+	COMMAND ${name} -max_len=256 -timeout=10 -max_total_time=300 -dict=${CMAKE_CURRENT_SOURCE_DIR}/dict/parser.dict ${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-multipart-parser/corpus/.keep b/tests/fuzz-multipart-parser/corpus/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/fuzz-multipart-parser/dict/parser.dict b/tests/fuzz-multipart-parser/dict/parser.dict
new file mode 100644
index 000000000000..72a5bdd3d8e6
--- /dev/null
+++ b/tests/fuzz-multipart-parser/dict/parser.dict
@@ -0,0 +1,10 @@ 
+"Content-Disposition: form-data; name="
+"\x0D\x0A"
+"\x0D"
+"x0A"
+"="
+";"
+"--"
+"Content-Type:"
+"filename="
+"--12--34--56"
diff --git a/tests/fuzz-multipart-parser/inputs/input1.txt b/tests/fuzz-multipart-parser/inputs/input1.txt
new file mode 100644
index 000000000000..849873e3905e
--- /dev/null
+++ b/tests/fuzz-multipart-parser/inputs/input1.txt
@@ -0,0 +1,6 @@ 
+--AaB03x
+Content-Disposition: form-data; name="files"; filename="fi;le1.txt"
+Content-Type: text/plain
+
+contents
+--AaB03x--
\ No newline at end of file
diff --git a/tests/fuzz-multipart-parser/inputs/input2.txt b/tests/fuzz-multipart-parser/inputs/input2.txt
new file mode 100644
index 000000000000..7ba009902eee
--- /dev/null
+++ b/tests/fuzz-multipart-parser/inputs/input2.txt
@@ -0,0 +1,10 @@ 
+--AaB03x
+Content-Disposition: form-data; name="submit-name"
+
+Larry
+--AaB03x
+Content-Disposition: form-data; name="files"; filename="file1.txt"
+Content-Type: text/plain
+
+
+--AaB03x--
diff --git a/tests/fuzz-multipart-parser/test-fuzz-multipart-parser.c b/tests/fuzz-multipart-parser/test-fuzz-multipart-parser.c
new file mode 100644
index 000000000000..ca952d9af9db
--- /dev/null
+++ b/tests/fuzz-multipart-parser/test-fuzz-multipart-parser.c
@@ -0,0 +1,43 @@ 
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "multipart_parser.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *input, size_t size)
+{
+	char *buf = NULL;
+	multipart_parser *p;
+	static multipart_parser_settings s = {
+		.on_part_data        = NULL,
+		.on_headers_complete = NULL,
+		.on_part_data_end    = NULL,
+		.on_header_field     = NULL,
+		.on_header_value     = NULL,
+	};
+	buf = calloc(1, size + 1);
+	if (!buf)
+		return 0;
+
+	memcpy(buf, input, size);
+	p = multipart_parser_init(buf, &s);
+	if (!p) {
+		free(buf);
+		return 0;
+	}
+
+	multipart_parser_execute(p, buf, size + 1);
+	multipart_parser_free(p);
+	free(buf);
+
+	return 0;
+}