From 51fd9736425b7f0763861a13db6333f3a9c24fa9 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Tue, 8 Feb 2022 21:26:53 +0100 Subject: [PATCH] Fuzzing of native http1 parser --- apps/restconf/clixon_http1_parse.y | 14 +++++---- apps/restconf/restconf_main_native.c | 44 ++++++++++++++++++++++++++++ test/fuzz/http1/README.md | 28 ++++++++++++++++++ test/fuzz/http1/input/1.http | 10 +++++++ test/fuzz/http1/input/2.http | 5 ++++ test/fuzz/http1/input/3.http | 8 +++++ test/fuzz/http1/input/4.http | 4 +++ test/fuzz/http1/runfuzz.sh | 25 ++++++++++++++++ 8 files changed, 132 insertions(+), 6 deletions(-) create mode 100644 test/fuzz/http1/README.md create mode 100644 test/fuzz/http1/input/1.http create mode 100644 test/fuzz/http1/input/2.http create mode 100644 test/fuzz/http1/input/3.http create mode 100644 test/fuzz/http1/input/4.http create mode 100755 test/fuzz/http1/runfuzz.sh diff --git a/apps/restconf/clixon_http1_parse.y b/apps/restconf/clixon_http1_parse.y index 4b206107..d000a212 100644 --- a/apps/restconf/clixon_http1_parse.y +++ b/apps/restconf/clixon_http1_parse.y @@ -279,13 +279,13 @@ absolute_paths : absolute_paths absolute_path { if (($$ = clixon_string_del_join($1, "/", $2)) == NULL) { free($2); YYABORT;} free($2); - _PARSE_DEBUG("absolute-paths -> absolute-paths absolute -path"); + _PARSE_DEBUG("absolute-paths -> absolute-paths absolute-path"); } | absolute_path { if (($$ = clixon_string_del_join(NULL, "/", $1)) == NULL) { free($1); YYABORT;} free($1); - _PARSE_DEBUG("absolute-paths -> absolute -path"); + _PARSE_DEBUG("absolute-paths -> absolute-path"); } ; @@ -326,10 +326,12 @@ header_fields : header_fields header_field CRLF field-name = token */ header_field : TOKEN COLON ows field_values ows { - if (http1_parse_header_field(_HY, $1, $4) < 0) - YYABORT; + if ($4){ + if (http1_parse_header_field(_HY, $1, $4) < 0) + YYABORT; + free($4); + } free($1); - free($4); _PARSE_DEBUG("header-field -> field-name : field-values"); } ; @@ -342,7 +344,7 @@ field_values : field_vchars $$ = $1; // XXX is there more than one?? _PARSE_DEBUG("field-values -> field-values field-vchars"); } - | { _PARSE_DEBUG("field-values -> "); } + | { $$ = NULL; _PARSE_DEBUG("field-values -> "); } ; diff --git a/apps/restconf/restconf_main_native.c b/apps/restconf/restconf_main_native.c index 383b763c..4374e89d 100644 --- a/apps/restconf/restconf_main_native.c +++ b/apps/restconf/restconf_main_native.c @@ -1400,6 +1400,11 @@ usage(clicon_handle h, exit(0); } +/* Enable for normal use + * Disable for unit testing, fuzzing, etc + */ +#if 1 + int main(int argc, char **argv) @@ -1602,3 +1607,42 @@ main(int argc, restconf_terminate(h); return retval; } + +#else /* Unit test */ + +int +main(int argc, + char **argv) +{ + int retval = -1; + clicon_handle h = NULL; + restconf_conn *rc; + int dbg = 0; + int c; + + while ((c = getopt(argc, argv, "hD:")) != -1) + switch (c) { + case 'h': + fprintf(stderr, "%s [-h] [-D ]\n", argv[0]); + break; + case 'D' : /* debug. Note this overrides any setting in the config */ + if (sscanf(optarg, "%d", &dbg) != 1) + fprintf(stderr, "%s [-h] [-D ]\n", argv[0]); + break; + } + if ((h = restconf_handle_init()) == NULL) + goto done; + clicon_log_init(__FILE__, LOG_DEBUG, CLICON_LOG_STDERR); + clicon_debug_init(dbg, NULL); + if ((rc = restconf_conn_new(h, 0)) == NULL) + goto done; + if (restconf_stream_data_new(rc, 0) == NULL) + goto done; + if (clixon_http1_parse_file(h, rc, stdin, "stdin") < 0) + goto done; + retval = 0; + done: + return retval; +} + +#endif diff --git a/test/fuzz/http1/README.md b/test/fuzz/http1/README.md new file mode 100644 index 00000000..c501da86 --- /dev/null +++ b/test/fuzz/http1/README.md @@ -0,0 +1,28 @@ +# Clixon http1 fuzzing + +This dir contains code for fuzzing the clixon http1 parser. This is normally inside the +native restconf app and need some special compiling to run stand-alone. + +Install AFL, see [..](..) + +Edit `apps/restconf/restconf_main_native.c` by disabling the regular +main function and replacing it with the unit testing `main`: +``` +--- a/apps/restconf/restconf_main_native.c ++++ b/apps/restconf/restconf_main_native.c +@@ -1403,7 +1403,7 @@ usage(clicon_handle h, + /* Enable for normal use + * Disable for unit testing, fuzzing, etc + */ +-#if 1 ++#if 0 +``` + +Build and install clixon libraries and restconf statically +``` + ./configure LINKAGE=static INSTALLFLAGS="" CC=/usr/bin/afl-clang-fast + make + sudo make install + ./runfuzz.sh +``` + diff --git a/test/fuzz/http1/input/1.http b/test/fuzz/http1/input/1.http new file mode 100644 index 00000000..9bb0ee9b --- /dev/null +++ b/test/fuzz/http1/input/1.http @@ -0,0 +1,10 @@ +PUT /restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0 HTTP/1.1 +Host: 127.0.0.1 +Accept: */* +Content-Type: application/yang-data+json +Content-Length: 91 + +{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}} + + + diff --git a/test/fuzz/http1/input/2.http b/test/fuzz/http1/input/2.http new file mode 100644 index 00000000..4d438524 --- /dev/null +++ b/test/fuzz/http1/input/2.http @@ -0,0 +1,5 @@ +GET /restconf/data HTTP/1.1 +Host: localhost +Accept: application/yang-data+xml + + diff --git a/test/fuzz/http1/input/3.http b/test/fuzz/http1/input/3.http new file mode 100644 index 00000000..a259c4e5 --- /dev/null +++ b/test/fuzz/http1/input/3.http @@ -0,0 +1,8 @@ +POST /restconf/data/ietf-interfaces:interfaces HTTP/1.1 +Host: 127.0.0.1 +Accept: application/yang-data+xml +Content-Type: application/yang-data+xml +Content-Length: 138 + +eth/0/42ex:ethtrue + diff --git a/test/fuzz/http1/input/4.http b/test/fuzz/http1/input/4.http new file mode 100644 index 00000000..5ce1b0c5 --- /dev/null +++ b/test/fuzz/http1/input/4.http @@ -0,0 +1,4 @@ +DELETE /restconf/data/ietf-interfaces:interfaces HTTP/1.1 +Host: 127.0.0.1 + + diff --git a/test/fuzz/http1/runfuzz.sh b/test/fuzz/http1/runfuzz.sh new file mode 100755 index 00000000..c3af2b97 --- /dev/null +++ b/test/fuzz/http1/runfuzz.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +# Run a fuzzing test using american fuzzy lop +# Add input strings in input +set -eux + +if [ $# -ne 0 ]; then + echo "usage: $0" + exit 255 +fi + +MEGS=500 # memory limit for child process (50 MB) + +# remove input and input dirs +#test ! -d input || rm -rf input +test ! -d output || sudo rm -rf output + +# create if dirs dont exists +#test -d input || mkdir input +test -d output || mkdir output + +# Run script +# CC=/usr/bin/afl-clang +sudo afl-fuzz -i input -o output -d -m $MEGS -- /usr/local/sbin/clixon_restconf + +