diff --git a/.clusterfuzzlite/Dockerfile b/.clusterfuzzlite/Dockerfile new file mode 100644 index 00000000..17628373 --- /dev/null +++ b/.clusterfuzzlite/Dockerfile @@ -0,0 +1,5 @@ +FROM gcr.io/oss-fuzz-base/base-builder:v1 +RUN apt-get update && apt-get install -y make libssl-dev libbsd-dev +COPY . $SRC/app-stellar +WORKDIR $SRC/app-stellar +COPY .clusterfuzzlite/build.sh $SRC/ diff --git a/.clusterfuzzlite/build.sh b/.clusterfuzzlite/build.sh new file mode 100755 index 00000000..65568903 --- /dev/null +++ b/.clusterfuzzlite/build.sh @@ -0,0 +1,9 @@ +#!/bin/bash -eu + +# build fuzzers + +pushd fuzz +./build.sh +mv ./cmake-build-fuzz/fuzz_tx $OUT/app-stellar-fuzz-tx +popd + diff --git a/.clusterfuzzlite/project.yaml b/.clusterfuzzlite/project.yaml new file mode 100644 index 00000000..b4788012 --- /dev/null +++ b/.clusterfuzzlite/project.yaml @@ -0,0 +1 @@ +language: c++ diff --git a/.github/workflows/cflite_batch.yml b/.github/workflows/cflite_batch.yml new file mode 100644 index 00000000..b1c7861b --- /dev/null +++ b/.github/workflows/cflite_batch.yml @@ -0,0 +1,33 @@ +name: ClusterFuzzLite batch fuzzing +on: + schedule: + - cron: '1 * * * 0' # Every sunday +permissions: read-all +jobs: + BatchFuzzing: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + sanitizer: [address, undefined, memory] + steps: + - name: Build Fuzzers (${{ matrix.sanitizer }}) + id: build + uses: google/clusterfuzzlite/actions/build_fuzzers@v1 + with: + language: c++ + sanitizer: ${{ matrix.sanitizer }} + - name: Run Fuzzers (${{ matrix.sanitizer }}) + id: run + uses: google/clusterfuzzlite/actions/run_fuzzers@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + fuzz-seconds: 3600 # 1 hour + mode: 'batch' + sanitizer: ${{ matrix.sanitizer }} + # Optional but recommended: For storing certain artifacts from fuzzing. + # See later section on "Git repo for storage". + #storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/LedgerHQ/fuzzers-corpus.git + #storage-repo-branch: main # Optional. Defaults to "main" + #storage-repo-branch-coverage: gh-pages # Optional. Defaults to "gh-pages". + diff --git a/.github/workflows/cflite_pr.yml b/.github/workflows/cflite_pr.yml new file mode 100644 index 00000000..03873f48 --- /dev/null +++ b/.github/workflows/cflite_pr.yml @@ -0,0 +1,45 @@ +name: ClusterFuzzLite PR fuzzing +on: + pull_request: + paths: + - '**' +permissions: read-all +jobs: + PR: + runs-on: ubuntu-latest + concurrency: + group: ${{ github.workflow }}-${{ matrix.sanitizer }}-${{ github.ref }} + cancel-in-progress: true + strategy: + fail-fast: false + matrix: + sanitizer: [address, undefined, memory] + steps: + - name: Build Fuzzers (${{ matrix.sanitizer }}) + id: build + uses: google/clusterfuzzlite/actions/build_fuzzers@v1 + with: + language: c++ + github-token: ${{ secrets.GITHUB_TOKEN }} + sanitizer: ${{ matrix.sanitizer }} + # Optional but recommended: used to only run fuzzers that are affected + # by the PR. + # See later section on "Git repo for storage". + #storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/LedgerHQ/fuzzers-corpus.git + #storage-repo-branch: main # Optional. Defaults to "main" + #storage-repo-branch-coverage: gh-pages # Optional. Defaults to "gh-pages". + - name: Run Fuzzers (${{ matrix.sanitizer }}) + id: run + uses: google/clusterfuzzlite/actions/run_fuzzers@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + fuzz-seconds: 600 # 10 minutes + mode: 'code-change' + sanitizer: ${{ matrix.sanitizer }} + # Optional but recommended: used to download the corpus produced by + # batch fuzzing. + # See later section on "Git repo for storage". + #storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/LedgerHQ/fuzzers-corpus.git + #storage-repo-branch: main # Optional. Defaults to "main" + #storage-repo-branch-coverage: gh-pages # Optional. Defaults to "gh-pages". + diff --git a/src/stellar_parser.c b/src/stellar_parser.c index cbc9dbe4..604ffd43 100644 --- a/src/stellar_parser.c +++ b/src/stellar_parser.c @@ -46,7 +46,7 @@ static bool buffer_read32(buffer_t *buffer, uint32_t *n) { } const uint8_t *ptr = buffer->ptr + buffer->offset; - *n = ptr[3] + (ptr[2] << 8u) + (ptr[1] << 16u) + (ptr[0] << 24u); + *n = ptr[3] + (ptr[2] << 8u) + (ptr[1] << 16u) + ((uint32_t)(ptr[0]) << 24u); buffer_advance(buffer, 4); return true; } @@ -58,8 +58,8 @@ bool buffer_read64(buffer_t *buffer, uint64_t *n) { } const uint8_t *ptr = buffer->ptr + buffer->offset; - uint32_t i1 = ptr[3] + (ptr[2] << 8u) + (ptr[1] << 16u) + (ptr[0] << 24u); - uint32_t i2 = ptr[7] + (ptr[6] << 8u) + (ptr[5] << 16u) + (ptr[4] << 24u); + uint32_t i1 = ptr[3] + (ptr[2] << 8u) + (ptr[1] << 16u) + ((uint32_t)(ptr[0]) << 24u); + uint32_t i2 = ptr[7] + (ptr[6] << 8u) + (ptr[5] << 16u) + ((uint32_t)(ptr[4]) << 24u); *n = i2 | ((uint64_t) i1 << 32u); buffer->offset += 8; return true; diff --git a/src/stellar_utils.c b/src/stellar_utils.c index fbc924e7..edeffa43 100644 --- a/src/stellar_utils.c +++ b/src/stellar_utils.c @@ -40,7 +40,8 @@ bool parse_bip32_path(uint8_t *path, } for (size_t i = 0; i < path_length; i++) { - path_parsed[i] = (path[0] << 24u) | (path[1] << 16u) | (path[2] << 8u) | (path[3]); + path_parsed[i] = + ((uint32_t)(path[0]) << 24u) | (path[1] << 16u) | (path[2] << 8u) | (path[3]); path += 4; } @@ -48,10 +49,10 @@ bool parse_bip32_path(uint8_t *path, } unsigned short crc16(char *ptr, int count) { - int crc; + uint32_t crc; crc = 0; while (--count >= 0) { - crc = crc ^ (int) *ptr++ << 8; + crc = crc ^ (uint32_t) *ptr++ << 8; int i = 8; do { if (crc & 0x8000) @@ -75,7 +76,7 @@ int base32_encode(const uint8_t *data, int length, char *result, int bufSize) { } if (length > 0) { - int buffer = data[0]; + uint32_t buffer = data[0]; int next = 1; int bitsLeft = 8; int quantum = 8; @@ -346,8 +347,15 @@ int print_int(int64_t l, char *out, size_t out_len) { return -1; } if (l < 0) { + uint64_t n; + out[0] = '-'; - return print_uint(-l, out + 1, out_len - 1); + if (l == INT64_MIN) { + n = (uint64_t) l; + } else { + n = -l; + } + return print_uint(n, out + 1, out_len - 1); } return print_uint(l, out, out_len); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6a3571fd..caa06206 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -17,6 +17,11 @@ add_library(stellar ../src/stellar_parser.c ) +if (FUZZ) + add_library(bsd STATIC IMPORTED) + set_property(TARGET bsd PROPERTY IMPORTED_LOCATION /lib/x86_64-linux-gnu/libbsd.a) +endif() + target_include_directories(stellar PUBLIC ../src include) target_link_libraries(stellar PRIVATE bsd) @@ -41,8 +46,18 @@ if (FUZZ) message(FATAL_ERROR "Fuzzer needs to be built with Clang") endif() + # compatible with ClusterFuzzLite + if (NOT DEFINED ENV{LIB_FUZZING_ENGINE}) + set(COMPILATION_FLAGS_ "-fsanitize=address,fuzzer -g") + else() + set(COMPILATION_FLAGS_ "$ENV{LIB_FUZZING_ENGINE} $ENV{CXXFLAGS}") + endif() + + string(REPLACE " " ";" COMPILATION_FLAGS ${COMPILATION_FLAGS_}) + message(${COMPILATION_FLAGS}) + add_executable(fuzz_tx src/fuzz_tx.c) - target_compile_options(fuzz_tx PRIVATE -fsanitize=address,fuzzer -g -ggdb2) - target_link_options(fuzz_tx PRIVATE -fsanitize=address,fuzzer) + target_compile_options(fuzz_tx PRIVATE ${COMPILATION_FLAGS}) + target_link_options(fuzz_tx PRIVATE ${COMPILATION_FLAGS}) target_link_libraries(fuzz_tx PRIVATE stellar bsd crypto) endif() diff --git a/tests/requirements.txt b/tests/requirements.txt index 7b572249..620d452e 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,3 +1,4 @@ construct==2.10.61 pytest>=6.1.1,<7.0.0 ledgerwallet>=0.1.2 +protobuf~=3.19