diff --git a/.clusterfuzzlite/Dockerfile b/.clusterfuzzlite/Dockerfile new file mode 100644 index 0000000..7dbb612 --- /dev/null +++ b/.clusterfuzzlite/Dockerfile @@ -0,0 +1,6 @@ +FROM gcr.io/oss-fuzz-base/base-builder +RUN apt-get update && apt-get install -y make autoconf automake libtool +COPY . $SRC/uvwasi +COPY .clusterfuzzlite/build.sh $SRC/build.sh +COPY .clusterfuzzlite/*.c $SRC/ +WORKDIR uvwasi diff --git a/.clusterfuzzlite/build.sh b/.clusterfuzzlite/build.sh new file mode 100644 index 0000000..bfe2542 --- /dev/null +++ b/.clusterfuzzlite/build.sh @@ -0,0 +1,11 @@ +# Disable building of shared library +#sed -i 's/add\_library(uvwasi SHARED/# /g' CMakeLists.txt +mkdir build +cd build +cmake ../ +make uvwasi_a + +$CC $CFLAGS $LIB_FUZZING_ENGINE ../.clusterfuzzlite/fuzz_normalize_path.c \ + -o $OUT/fuzz_normalize_path \ + ./libuvwasi_a.a _deps/libuv-build/libuv_a.a \ + -I$SRC/uvwasi/include -I$PWD/_deps/libuv-src/include/ diff --git a/.clusterfuzzlite/fuzz_normalize_path.c b/.clusterfuzzlite/fuzz_normalize_path.c new file mode 100644 index 0000000..e527c5f --- /dev/null +++ b/.clusterfuzzlite/fuzz_normalize_path.c @@ -0,0 +1,25 @@ +#include +#include +#include + +#include "../src/path_resolver.h" + +#define BUFFER_SIZE 128 + +char normalized_buffer[BUFFER_SIZE+1]; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + char *new_str = (char *)malloc(size + 1); + if (new_str == NULL) { + return 0; + } + memcpy(new_str, data, size); + new_str[size] = '\0'; + + memset(normalized_buffer, 0, BUFFER_SIZE); + + uvwasi__normalize_path(new_str, size, normalized_buffer, BUFFER_SIZE); + + free(new_str); + return 0; +} diff --git a/.clusterfuzzlite/project.yaml b/.clusterfuzzlite/project.yaml new file mode 100644 index 0000000..b455aa3 --- /dev/null +++ b/.clusterfuzzlite/project.yaml @@ -0,0 +1 @@ +language: c diff --git a/.github/workflows/cflite.yml b/.github/workflows/cflite.yml new file mode 100644 index 0000000..e443514 --- /dev/null +++ b/.github/workflows/cflite.yml @@ -0,0 +1,29 @@ +name: ClusterFuzzLite PR fuzzing +on: + workflow_dispatch: + pull_request: + branches: [ main ] +permissions: read-all +jobs: + PR: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + sanitizer: [address] + steps: + - name: Build Fuzzers (${{ matrix.sanitizer }}) + id: build + uses: google/clusterfuzzlite/actions/build_fuzzers@v1 + with: + sanitizer: ${{ matrix.sanitizer }} + language: c + bad-build-check: false + - name: Run Fuzzers (${{ matrix.sanitizer }}) + id: run + uses: google/clusterfuzzlite/actions/run_fuzzers@v1 + with: + fuzz-seconds: 100 + mode: 'code-change' + report-unreproducible-crashes: false + sanitizer: ${{ matrix.sanitizer }} diff --git a/README.md b/README.md index b929704..e3f33cc 100644 --- a/README.md +++ b/README.md @@ -2500,6 +2500,26 @@ To do a release complete the following steps: * Update uvwasi in Node.js or any projects you want to update - there are several other projects that use uvwasi. +## Running fuzzers locally + +We support fuzzing by way of [ClusterFuzzLite](https://google.github.io/clusterfuzzlite/), +which is run automatically against pull requests. You can run these fuzzers +locally with the [OSS-Fuzz](https://github.com/google/oss-fuzz) fuzzing +infrastructure, using the following steps: + +```sh +git clone https://github.com/google/oss-fuzz +git clone https://github.com/nodejs/uvwasi +cd uvwasi + +# Build the fuzzers in .clusterfuzzlite +python3 ../oss-fuzz/infra/helper.py build_fuzzers --external $PWD + +# Run the fuzzer for 10 seconds +python3 ../oss-fuzz/infra/helper.py run_fuzzer --external $PWD fuzz_normalize_path -- -max_total_time=10 +``` + + [WASI]: https://github.com/WebAssembly/WASI [libuv]: https://github.com/libuv/libuv [preview 1]: https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md diff --git a/src/path_resolver.c b/src/path_resolver.c index 77f0623..8a73f03 100644 --- a/src/path_resolver.c +++ b/src/path_resolver.c @@ -72,6 +72,10 @@ uvwasi_errno_t uvwasi__normalize_path(const char* path, uvwasi_size_t path_len, char* normalized_path, uvwasi_size_t normalized_len) { + /* Normalizes path and stores the resulting buffer in normalized_path. + the sizes of the buffers must correspond to strlen() of the relevant + buffers, i.e. there must be room in the relevant buffers for a + NULL-byte. */ const char* cur; char* ptr; char* next; @@ -345,7 +349,8 @@ static uvwasi_errno_t uvwasi__resolve_path_to_host( char** resolved_path, uvwasi_size_t* resolved_len ) { - /* Return the normalized path, but resolved to the host's real path. */ + /* Return the normalized path, but resolved to the host's real path. + `path` must be a NULL-terminated string. */ char* res_path; char* stripped_path; int real_path_len;