OSS-Fuzz coverage improvment
I submitted a PR a few weeks ago that significantly improves the fuzzing coverage of your project, with a focus on parsers. While it occasionally uses internal APIs due to the unconventional nature of this type of testing, I am reasonably confident in its stability as I ran the fuzz targets for an extended period at home and took the time to read the related source code.
Would you be able to review it when you have some time? You can find it here: https://github.com/google/oss-fuzz/pull/12852
Thanks... while it's very welcome, I am not sure what to do with this or how to test it, from lws perspective (eg, ./Dockerfile is not something in upstream lws).
The .cpp files (fuzz harnesses) act as glue between you code and the fuzzing engine. They are not OSS-Fuzz specific as they are designed for LibFuzzer and are compatible with most fuzzing engines. Similarly, seed and dictionary files, used by fuzzing engines to generate test cases, are also independent from OSS-fuzz. This is why OSS-Fuzz maintainers recommend keeping those files in the project's upstream repository. I assume they prefer to keep only OSS-Fuzz code and OSS-Fuzz specific project integration (the Dockerfile and build.sh script) on their side.
You can test the fuzz targets locally by building them using the OSS-Fuzz Docker image:
$ cd /path/to/oss-fuzz
$ python infra/helper.py build_image libwebsockets
$ python infra/helper.py build_fuzzers --sanitizer address libwebsockets
Where /path/to/oss-fuzz is the cloned OSS-fuzz repository (sanitizers "memory" and "undefined" are also available but won't work with your project as is). Then they can be launched with:
$ python infra/helper.py run_fuzzer libwebsockets <fuzz_target>
Available fuzz targets are:
- lws_upng_fuzzer (pre-existing)
- lws_lhs_fuzzer
- lws_parse_fuzzer
- lws_parse_uri_fuzzer
The last three are added in the PR.
The output will include periodic statistics and status updates displayed on stdout. If the fuzzer detects a crash or hang, the input that triggered it will be saved at /path/to/oss-fuzz/build/out/libwebsockets/. For details, you can refer to the OSS-Fuzz documentation.
Alternatively you can build and run the fuzz targets outside of OSS-fuzz, see LibFuzzer documentation, for example. However if you do this there is no guarantee it will work properly within OSS-Fuzz.
I hope this clears things up, let me know if not.
Thanks for the info. I spent some time trying to build libwebsockets inside this and fuzz it using the flow given here, but it blew chunks when trying to launch the fuzzer
$ python infra/helper.py run_fuzzer libwebsockets lws_upng_fuzzer
Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
ERROR:__main__:lws_upng_fuzzer does not seem to exist. Please run build_fuzzers first.
I found some warnings during the build inside oss-fuzz, and pushed two patches on main that should clear them on the assumption that's blocking the fuzzer build. But I was unable to get the build to bring in the changes, I assume it is pinned somewhere to some earlier commit.
https://github.com/warmcat/libwebsockets/commit/8210ccba08072a58c750c8f85160c8825f4708f7 https://github.com/warmcat/libwebsockets/commit/e0c312c20248b2c7f509216e3b3463dc372fc114
The build is not failing. You're having issues because I typed the name of the pre-existing fuzzer wrong... It's lws_upng_inflate_fuzzer, not lws_upng_fuzzer. Sorry about this.
No commit is pinned - from the Dockerfile:
RUN git clone --depth 1 https://github.com/warmcat/libwebsockets.git
https://github.com/warmcat/libwebsockets/commit/8210ccba08072a58c750c8f85160c8825f4708f7 appears to be empty.
https://github.com/warmcat/libwebsockets/commit/e0c312c20248b2c7f509216e3b3463dc372fc114 is taking effects on my side. There is a only warning left while there was multiple ones previously.
/src/libwebsockets//lib/secure-streams/private-lib-secure-streams.h:214:1: warning: empty union has size 0 in C, size 1 in C++ [-Wextern-c-compat]
214 | union lws_ss_contemp {
|
But that's not stopping the build anyway.
Hi Andy, Is there still an issue with this ? We don't have to move anything to the LWS repo for the additions to take effect if you don't have time for this.. Once you approve it will be merged into OSS-fuzz repository. They don't favor that option but they allow it.
This still doesn't seem to work for me.
I can run the first two steps seemingly OK, including build_fuzzers, which ends like this
...
[100%] Built target test-server-extpoll
[100%] Built target test-server
[100%] Built target test-client
+ cd /src/libwebsockets/
+ INCLUDE_DIRS='-I/src/libwebsockets//build/include -I/src/libwebsockets//build -I/src/libwebsockets//lib/core/ -I/src/libwebsockets//lib/plat/unix -I/src/libwebsockets//lib/tls/ -I/src/libwebsockets//lib/secure-streams/ -I/src/libwebsockets//lib/event-libs/ -I/src/libwebsockets//lib/system/smd -I/src/libwebsockets//lib/system/metrics/ -I/src/libwebsockets//lib/core-net -I/src/libwebsockets//lib/roles -I/src/libwebsockets//lib/roles/http -I/src/libwebsockets//lib/roles/h1 -I/src/libwebsockets//lib/roles/h2 -I/src/libwebsockets//lib/roles/ws'
+ FUZZER_SRCS=("lws_lhs_fuzzer.cpp" "lws_upng_inflate_fuzzer.cpp" "lws_parse_uri_fuzzer.cpp" "lws_parse_fuzzer.cpp")
+ for FUZZER in "${FUZZER_SRCS[@]}"
++ basename lws_lhs_fuzzer.cpp .cpp
+ FUZZER_NAME=lws_lhs_fuzzer
+ clang++ -O1 -fno-omit-frame-pointer -gline-tables-only -Wno-error=enum-constexpr-conversion -Wno-error=incompatible-function-pointer-types -Wno-error=int-conversion -Wno-error=deprecated-declarations -Wno-error=implicit-function-declaration -Wno-error=implicit-int -Wno-error=vla-cxx-extension -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address -fsanitize-address-use-after-scope -fsanitize=fuzzer-no-link -fsanitize=fuzzer -I/src/libwebsockets//build/include -I/src/libwebsockets//build -I/src/libwebsockets//lib/core/ -I/src/libwebsockets//lib/plat/unix -I/src/libwebsockets//lib/tls/ -I/src/libwebsockets//lib/secure-streams/ -I/src/libwebsockets//lib/event-libs/ -I/src/libwebsockets//lib/system/smd -I/src/libwebsockets//lib/system/metrics/ -I/src/libwebsockets//lib/core-net -I/src/libwebsockets//lib/roles -I/src/libwebsockets//lib/roles/http -I/src/libwebsockets//lib/roles/h1 -I/src/libwebsockets//lib/roles/h2 -I/src/libwebsockets//lib/roles/ws -o /out/lws_lhs_fuzzer lws_lhs_fuzzer.cpp -L/src/libwebsockets//build/lib -l:libwebsockets.a -L/usr/lib/x86_64-linux-gnu/ -l:libssl.so -l:libcrypto.so
+ for FUZZER in "${FUZZER_SRCS[@]}"
++ basename lws_upng_inflate_fuzzer.cpp .cpp
+ FUZZER_NAME=lws_upng_inflate_fuzzer
+ clang++ -O1 -fno-omit-frame-pointer -gline-tables-only -Wno-error=enum-constexpr-conversion -Wno-error=incompatible-function-pointer-types -Wno-error=int-conversion -Wno-error=deprecated-declarations -Wno-error=implicit-function-declaration -Wno-error=implicit-int -Wno-error=vla-cxx-extension -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address -fsanitize-address-use-after-scope -fsanitize=fuzzer-no-link -fsanitize=fuzzer -I/src/libwebsockets//build/include -I/src/libwebsockets//build -I/src/libwebsockets//lib/core/ -I/src/libwebsockets//lib/plat/unix -I/src/libwebsockets//lib/tls/ -I/src/libwebsockets//lib/secure-streams/ -I/src/libwebsockets//lib/event-libs/ -I/src/libwebsockets//lib/system/smd -I/src/libwebsockets//lib/system/metrics/ -I/src/libwebsockets//lib/core-net -I/src/libwebsockets//lib/roles -I/src/libwebsockets//lib/roles/http -I/src/libwebsockets//lib/roles/h1 -I/src/libwebsockets//lib/roles/h2 -I/src/libwebsockets//lib/roles/ws -o /out/lws_upng_inflate_fuzzer lws_upng_inflate_fuzzer.cpp -L/src/libwebsockets//build/lib -l:libwebsockets.a -L/usr/lib/x86_64-linux-gnu/ -l:libssl.so -l:libcrypto.so
+ for FUZZER in "${FUZZER_SRCS[@]}"
++ basename lws_parse_uri_fuzzer.cpp .cpp
+ FUZZER_NAME=lws_parse_uri_fuzzer
+ clang++ -O1 -fno-omit-frame-pointer -gline-tables-only -Wno-error=enum-constexpr-conversion -Wno-error=incompatible-function-pointer-types -Wno-error=int-conversion -Wno-error=deprecated-declarations -Wno-error=implicit-function-declaration -Wno-error=implicit-int -Wno-error=vla-cxx-extension -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address -fsanitize-address-use-after-scope -fsanitize=fuzzer-no-link -fsanitize=fuzzer -I/src/libwebsockets//build/include -I/src/libwebsockets//build -I/src/libwebsockets//lib/core/ -I/src/libwebsockets//lib/plat/unix -I/src/libwebsockets//lib/tls/ -I/src/libwebsockets//lib/secure-streams/ -I/src/libwebsockets//lib/event-libs/ -I/src/libwebsockets//lib/system/smd -I/src/libwebsockets//lib/system/metrics/ -I/src/libwebsockets//lib/core-net -I/src/libwebsockets//lib/roles -I/src/libwebsockets//lib/roles/http -I/src/libwebsockets//lib/roles/h1 -I/src/libwebsockets//lib/roles/h2 -I/src/libwebsockets//lib/roles/ws -o /out/lws_parse_uri_fuzzer lws_parse_uri_fuzzer.cpp -L/src/libwebsockets//build/lib -l:libwebsockets.a -L/usr/lib/x86_64-linux-gnu/ -l:libssl.so -l:libcrypto.so
+ for FUZZER in "${FUZZER_SRCS[@]}"
++ basename lws_parse_fuzzer.cpp .cpp
+ FUZZER_NAME=lws_parse_fuzzer
+ clang++ -O1 -fno-omit-frame-pointer -gline-tables-only -Wno-error=enum-constexpr-conversion -Wno-error=incompatible-function-pointer-types -Wno-error=int-conversion -Wno-error=deprecated-declarations -Wno-error=implicit-function-declaration -Wno-error=implicit-int -Wno-error=vla-cxx-extension -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address -fsanitize-address-use-after-scope -fsanitize=fuzzer-no-link -fsanitize=fuzzer -I/src/libwebsockets//build/include -I/src/libwebsockets//build -I/src/libwebsockets//lib/core/ -I/src/libwebsockets//lib/plat/unix -I/src/libwebsockets//lib/tls/ -I/src/libwebsockets//lib/secure-streams/ -I/src/libwebsockets//lib/event-libs/ -I/src/libwebsockets//lib/system/smd -I/src/libwebsockets//lib/system/metrics/ -I/src/libwebsockets//lib/core-net -I/src/libwebsockets//lib/roles -I/src/libwebsockets//lib/roles/http -I/src/libwebsockets//lib/roles/h1 -I/src/libwebsockets//lib/roles/h2 -I/src/libwebsockets//lib/roles/ws -o /out/lws_parse_fuzzer lws_parse_fuzzer.cpp -L/src/libwebsockets//build/lib -l:libwebsockets.a -L/usr/lib/x86_64-linux-gnu/ -l:libssl.so -l:libcrypto.so
However trying to use the fuzzers dies immediately (with the correct fuzzer names vs what was built)
$ python infra/helper.py run_fuzzer libwebsockets lws_upng_inflate_fuzzer
Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
ERROR:__main__:lws_upng_inflate_fuzzer does not seem to exist. Please run build_fuzzers first.
$ python infra/helper.py run_fuzzer libwebsockets lws_lhs_fuzzer
Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
ERROR:__main__:lws_lhs_fuzzer does not seem to exist. Please run build_fuzzers first.
Eg the upng fuzzer exists at ./build/out/libwebsockets/lws_upng_inflate_fuzzer (it's 8MB)