diff options
| author | oxpa <iippolitov@gmail.com> | 2024-09-17 14:21:10 +0100 |
|---|---|---|
| committer | oxpa <iippolitov@gmail.com> | 2024-09-17 14:21:10 +0100 |
| commit | 2417826d8bebf921ee1be102ef8ce702f0683d66 (patch) | |
| tree | 76d29a1705415ed7368870826dbb2f04942ee794 /fuzzing | |
| parent | 0e79d961bb1ea68674961da1703ffedb1ddf6e43 (diff) | |
| parent | 24ed91f40634372d99f67f0e4e3c2ac0abde81bd (diff) | |
| download | unit-2417826d8bebf921ee1be102ef8ce702f0683d66.tar.gz unit-2417826d8bebf921ee1be102ef8ce702f0683d66.tar.bz2 | |
Merge tag '1.33.0' into packaging.
Unit 1.33.0 release.
Diffstat (limited to 'fuzzing')
45 files changed, 881 insertions, 0 deletions
diff --git a/fuzzing/.gitattributes b/fuzzing/.gitattributes new file mode 100644 index 00000000..70e0757b --- /dev/null +++ b/fuzzing/.gitattributes @@ -0,0 +1 @@ +*.bin whitespace=-blank-at-eol,-blank-at-eof diff --git a/fuzzing/README.md b/fuzzing/README.md new file mode 100644 index 00000000..9c70c801 --- /dev/null +++ b/fuzzing/README.md @@ -0,0 +1,68 @@ +# Fuzzing unit + +These tests are generally advised to run only on GNU/Linux. + +## Build fuzzers using libFuzzer. + +Running `sh fuzzing/build-fuzz.sh` can build all the fuzzers with standard +`ASan` and `UBSan`. + +### More comprehensive How-to Guide. + +#### Export flags that are to be used by Unit for fuzzing. + +Note that in `CFLAGS` and `CXXFLAGS`, any type of sanitizers can be added. + +- [AddressSanitizer](https://clang.llvm.org/docs/AddressSanitizer.html), + [ThreadSanitizer](https://clang.llvm.org/docs/ThreadSanitizer.html), + [MemorySanitizer](https://clang.llvm.org/docs/MemorySanitizer.html), + [UndefinedBehaviorSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html), + [LeakSanitizer](https://clang.llvm.org/docs/LeakSanitizer.html). + +```shell +$ export CC=clang +$ export CXX=clang++ +$ export CFLAGS="-g -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=fuzzer-no-link" +$ export CXXFLAGS="-g -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=fuzzer-no-link" +$ export LIB_FUZZING_ENGINE="-fsanitize=fuzzer" +``` + +#### Build Unit for Fuzzing. + +```shell +$ ./configure --no-regex --no-pcre2 --fuzz=$LIB_FUZZING_ENGINE +$ make fuzz -j$(nproc) +``` + +#### Running fuzzers. + +```shell +$ mkdir -p build/fuzz_basic_seed +$ mkdir -p build/fuzz_http_controller_seed +$ mkdir -p build/fuzz_http_h1p_seed +$ mkdir -p build/fuzz_http_h1p_peer_seed +$ mkdir -p build/fuzz_json_seed + +$ ./build/fuzz_basic build/fuzz_basic_seed fuzzing/fuzz_basic_seed_corpus +$ ./build/fuzz_http_controller build/fuzz_http_controller_seed fuzzing/fuzz_http_seed_corpus +$ ./build/fuzz_http_h1p build/fuzz_http_h1p_seed fuzzing/fuzz_http_seed_corpus +$ ./build/fuzz_http_h1p_peer build/fuzz_http_h1p_peer_seed fuzzing/fuzz_http_seed_corpus +$ ./build/fuzz_json build/fuzz_json_seed fuzzing/fuzz_json_seed_corpus +``` + +Here is more information about [LibFuzzer](https://llvm.org/docs/LibFuzzer.html). + +## Build fuzzers using other fuzzing engines. + +- [Honggfuzz](https://github.com/google/honggfuzz/blob/master/docs/PersistentFuzzing.md). +- [AFLplusplus](https://github.com/AFLplusplus/AFLplusplus/blob/stable/utils/aflpp_driver/README.md). + + +## Requirements. + +You will likely need at least the following packages installed (package names +may vary). + +``` +clang, llvm & compiler-rt +``` diff --git a/fuzzing/build-fuzz.sh b/fuzzing/build-fuzz.sh new file mode 100644 index 00000000..62f7a676 --- /dev/null +++ b/fuzzing/build-fuzz.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +export CC=clang +export CXX=clang++ +export CFLAGS="-g -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address,undefined -fsanitize=fuzzer-no-link" +export CXXFLAGS="-g -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address,undefined -fsanitize=fuzzer-no-link" +export LIB_FUZZING_ENGINE="-fsanitize=fuzzer" + +./configure --no-regex --no-pcre2 --fuzz=$LIB_FUZZING_ENGINE +make fuzz -j$(nproc) + +mkdir -p build/fuzz_basic_seed +mkdir -p build/fuzz_http_controller_seed +mkdir -p build/fuzz_http_h1p_seed +mkdir -p build/fuzz_http_h1p_peer_seed +mkdir -p build/fuzz_json_seed + +echo "" +echo "Run: ./build/\${fuzzer} build/\${fuzzer}_seed fuzzing/\${fuzzer}_seed_corpus" +echo "" diff --git a/fuzzing/fuzz_basic_seed_corpus/base64_0.bin b/fuzzing/fuzz_basic_seed_corpus/base64_0.bin Binary files differnew file mode 100644 index 00000000..71501405 --- /dev/null +++ b/fuzzing/fuzz_basic_seed_corpus/base64_0.bin diff --git a/fuzzing/fuzz_basic_seed_corpus/term_0.bin b/fuzzing/fuzz_basic_seed_corpus/term_0.bin Binary files differnew file mode 100644 index 00000000..c7fff416 --- /dev/null +++ b/fuzzing/fuzz_basic_seed_corpus/term_0.bin diff --git a/fuzzing/fuzz_basic_seed_corpus/term_1.bin b/fuzzing/fuzz_basic_seed_corpus/term_1.bin Binary files differnew file mode 100644 index 00000000..bd03def0 --- /dev/null +++ b/fuzzing/fuzz_basic_seed_corpus/term_1.bin diff --git a/fuzzing/fuzz_basic_seed_corpus/utf8_0.bin b/fuzzing/fuzz_basic_seed_corpus/utf8_0.bin Binary files differnew file mode 100644 index 00000000..d395758e --- /dev/null +++ b/fuzzing/fuzz_basic_seed_corpus/utf8_0.bin diff --git a/fuzzing/fuzz_http.dict b/fuzzing/fuzz_http.dict new file mode 100644 index 00000000..0a198414 --- /dev/null +++ b/fuzzing/fuzz_http.dict @@ -0,0 +1,38 @@ +"Accept-Encoding" +"Accept-Language" +"Accept" +"Authorization" +"Cache-Control" +"Connection" +"Content-Length" +"Content-Range" +"Content-Type" +"Cookie" +"Date" +"Expect" +"Host" +"If-Match" +"If-Modified-Since" +"If-None-Match" +"If-Range" +"If-Unmodified-Since" +"Keep-Alive" +"Origin" +"Pragma" +"Range" +"Referer" +"Sec-WebSocket-Key" +"Sec-WebSocket-Version" +"Server" +"TE" +"Transfer-Encoding" +"Upgrade-Insecure-Requests" +"Upgrade" +"User-Agent" +"Via" +"X-Forwarded-For" +"X-Forwarded-Host" +"X-Forwarded-Proto" +"X-Http-Method-Override" +"X-Real-IP" +"X-Request-ID" diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_bench.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_bench.bin new file mode 100644 index 00000000..64e2f7e8 --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_bench.bin @@ -0,0 +1,16 @@ +POST /path/to/very/interesting/article/on.this.site?arg1=value&arg2=value2&very_big_arg=even_bigger_value HTTP/1.1
+Host: www.example.com
+User-Agent: Mozilla/5.0 (X11; Gentoo Linux x86_64; rv:42.0) Firefox/42.0
+Accept: text/html,application/json,application/xml;q=0.9,*/*;q=0.8
+Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4
+Accept-Encoding: gzip, deflate, br
+If-Modified-Since: Wed, 31 Dec 1986 16:00:00 GMT
+Referer: https://example.org/path/to/not-interesting/article.html
+Cookie: name=value; name2=value2; some_big_cookie=Olr+/9hoA0og/dAcHH1p8sEFAHAAAAAElFTkSuQmCC
+Connection: keep-alive
+Content-Length: 0
+Upgrade-Insecure-Requests: 1
+Pragma: no-cache
+Cache-Control: no-cache
+X-Forwarded-For: 192.0.2.0, 198.51.100.0, 203.0.113.0
+
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_0.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_0.bin new file mode 100644 index 00000000..00ff084d --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_0.bin @@ -0,0 +1,2 @@ +XXX-METHOD /d.ir/fi+le.ext?key=val HTTP/1.2 + diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_1.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_1.bin new file mode 100644 index 00000000..2f6c6149 --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_1.bin @@ -0,0 +1,2 @@ +GEt / HTTP/1.0
+
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_10.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_10.bin new file mode 100644 index 00000000..03337016 --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_10.bin @@ -0,0 +1,2 @@ +GET /na %20me.ext?args HTTP/1.0
+
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_11.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_11.bin new file mode 100644 index 00000000..bac5bc27 --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_11.bin @@ -0,0 +1,2 @@ +GET / HTTP/1.0 HTTP/1.1
+
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_12.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_12.bin new file mode 100644 index 00000000..75bd72e2 --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_12.bin @@ -0,0 +1,3 @@ +GET / HTTP/1.1
+Host:example.com
+
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_13.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_13.bin new file mode 100644 index 00000000..2216ec8d --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_13.bin @@ -0,0 +1,3 @@ +GET / HTTP/1.1
+Host:
+
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_14.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_14.bin new file mode 100644 index 00000000..12435096 --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_14.bin @@ -0,0 +1,3 @@ +GET / HTTP/1.1
+:Host: example.com
+
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_15.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_15.bin new file mode 100644 index 00000000..88bb36f4 --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_15.bin @@ -0,0 +1,3 @@ +GET / HTTP/1.1
+Ho_st: example.com
+
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_16.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_16.bin new file mode 100644 index 00000000..ce7453c2 --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_16.bin @@ -0,0 +1,4 @@ +GET / HTTP/1.1
+Ho +st: example.com
+
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_17.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_17.bin new file mode 100644 index 00000000..5016e0df --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_17.bin @@ -0,0 +1,3 @@ +GET / HTTP/1.1
+Host: exa
mple.com
+
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_18.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_18.bin new file mode 100644 index 00000000..d2409a88 --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_18.bin @@ -0,0 +1,3 @@ +GET / HTTP/1.1
+Host: example.com
+
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_19.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_19.bin new file mode 100644 index 00000000..40e39921 --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_19.bin @@ -0,0 +1,3 @@ +GET / HTTP/1.1
+!#$%&'*+.^_`|~: allowed
+
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_2.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_2.bin new file mode 100644 index 00000000..cfc0d81a --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_2.bin @@ -0,0 +1,3 @@ +GET / + HTTP/1.0
+
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_20.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_20.bin new file mode 100644 index 00000000..b1deb571 --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_20.bin @@ -0,0 +1,3 @@ +GET / HTTP/1.1
+Host: xn--e1afmkfd.xn--80akhbyknj4f
+
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_21.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_21.bin new file mode 100644 index 00000000..89565fd8 --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_21.bin @@ -0,0 +1,4 @@ +GET / HTTP/1.1
+Host: exa +mple.com
+
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_22.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_22.bin new file mode 100644 index 00000000..3e0f8f6a --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_22.bin @@ -0,0 +1,3 @@ +GET / HTTP/1.1
+Host: exa mple.com
+
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_23.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_23.bin new file mode 100644 index 00000000..da0661e5 --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_23.bin @@ -0,0 +1,5 @@ +GET / HTTP/1.1
+X-Unknown-Header: value
+X-Good-Header: value
+!#$%&'*+.^_`|~: skipped
+
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_24.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_24.bin new file mode 100644 index 00000000..6b5232e3 --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_24.bin @@ -0,0 +1,5 @@ +GET / HTTP/1.1
+X-Good-Header: value
+X-Unknown-Header: value
+X-Bad-Header: value
+
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_3.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_3.bin new file mode 100644 index 00000000..20afdfb4 --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_3.bin @@ -0,0 +1 @@ +GET / HTTP/1.0
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_4.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_4.bin new file mode 100644 index 00000000..22b52346 --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_4.bin @@ -0,0 +1 @@ +GET / HTTP/2.0
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_5.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_5.bin new file mode 100644 index 00000000..2da59689 --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_5.bin @@ -0,0 +1,2 @@ +GET /. HTTP/1.0
+
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_6.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_6.bin new file mode 100644 index 00000000..9cf4c094 --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_6.bin @@ -0,0 +1,2 @@ +GET /# HTTP/1.0
+
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_7.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_7.bin new file mode 100644 index 00000000..d02576e0 --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_7.bin @@ -0,0 +1,2 @@ +GET /?# HTTP/1.0
+
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_8.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_8.bin new file mode 100644 index 00000000..fa246dc4 --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_8.bin @@ -0,0 +1,2 @@ +GET // HTTP/1.0
+
diff --git a/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_9.bin b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_9.bin new file mode 100644 index 00000000..2668f283 --- /dev/null +++ b/fuzzing/fuzz_http_seed_corpus/nxt_http_test_run_9.bin @@ -0,0 +1,2 @@ +GET /%20 HTTP/1.0
+
diff --git a/fuzzing/fuzz_json_seed_corpus/json_0.bin b/fuzzing/fuzz_json_seed_corpus/json_0.bin new file mode 100644 index 00000000..450e2283 --- /dev/null +++ b/fuzzing/fuzz_json_seed_corpus/json_0.bin @@ -0,0 +1 @@ +[{"container": 1000, "host": 0, "size": 1},{"container": 10000, "host": 10000, "size": 1}, {"container": 60000, "host": 60000, "size": 1}]
\ No newline at end of file diff --git a/fuzzing/fuzz_json_seed_corpus/json_1.bin b/fuzzing/fuzz_json_seed_corpus/json_1.bin new file mode 100644 index 00000000..0637a088 --- /dev/null +++ b/fuzzing/fuzz_json_seed_corpus/json_1.bin @@ -0,0 +1 @@ +[]
\ No newline at end of file diff --git a/fuzzing/fuzz_json_seed_corpus/json_2.bin b/fuzzing/fuzz_json_seed_corpus/json_2.bin new file mode 100644 index 00000000..5c1201b8 --- /dev/null +++ b/fuzzing/fuzz_json_seed_corpus/json_2.bin @@ -0,0 +1 @@ +[{"container": 0, "host": 0, "size": 1}]
\ No newline at end of file diff --git a/fuzzing/fuzz_json_seed_corpus/json_3.bin b/fuzzing/fuzz_json_seed_corpus/json_3.bin new file mode 100644 index 00000000..e040c9b7 --- /dev/null +++ b/fuzzing/fuzz_json_seed_corpus/json_3.bin @@ -0,0 +1 @@ +[{"container": 1000, "host": 0, "size": 1}]
\ No newline at end of file diff --git a/fuzzing/fuzz_json_seed_corpus/json_4.bin b/fuzzing/fuzz_json_seed_corpus/json_4.bin new file mode 100644 index 00000000..30a2bc50 --- /dev/null +++ b/fuzzing/fuzz_json_seed_corpus/json_4.bin @@ -0,0 +1 @@ +[{"container": 0, "host": 1000, "size": 1}, {"container": 1000, "host": 2000, "size": 1}]
\ No newline at end of file diff --git a/fuzzing/nxt_basic_fuzz.c b/fuzzing/nxt_basic_fuzz.c new file mode 100644 index 00000000..5f71a909 --- /dev/null +++ b/fuzzing/nxt_basic_fuzz.c @@ -0,0 +1,236 @@ +/* + * Copyright (C) NGINX, Inc. + */ + +#include <nxt_main.h> +#include <nxt_sha1.h> +#include <nxt_websocket.h> +#include <nxt_websocket_header.h> + +/* DO NOT TRY THIS AT HOME! */ +#include <nxt_websocket_accept.c> + + +#define KMININPUTLENGTH 4 +#define KMAXINPUTLENGTH 128 + + +extern int LLVMFuzzerInitialize(int *argc, char ***argv); +extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); + +void nxt_base64_fuzz(const u_char *data, size_t size); +void nxt_djb_hash_fuzz(const u_char *data, size_t size); +void nxt_murmur_hash2_fuzz(const u_char *data, size_t size); +void nxt_parse_fuzz(const u_char *data, size_t size); +void nxt_sha1_fuzz(const u_char *data, size_t size); +void nxt_sha1_update_fuzz(const u_char *data, size_t size); +void nxt_term_fuzz(const u_char *data, size_t size); +void nxt_time_fuzz(const u_char *data, size_t size); +void nxt_uri_fuzz(const u_char *data, size_t size); +void nxt_utf8_fuzz(const u_char *data, size_t size); +void nxt_websocket_base64_fuzz(const u_char *data, size_t size); +void nxt_websocket_frame_fuzz(const u_char *data, size_t size); + + +extern char **environ; + + +int +LLVMFuzzerInitialize(int *argc, char ***argv) +{ + if (nxt_lib_start("fuzzing", NULL, &environ) != NXT_OK) { + return NXT_ERROR; + } + + return 0; +} + + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (size < KMININPUTLENGTH || size > KMAXINPUTLENGTH) { + return 0; + } + + nxt_base64_fuzz(data, size); + nxt_djb_hash_fuzz(data, size); + nxt_murmur_hash2_fuzz(data, size); + nxt_parse_fuzz(data, size); + nxt_sha1_fuzz(data, size); + nxt_sha1_update_fuzz(data, size); + nxt_term_fuzz(data, size); + nxt_time_fuzz(data, size); + nxt_uri_fuzz(data, size); + nxt_utf8_fuzz(data, size); + nxt_websocket_base64_fuzz(data, size); + nxt_websocket_frame_fuzz(data, size); + + return 0; +} + + +void +nxt_base64_fuzz(const u_char *data, size_t size) +{ + u_char buf[256]; + ssize_t ret; + + /* + * Validate base64 data before decoding. + */ + ret = nxt_base64_decode(NULL, (u_char *)data, size); + if (ret == NXT_ERROR) { + return; + } + + nxt_base64_decode(buf, (u_char *)data, size); +} + + +void +nxt_djb_hash_fuzz(const u_char *data, size_t size) +{ + nxt_djb_hash(data, size); + nxt_djb_hash_lowcase(data, size); +} + + +void +nxt_murmur_hash2_fuzz(const u_char *data, size_t size) +{ + nxt_murmur_hash2(data, size); + nxt_murmur_hash2_uint32(data); +} + + +void +nxt_parse_fuzz(const u_char *data, size_t size) +{ + nxt_str_t input; + + input.start = (u_char *)data; + input.length = size; + + nxt_int_parse(data, size); + nxt_size_t_parse(data, size); + nxt_size_parse(data, size); + nxt_off_t_parse(data, size); + nxt_str_int_parse(&input); + nxt_number_parse(&data, data + size); +} + + +void +nxt_sha1_fuzz(const u_char *data, size_t size) +{ + u_char bin_accept[20]; + nxt_sha1_t ctx; + + nxt_sha1_init(&ctx); + nxt_sha1_update(&ctx, data, size); + nxt_sha1_final(bin_accept, &ctx); +} + + +void +nxt_sha1_update_fuzz(const u_char *data, size_t size) +{ + u_char bin_accept[20]; + nxt_sha1_t ctx; + + nxt_sha1_init(&ctx); + nxt_sha1_update(&ctx, data, size); + nxt_sha1_update(&ctx, data, size); + nxt_sha1_final(bin_accept, &ctx); +} + + +void +nxt_term_fuzz(const u_char *data, size_t size) +{ + nxt_term_parse(data, size, 0); + nxt_term_parse(data, size, 1); +} + + +void +nxt_time_fuzz(const u_char *data, size_t size) +{ + nxt_time_parse(data, size); +} + + +void +nxt_uri_fuzz(const u_char *data, size_t size) +{ + u_char *dst; + + dst = nxt_zalloc(size * 3); + if (dst == NULL) { + return; + } + + nxt_decode_uri(dst, (u_char *)data, size); + nxt_decode_uri_plus(dst, (u_char *)data, size); + + nxt_memzero(dst, size * 3); + nxt_encode_uri(NULL, (u_char *)data, size); + nxt_encode_uri(dst, (u_char *)data, size); + + nxt_free(dst); +} + + +void +nxt_utf8_fuzz(const u_char *data, size_t size) +{ + const u_char *in; + + in = data; + nxt_utf8_decode(&in, data + size); + + nxt_utf8_casecmp((const u_char *)"ABC АБВ ΑΒΓ", + data, + nxt_length("ABC АБВ ΑΒΓ"), + size); +} + + +void +nxt_websocket_base64_fuzz(const u_char *data, size_t size) +{ + u_char *out; + + out = nxt_zalloc(size * 2); + if (out == NULL) { + return; + } + + nxt_websocket_base64_encode(out, data, size); + + nxt_free(out); +} + + +void +nxt_websocket_frame_fuzz(const u_char *data, size_t size) +{ + u_char *input; + + /* + * Resolve overwrites-const-input by using a copy of the data. + */ + input = nxt_malloc(size); + if (input == NULL) { + return; + } + + nxt_memcpy(input, data, size); + + nxt_websocket_frame_init(input, 0); + nxt_websocket_frame_header_size(input); + nxt_websocket_frame_payload_len(input); + + nxt_free(input); +} diff --git a/fuzzing/nxt_http_controller_fuzz.c b/fuzzing/nxt_http_controller_fuzz.c new file mode 100644 index 00000000..25527ae1 --- /dev/null +++ b/fuzzing/nxt_http_controller_fuzz.c @@ -0,0 +1,98 @@ +/* + * Copyright (C) NGINX, Inc. + */ + +#include <nxt_main.h> + +/* DO NOT TRY THIS AT HOME! */ +#include "nxt_controller.c" + + +#define KMININPUTLENGTH 2 +#define KMAXINPUTLENGTH 1024 + + +extern int LLVMFuzzerInitialize(int *argc, char ***argv); +extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); + + +extern char **environ; + + +int +LLVMFuzzerInitialize(int *argc, char ***argv) +{ + nxt_int_t ret; + + if (nxt_lib_start("fuzzing", NULL, &environ) != NXT_OK) { + return NXT_ERROR; + } + + ret = nxt_http_fields_hash(&nxt_controller_fields_hash, + nxt_controller_request_fields, + nxt_nitems(nxt_controller_request_fields)); + if (ret != NXT_OK) { + return NXT_ERROR; + } + + return 0; +} + + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + nxt_mp_t *mp; + nxt_int_t rc; + nxt_buf_mem_t buf; + nxt_controller_request_t *req; + nxt_http_request_parse_t rp; + + if (size < KMININPUTLENGTH || size > KMAXINPUTLENGTH) { + return 0; + } + + mp = nxt_mp_create(1024, 128, 256, 32); + if (mp == NULL) { + return 0; + } + + req = nxt_mp_zget(mp, sizeof(nxt_controller_request_t)); + if (req == NULL) { + goto failed; + } + + req->conn = nxt_mp_zget(mp, sizeof(nxt_conn_t)); + if (req->conn == NULL) { + goto failed; + } + + buf.start = (u_char *)data; + buf.end = (u_char *)data + size; + buf.pos = buf.start; + buf.free = buf.end; + + nxt_main_log.level = NXT_LOG_ALERT; + req->conn->log = nxt_main_log; + + nxt_memzero(&rp, sizeof(nxt_http_request_parse_t)); + + rc = nxt_http_parse_request_init(&rp, mp); + if (rc != NXT_OK) { + goto failed; + } + + rc = nxt_http_parse_request(&rp, &buf); + if (rc != NXT_DONE) { + goto failed; + } + + nxt_http_fields_process(rp.fields, &nxt_controller_fields_hash, + req); + +failed: + + nxt_mp_destroy(mp); + + return 0; +} diff --git a/fuzzing/nxt_http_h1p_fuzz.c b/fuzzing/nxt_http_h1p_fuzz.c new file mode 100644 index 00000000..b8893ad6 --- /dev/null +++ b/fuzzing/nxt_http_h1p_fuzz.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) NGINX, Inc. + */ + +#include <nxt_main.h> + +/* DO NOT TRY THIS AT HOME! */ +#include "nxt_h1proto.c" + + +#define KMININPUTLENGTH 2 +#define KMAXINPUTLENGTH 1024 + + +extern int LLVMFuzzerInitialize(int *argc, char ***argv); +extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); + + +extern char **environ; + + +int +LLVMFuzzerInitialize(int *argc, char ***argv) +{ + nxt_int_t ret; + + if (nxt_lib_start("fuzzing", NULL, &environ) != NXT_OK) { + return NXT_ERROR; + } + + ret = nxt_http_fields_hash(&nxt_h1p_fields_hash, + nxt_h1p_fields, nxt_nitems(nxt_h1p_fields)); + if (ret != NXT_OK) { + return NXT_ERROR; + } + + return 0; +} + + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + nxt_mp_t *mp; + nxt_int_t rc; + nxt_buf_mem_t buf; + nxt_http_request_t *req; + nxt_http_request_parse_t rp; + + if (size < KMININPUTLENGTH || size > KMAXINPUTLENGTH) { + return 0; + } + + mp = nxt_mp_create(1024, 128, 256, 32); + if (mp == NULL) { + return 0; + } + + req = nxt_mp_zget(mp, sizeof(nxt_http_request_t)); + if (req == NULL) { + goto failed; + } + + req->proto.h1 = nxt_mp_zget(mp, sizeof(nxt_h1proto_t)); + if (req->proto.h1 == NULL) { + goto failed; + } + + req->conf = nxt_mp_zget(mp, sizeof(nxt_socket_conf_joint_t)); + if (req->conf == NULL) { + goto failed; + } + + req->conf->socket_conf = nxt_mp_zget(mp, sizeof(nxt_socket_conf_t)); + if (req->conf->socket_conf == NULL) { + goto failed; + } + + buf.start = (u_char *)data; + buf.end = (u_char *)data + size; + buf.pos = buf.start; + buf.free = buf.end; + + req->mem_pool = mp; + req->conf->socket_conf->max_body_size = 8 * 1024 * 1024; + + nxt_memzero(&rp, sizeof(nxt_http_request_parse_t)); + + rc = nxt_http_parse_request_init(&rp, mp); + if (rc != NXT_OK) { + goto failed; + } + + rc = nxt_http_parse_request(&rp, &buf); + if (rc != NXT_DONE) { + goto failed; + } + + nxt_http_fields_process(rp.fields, &nxt_h1p_fields_hash, req); + +failed: + + nxt_mp_destroy(mp); + + return 0; +} diff --git a/fuzzing/nxt_http_h1p_peer_fuzz.c b/fuzzing/nxt_http_h1p_peer_fuzz.c new file mode 100644 index 00000000..43786d0c --- /dev/null +++ b/fuzzing/nxt_http_h1p_peer_fuzz.c @@ -0,0 +1,99 @@ +/* + * Copyright (C) NGINX, Inc. + */ + +#include <nxt_main.h> + +/* DO NOT TRY THIS AT HOME! */ +#include "nxt_h1proto.c" + + +#define KMININPUTLENGTH 2 +#define KMAXINPUTLENGTH 1024 + + +extern int LLVMFuzzerInitialize(int *argc, char ***argv); +extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); + + +extern char **environ; + + +int +LLVMFuzzerInitialize(int *argc, char ***argv) +{ + nxt_int_t ret; + + if (nxt_lib_start("fuzzing", NULL, &environ) != NXT_OK) { + return NXT_ERROR; + } + + ret = nxt_http_fields_hash(&nxt_h1p_peer_fields_hash, + nxt_h1p_peer_fields, + nxt_nitems(nxt_h1p_peer_fields)); + if (ret != NXT_OK) { + return NXT_ERROR; + } + + return 0; +} + + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + nxt_mp_t *mp; + nxt_int_t rc; + nxt_buf_mem_t buf; + nxt_http_request_t *req; + nxt_http_request_parse_t rp; + + if (size < KMININPUTLENGTH || size > KMAXINPUTLENGTH) { + return 0; + } + + mp = nxt_mp_create(1024, 128, 256, 32); + if (mp == NULL) { + return 0; + } + + req = nxt_mp_zget(mp, sizeof(nxt_http_request_t)); + if (req == NULL) { + goto failed; + } + + req->peer = nxt_mp_zalloc(mp, sizeof(nxt_http_peer_t)); + if (req->peer == NULL) { + goto failed; + } + + req->peer->proto.h1 = nxt_mp_zalloc(mp, sizeof(nxt_h1proto_t)); + if (req->peer->proto.h1 == NULL) { + goto failed; + } + + buf.start = (u_char *)data; + buf.end = (u_char *)data + size; + buf.pos = buf.start; + buf.free = buf.end; + + nxt_memzero(&rp, sizeof(nxt_http_request_parse_t)); + + rc = nxt_http_parse_request_init(&rp, mp); + if (rc != NXT_OK) { + goto failed; + } + + rc = nxt_http_parse_request(&rp, &buf); + if (rc != NXT_DONE) { + goto failed; + } + + nxt_http_fields_process(rp.fields, &nxt_h1p_peer_fields_hash, req); + +failed: + + nxt_mp_destroy(mp); + + return 0; +} diff --git a/fuzzing/nxt_json_fuzz.c b/fuzzing/nxt_json_fuzz.c new file mode 100644 index 00000000..fa222988 --- /dev/null +++ b/fuzzing/nxt_json_fuzz.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) NGINX, Inc. + */ + +#include <nxt_main.h> +#include <nxt_conf.h> +#include <nxt_router.h> + +#define KMININPUTLENGTH 2 +#define KMAXINPUTLENGTH 1024 + + +extern int LLVMFuzzerInitialize(int *argc, char ***argv); +extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); + + +extern char **environ; + + +int +LLVMFuzzerInitialize(int *argc, char ***argv) +{ + if (nxt_lib_start("fuzzing", NULL, &environ) != NXT_OK) { + return NXT_ERROR; + } + + return 0; +} + + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + nxt_mp_t *mp; + nxt_str_t input; + nxt_thread_t *thr; + nxt_runtime_t *rt; + nxt_conf_value_t *conf; + nxt_conf_validation_t vldt; + nxt_conf_json_pretty_t pretty; + + if (size < KMININPUTLENGTH || size > KMAXINPUTLENGTH) { + return 0; + } + + thr = nxt_thread(); + + mp = nxt_mp_create(1024, 128, 256, 32); + if (mp == NULL) { + return 0; + } + + rt = nxt_mp_zget(mp, sizeof(nxt_runtime_t)); + if (rt == NULL) { + goto failed; + } + + rt->languages = nxt_array_create(mp, 1, sizeof(nxt_app_lang_module_t)); + if (rt->languages == NULL) { + goto failed; + } + + input.start = (u_char *)data; + input.length = size; + + thr->runtime = rt; + rt->mem_pool = mp; + + nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t)); + nxt_memzero(&vldt, sizeof(nxt_conf_validation_t)); + + conf = nxt_conf_json_parse_str(mp, &input); + if (conf == NULL) { + goto failed; + } + + nxt_conf_json_length(conf, NULL); + nxt_conf_json_length(conf, &pretty); + + vldt.pool = nxt_mp_create(1024, 128, 256, 32); + if (vldt.pool == NULL) { + goto failed; + } + + vldt.conf = conf; + vldt.conf_pool = mp; + vldt.ver = NXT_VERNUM; + + nxt_conf_validate(&vldt); + nxt_mp_destroy(vldt.pool); + +failed: + + nxt_mp_destroy(mp); + + return 0; +} diff --git a/fuzzing/oss-fuzz.sh b/fuzzing/oss-fuzz.sh new file mode 100644 index 00000000..1fe5ecda --- /dev/null +++ b/fuzzing/oss-fuzz.sh @@ -0,0 +1,29 @@ +#!/bin/bash -eu + +# Build unit +./configure --no-regex --no-pcre2 --fuzz="$LIB_FUZZING_ENGINE" +make fuzz -j"$(nproc)" + +# Copy all fuzzers. +cp build/fuzz_* $OUT/ + +# cd into fuzzing dir +pushd fuzzing/ +cp fuzz_http.dict $OUT/fuzz_http_controller.dict +cp fuzz_http.dict $OUT/fuzz_http_h1p.dict +cp fuzz_http.dict $OUT/fuzz_http_h1p_peer.dict + +# Create temporary directories. +cp -r fuzz_http_seed_corpus/ fuzz_http_controller_seed_corpus/ +cp -r fuzz_http_seed_corpus/ fuzz_http_h1p_seed_corpus/ +cp -r fuzz_http_seed_corpus/ fuzz_http_h1p_peer_seed_corpus/ + +zip -r $OUT/fuzz_basic_seed_corpus.zip fuzz_basic_seed_corpus/ +zip -r $OUT/fuzz_http_controller_seed_corpus.zip fuzz_http_controller_seed_corpus/ +zip -r $OUT/fuzz_http_h1p_seed_corpus.zip fuzz_http_h1p_seed_corpus/ +zip -r $OUT/fuzz_http_h1p_peer_seed_corpus.zip fuzz_http_h1p_peer_seed_corpus/ +zip -r $OUT/fuzz_json_seed_corpus.zip fuzz_json_seed_corpus/ + +# Delete temporary directories. +rm -r fuzz_http_controller_seed_corpus/ fuzz_http_h1p_seed_corpus/ fuzz_http_h1p_peer_seed_corpus/ +popd |
