Meta: Hoist the Fuzzers directory up one level

This commit is contained in:
Timothy Flynn 2026-06-12 12:39:10 -04:00 committed by Tim Flynn
parent 8c800d86c5
commit b9ae2e472e
31 changed files with 139 additions and 139 deletions

View file

@ -126,7 +126,7 @@ add_subdirectory(AK)
add_subdirectory(Libraries) add_subdirectory(Libraries)
if (ENABLE_FUZZERS) if (ENABLE_FUZZERS)
add_subdirectory(Meta/Lagom/Fuzzers) add_subdirectory(Meta/Fuzzers)
endif() endif()
# No utilities or tests in these configs # No utilities or tests in these configs

View file

@ -20,9 +20,9 @@ There are some optional features that can be enabled during compilation that are
- `ENABLE_UNDEFINED_SANITIZER`: builds in runtime checks for [undefined behavior](https://en.wikipedia.org/wiki/Undefined_behavior) (like null pointer dereferences and signed integer overflows) in Lagom and Ladybird. - `ENABLE_UNDEFINED_SANITIZER`: builds in runtime checks for [undefined behavior](https://en.wikipedia.org/wiki/Undefined_behavior) (like null pointer dereferences and signed integer overflows) in Lagom and Ladybird.
- `UNDEFINED_BEHAVIOR_IS_FATAL`: makes all undefined behavior sanitizer errors non-recoverable. This option reduces the performance overhead of `ENABLE_UNDEFINED_SANITIZER`. - `UNDEFINED_BEHAVIOR_IS_FATAL`: makes all undefined behavior sanitizer errors non-recoverable. This option reduces the performance overhead of `ENABLE_UNDEFINED_SANITIZER`.
- `ENABLE_COMPILER_EXPLORER_BUILD`: Skip building non-library entities in Lagom (this only applies to Lagom). - `ENABLE_COMPILER_EXPLORER_BUILD`: Skip building non-library entities in Lagom (this only applies to Lagom).
- `ENABLE_FUZZERS`: builds [fuzzers](../Meta/Lagom/ReadMe.md#fuzzing) for various parts of the system. - `ENABLE_FUZZERS`: builds [fuzzers](../Meta/Fuzzers/README.md) for various parts of the system.
- `ENABLE_FUZZERS_LIBFUZZER`: builds Clang libFuzzer-based [fuzzers](../Meta/Lagom/ReadMe.md#fuzzing) for various parts of the system. - `ENABLE_FUZZERS_LIBFUZZER`: builds Clang libFuzzer-based [fuzzers](../Meta/Fuzzers/README.md) for various parts of the system.
- `ENABLE_FUZZERS_OSSFUZZ`: builds OSS-Fuzz compatible [fuzzers](../Meta/Lagom/ReadMe.md#fuzzing) for various parts of the system. - `ENABLE_FUZZERS_OSSFUZZ`: builds OSS-Fuzz compatible [fuzzers](../Meta/Fuzzers/README.md) for various parts of the system.
- `ENABLE_ALL_THE_DEBUG_MACROS`: used for checking whether debug code compiles on CI. This should not be set normally, as it clutters the console output and makes the system run very slowly. Instead, enable only the needed debug macros, as described below. - `ENABLE_ALL_THE_DEBUG_MACROS`: used for checking whether debug code compiles on CI. This should not be set normally, as it clutters the console output and makes the system run very slowly. Instead, enable only the needed debug macros, as described below.
- `ENABLE_COMPILETIME_FORMAT_CHECK`: checks for the validity of `std::format`-style format string during compilation. Enabled by default. - `ENABLE_COMPILETIME_FORMAT_CHECK`: checks for the validity of `std::format`-style format string during compilation. Enabled by default.
- `INCLUDE_WASM_SPEC_TESTS`: downloads and includes the WebAssembly spec testsuite tests. In order to use this option, you will need to install `prettier` and `wasm-tools`. - `INCLUDE_WASM_SPEC_TESTS`: downloads and includes the WebAssembly spec testsuite tests. In order to use this option, you will need to install `prettier` and `wasm-tools`.

View file

@ -2,13 +2,14 @@
set -e set -e
LADYBIRD_SOURCE_DIR="$(dirname "${0}")"/../.. DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
LADYBIRD_SOURCE_DIR="${DIR}/../.."
cd "${LADYBIRD_SOURCE_DIR}" cd "${LADYBIRD_SOURCE_DIR}"
. "Meta/Utils/find_compiler.sh" . "Meta/Utils/find_compiler.sh"
pick_host_compiler --clang-only pick_host_compiler --clang-only
echo "Building Lagom Fuzzers..." echo "Building Fuzzers..."
if [ "$#" -gt "0" ] && [ "--oss-fuzz" = "$1" ] ; then if [ "$#" -gt "0" ] && [ "--oss-fuzz" = "$1" ] ; then
echo "Building for oss-fuzz configuration..." echo "Building for oss-fuzz configuration..."

View file

@ -24,7 +24,7 @@ WORKDIR /home
RUN dnf install -y clang cmake git-core ninja-build RUN dnf install -y clang cmake git-core ninja-build
RUN git clone --depth=1 https://github.com/LadybirdBrowser/ladybird RUN git clone --depth=1 https://github.com/LadybirdBrowser/ladybird
RUN cd ladybird/Meta/Lagom && ./BuildFuzzers.sh RUN cd ladybird/Meta/Fuzzers && ./BuildFuzzers.sh
FROM fedora:39 AS fuzzilli-build FROM fedora:39 AS fuzzilli-build
@ -42,8 +42,8 @@ WORKDIR /home
# This is unfortunate, but we need libswiftCore.so (and possibly other files) from the # This is unfortunate, but we need libswiftCore.so (and possibly other files) from the
# Swift runtime. The "swift-lang-runtime" package doesn't seem to exist in Fedora :/ # Swift runtime. The "swift-lang-runtime" package doesn't seem to exist in Fedora :/
RUN dnf install -y swift-lang procps-ng RUN dnf install -y swift-lang procps-ng
COPY --from=serenity-build /home/serenity/Meta/Lagom/Build/lagom-fuzzers/bin ./bin COPY --from=serenity-build /home/serenity/Meta/Fuzzers/Build/lagom-fuzzers/bin ./bin
COPY --from=serenity-build /home/serenity/Meta/Lagom/Build/lagom-fuzzers/lib64 ./lib64 COPY --from=serenity-build /home/serenity/Meta/Fuzzers/Build/lagom-fuzzers/lib64 ./lib64
COPY --from=fuzzilli-build /home/fuzzilli/.build/x86_64-unknown-linux-gnu/release/FuzzilliCli . COPY --from=fuzzilli-build /home/fuzzilli/.build/x86_64-unknown-linux-gnu/release/FuzzilliCli .
RUN mkdir fuzzilli-storage RUN mkdir fuzzilli-storage
ENV FUZZILLI_CLI_OPTIONS "" ENV FUZZILLI_CLI_OPTIONS ""

View file

@ -2,7 +2,7 @@
1. Download a copy of the Fuzzilli repo from https://github.com/googleprojectzero/fuzzilli 1. Download a copy of the Fuzzilli repo from https://github.com/googleprojectzero/fuzzilli
2. Install Swift and make sure it's in your path environment variable. 2. Install Swift and make sure it's in your path environment variable.
3. Build FuzzilliJs as you would the other fuzzers. [See ReadMe.md in the parent folder.](https://github.com/SerenityOS/serenity/blob/master/Meta/Lagom/ReadMe.md) 3. Build FuzzilliJs as you would the other fuzzers. [See README.md](README.md).
5. Build Fuzzilli with ```swift build -c release``` 5. Build Fuzzilli with ```swift build -c release```
6. Run Fuzzilli with ```swift run -c release FuzzilliCli --profile=serenity /path/to/FuzzilliJs```. See ```swift run FuzzilliCli --help``` for options. 6. Run Fuzzilli with ```swift run -c release FuzzilliCli --profile=serenity /path/to/FuzzilliJs```. See ```swift run FuzzilliCli --help``` for options.

128
Meta/Fuzzers/README.md Normal file
View file

@ -0,0 +1,128 @@
# Fuzzing
Lagom can be used to fuzz parts of Ladybird's code base. Fuzzers can be run locally, and they also run continuously on OSS-Fuzz.
## Fuzzing locally
This requires building with `clang`, so it's convenient to use a different build directory for that. Fuzzers work best with Address Sanitizer enabled. The fuzzer build requires code generators to be pre-built without fuzzing in a two stage build.
To build with LLVM's libFuzzer, invoke the ``BuildFuzzers.sh`` script with no arguments.
```sh
./BuildFuzzers.sh
./Build/lagom-fuzzers/FuzzSomething # The full list can be found in Fuzzers/CMakeLists.txt
```
(Note that we require clang >= 14, see the pick_clang() function in the script for the paths that are searched)
To build fuzzers without any kind of default instrumentation, pass the ``--standalone`` flag to ``BuildFuzzers.sh``:
```sh
./BuildFuzzers.sh --standalone
# This binary will read a single test input from a given filename (or, if no filename is given, from stdin) and exit.
./Build/lagom-fuzzers-standalone/Fuzzers/FuzzSomething
```
The fuzzing build's CMake cache can be manipulated with commands like `cmake -B Build/fuzzers -S . -DENABLE_LAGOM_CCACHE=OFF`.
Any fuzzing results (particularly slow inputs, crashes, etc.) will be dropped in the current directory.
Fuzzers work better if you give them a fuzz corpus, e.g. `./Fuzzers/FuzzBMPLoader ../Base/res/html/misc/bmpsuite_files/rgba32-61754.bmp` Pay attention that LLVM also likes creating new files, don't blindly commit them (yet)!
To run several fuzz jobs in parallel, pass `-jobs=24 -workers=24`.
To get less log output, pass `-close_fd_mask=3` -- but that but hides assertion messages. Just `1` only closes stdout.
It's good to move overzealous log output behind `FOO_DEBUG` macros.
Using other fuzzers is possible, as demonstrated by the OSS-fuzz build. Doing so likely requires setting CFLAGS and CXXFLAGS
on the second stage of the CMake build, or in your environment.
## Keeping track of interesting testcases
There are many quirky files that exercise a lot of interesting edge cases.
We should probably keep track of them, somewhere.
We have a [bmp suite and a jpg suite and several others](https://github.com/LadybirdWebBrowser/ladybird/tree/master/Base/res/html/misc).
They are GPL'ed, and therefore not quite as compatible with the rest of Serenity.
That's probably not a problem, but keeping "our" testcases separate from those GPL'ed suits sounds like a good idea.
We could keep those testcases somewhere else in the repository, like a `fuzz` directory.
But fuzzing tends to generate more and more and more files, and they will blow up in size.
Especially if we keep all interesting testcases, which is exactly what I intend to do.
So we should keep the actual testcases out of the main serenity repo,
that's why we created https://github.com/SerenityOS/serenity-fuzz-corpora
Feel free to upload lots and lots files there, or use them for great good!
## Fuzzing on OSS-Fuzz
https://oss-fuzz.com/ automatically runs all fuzzers in the Fuzzers/ subdirectory whose name starts with "Fuzz" and which are added to the build in `Fuzzers/CMakeLists.txt` if `ENABLE_FUZZERS_OSSFUZZ` is set. Looking for "serenity" on oss-fuzz.com finds interesting links, in particular:
* [known open bugs found by fuzzers](https://oss-fuzz.com/testcases?project=serenity&open=yes)
* [oss-fuzz bug tracker for these](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:serenity)
* [coverage report](https://oss-fuzz.com/coverage-report/job/libfuzzer_asan_serenity/latest)
* [build logs](https://oss-fuzz-build-logs.storage.googleapis.com/index.html#serenity)
Here's [Serenity's OSS-Fuzz Config](https://github.com/google/oss-fuzz/tree/master/projects/serenity). The configuration runs the `BuildFuzzers.sh` script with the `--oss-fuzz` argument inside the OSS-Fuzz docker container.
To run the OSS-fuzz build locally:
```
git clone https://github.com/google/oss-fuzz/
cd oss-fuzz
python3 infra/helper.py build_image serenity
python3 infra/helper.py build_fuzzers serenity
```
These commands will put the fuzzers in `build/out/serenity` in the oss-fuzz repo. You can run the binaries in there individually, or simply type:
```
python3 infra/helper.py run_fuzzer serenity FUZZER_NAME
```
To build the fuzzers using the oss-fuzz build process, but against a local serenity checkout:
```
python3 infra/helper.py build_fuzzers serenity $HOME/src/serenity/
```
To run a shell in oss-fuzz's serenity docker image:
```
docker run -it gcr.io/oss-fuzz/serenity bash
```
## Analyzing a crash
LLVM fuzzers have a weird interface. In particular, to see the help, you need to call it with `-help=1`, and it will ignore `--help` and `-help`.
To reproduce a crash, run it like this: `MyFuzzer crash-27480a219572aa5a11b285968a3632a4cf25388e`
To reproduce a crash in gdb, you want to disable various signal handlers, so that gdb sees the actual location of the crash:
```
$ gdb ./Fuzzers/FuzzBMP
<... SNIP some output ...>
(gdb) run -handle_abrt=0 -handle_segv=0 crash-27480a219572aa5a11b285968a3632a4cf25388e
<... SNIP some output ...>
FuzzBMP: ../../Libraries/LibGfx/Bitmap.cpp:84: Gfx::Bitmap::Bitmap(Gfx::BitmapFormat, const Gfx::IntSize &, Gfx::Bitmap::Purgeable): Assertion `m_data && m_data != (void*)-1' failed.
Thread 1 "FuzzBMP" received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
50 ../sysdeps/unix/sysv/linux/raise.c: File or directory not found.
(gdb)
```
UBSan doesn't always give useful information. use something like `export UBSAN_OPTIONS=print_stacktrace=1` to always print stacktraces.
You may run into annoying issues with the stacktrace:
```
==123456==WARNING: invalid path to external symbolizer!
==123456==WARNING: Failed to use and restart external symbolizer!
```
That means it couldn't find the executable `llvm-symbolizer`, which could be in your OS's package `llvm`.
`llvm-symbolizer-11` will [not be recognized](https://stackoverflow.com/a/42845444/).

View file

@ -41,132 +41,3 @@ Things to keep in mind:
- You should prefer to use a library's `Lagom::` alias when linking - You should prefer to use a library's `Lagom::` alias when linking
- Example: `Lagom::Core` vs `LibCore` - Example: `Lagom::Core` vs `LibCore`
- If your application has name clashes with any names in AK, you may have to define `USING_AK_GLOBALLY=0` for the files that have visibility to both sets of headers. - If your application has name clashes with any names in AK, you may have to define `USING_AK_GLOBALLY=0` for the files that have visibility to both sets of headers.
## Fuzzing
Lagom can be used to fuzz parts of SerenityOS's code base. Fuzzers can be run locally, and they also run continuously on OSS-Fuzz.
### Fuzzing locally
Lagom can be used to fuzz parts of SerenityOS's code base. This requires building with `clang`, so it's convenient to use a different build directory for that. Fuzzers work best with Address Sanitizer enabled. The fuzzer build requires code generators to be pre-built without fuzzing in a two stage build.
To build with LLVM's libFuzzer, invoke the ``BuildFuzzers.sh`` script with no arguments.
```sh
./BuildFuzzers.sh
./Build/lagom-fuzzers/FuzzSomething # The full list can be found in Fuzzers/CMakeLists.txt
```
(Note that we require clang >= 14, see the pick_clang() function in the script for the paths that are searched)
To build fuzzers without any kind of default instrumentation, pass the ``--standalone`` flag to ``BuildFuzzers.sh``:
```sh
./BuildFuzzers.sh --standalone
# This binary will read a single test input from a given filename (or, if no filename is given, from stdin) and exit.
./Build/lagom-fuzzers-standalone/Fuzzers/FuzzSomething
```
The fuzzing build's CMake cache can be manipulated with commands like `cmake -B Build/fuzzers -S . -DENABLE_LAGOM_CCACHE=OFF`.
Any fuzzing results (particularly slow inputs, crashes, etc.) will be dropped in the current directory.
Fuzzers work better if you give them a fuzz corpus, e.g. `./Fuzzers/FuzzBMPLoader ../Base/res/html/misc/bmpsuite_files/rgba32-61754.bmp` Pay attention that LLVM also likes creating new files, don't blindly commit them (yet)!
To run several fuzz jobs in parallel, pass `-jobs=24 -workers=24`.
To get less log output, pass `-close_fd_mask=3` -- but that but hides assertion messages. Just `1` only closes stdout.
It's good to move overzealous log output behind `FOO_DEBUG` macros.
Using other fuzzers is possible, as demonstrated by the OSS-fuzz build. Doing so likely requires setting CFLAGS and CXXFLAGS
on the second stage of the CMake build, or in your environment.
### Keeping track of interesting testcases
There are many quirky files that exercise a lot of interesting edge cases.
We should probably keep track of them, somewhere.
We have a [bmp suite and a jpg suite and several others](https://github.com/LadybirdWebBrowser/ladybird/tree/master/Base/res/html/misc).
They are GPL'ed, and therefore not quite as compatible with the rest of Serenity.
That's probably not a problem, but keeping "our" testcases separate from those GPL'ed suits sounds like a good idea.
We could keep those testcases somewhere else in the repository, like a `fuzz` directory.
But fuzzing tends to generate more and more and more files, and they will blow up in size.
Especially if we keep all interesting testcases, which is exactly what I intend to do.
So we should keep the actual testcases out of the main serenity repo,
that's why we created https://github.com/SerenityOS/serenity-fuzz-corpora
Feel free to upload lots and lots files there, or use them for great good!
### Fuzzing on OSS-Fuzz
https://oss-fuzz.com/ automatically runs all fuzzers in the Fuzzers/ subdirectory whose name starts with "Fuzz" and which are added to the build in `Fuzzers/CMakeLists.txt` if `ENABLE_FUZZERS_OSSFUZZ` is set. Looking for "serenity" on oss-fuzz.com finds interesting links, in particular:
* [known open bugs found by fuzzers](https://oss-fuzz.com/testcases?project=serenity&open=yes)
* [oss-fuzz bug tracker for these](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:serenity)
* [coverage report](https://oss-fuzz.com/coverage-report/job/libfuzzer_asan_serenity/latest)
* [build logs](https://oss-fuzz-build-logs.storage.googleapis.com/index.html#serenity)
Here's [Serenity's OSS-Fuzz Config](https://github.com/google/oss-fuzz/tree/master/projects/serenity). The configuration runs the `BuildFuzzers.sh` script with the `--oss-fuzz` argument inside the OSS-Fuzz docker container.
To run the OSS-fuzz build locally:
```
git clone https://github.com/google/oss-fuzz/
cd oss-fuzz
python3 infra/helper.py build_image serenity
python3 infra/helper.py build_fuzzers serenity
```
These commands will put the fuzzers in `build/out/serenity` in the oss-fuzz repo. You can run the binaries in there individually, or simply type:
```
python3 infra/helper.py run_fuzzer serenity FUZZER_NAME
```
To build the fuzzers using the oss-fuzz build process, but against a local serenity checkout:
```
python3 infra/helper.py build_fuzzers serenity $HOME/src/serenity/
```
To run a shell in oss-fuzz's serenity docker image:
```
docker run -it gcr.io/oss-fuzz/serenity bash
```
### Analyzing a crash
LLVM fuzzers have a weird interface. In particular, to see the help, you need to call it with `-help=1`, and it will ignore `--help` and `-help`.
To reproduce a crash, run it like this: `MyFuzzer crash-27480a219572aa5a11b285968a3632a4cf25388e`
To reproduce a crash in gdb, you want to disable various signal handlers, so that gdb sees the actual location of the crash:
```
$ gdb ./Fuzzers/FuzzBMP
<... SNIP some output ...>
(gdb) run -handle_abrt=0 -handle_segv=0 crash-27480a219572aa5a11b285968a3632a4cf25388e
<... SNIP some output ...>
FuzzBMP: ../../Libraries/LibGfx/Bitmap.cpp:84: Gfx::Bitmap::Bitmap(Gfx::BitmapFormat, const Gfx::IntSize &, Gfx::Bitmap::Purgeable): Assertion `m_data && m_data != (void*)-1' failed.
Thread 1 "FuzzBMP" received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
50 ../sysdeps/unix/sysv/linux/raise.c: File or directory not found.
(gdb)
```
UBSan doesn't always give useful information. use something like `export UBSAN_OPTIONS=print_stacktrace=1` to always print stacktraces.
You may run into annoying issues with the stacktrace:
```
==123456==WARNING: invalid path to external symbolizer!
==123456==WARNING: Failed to use and restart external symbolizer!
```
That means it couldn't find the executable `llvm-symbolizer`, which could be in your OS's package `llvm`.
`llvm-symbolizer-11` will [not be recognized](https://stackoverflow.com/a/42845444/).