diff --git a/.clusterfuzzlite/Dockerfile b/.clusterfuzzlite/Dockerfile new file mode 100644 index 00000000..6f2d35d9 --- /dev/null +++ b/.clusterfuzzlite/Dockerfile @@ -0,0 +1,7 @@ +FROM ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest AS LITE_BUILDER + +FROM gcr.io/oss-fuzz-base/base-builder:v1 +COPY . $SRC/app-cardano +COPY ./.clusterfuzzlite/build.sh $SRC/ +COPY --from=LITE_BUILDER /opt/ledger-secure-sdk $SRC/app-cardano/BOLOS_SDK +WORKDIR $SRC/app-cardano \ No newline at end of file diff --git a/.clusterfuzzlite/build.sh b/.clusterfuzzlite/build.sh new file mode 100644 index 00000000..6fc23299 --- /dev/null +++ b/.clusterfuzzlite/build.sh @@ -0,0 +1,9 @@ +#!/bin/bash -eu + +# build fuzzers + +pushd fuzzing +cmake -DBOLOS_SDK=../BOLOS_SDK -Bbuild -H. +make -C build +mv build/*_harness $OUT +popd \ No newline at end of file diff --git a/.clusterfuzzlite/project.yaml b/.clusterfuzzlite/project.yaml new file mode 100644 index 00000000..e196c5cc --- /dev/null +++ b/.clusterfuzzlite/project.yaml @@ -0,0 +1 @@ +language: c \ No newline at end of file diff --git a/.github/workflows/cflite_cron.yml b/.github/workflows/cflite_cron.yml new file mode 100644 index 00000000..44ac10c2 --- /dev/null +++ b/.github/workflows/cflite_cron.yml @@ -0,0 +1,41 @@ +name: ClusterFuzzLite cron tasks +on: + workflow_dispatch: + push: + branches: + - main # Use your actual default branch here. + schedule: + - cron: '0 13 * * 6' # At 01:00 PM, only on Saturday +permissions: read-all +jobs: + Fuzzing: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - mode: batch + sanitizer: address + - mode: batch + sanitizer: memory + - mode: prune + sanitizer: address + - mode: coverage + sanitizer: coverage + steps: + - name: Build Fuzzers (${{ matrix.mode }} - ${{ matrix.sanitizer }}) + id: build + uses: google/clusterfuzzlite/actions/build_fuzzers@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + language: c # Change this to the language you are fuzzing. + sanitizer: ${{ matrix.sanitizer }} + - name: Run Fuzzers (${{ matrix.mode }} - ${{ matrix.sanitizer }}) + id: run + uses: google/clusterfuzzlite/actions/run_fuzzers@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + fuzz-seconds: 300 # 5 minutes + mode: ${{ matrix.mode }} + sanitizer: ${{ matrix.sanitizer }} + \ No newline at end of file diff --git a/.github/workflows/cflite_pr.yml b/.github/workflows/cflite_pr.yml new file mode 100644 index 00000000..f70175e1 --- /dev/null +++ b/.github/workflows/cflite_pr.yml @@ -0,0 +1,43 @@ +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] # Override this with the sanitizers you want. + steps: + - name: Build Fuzzers (${{ matrix.sanitizer }}) + id: build + uses: google/clusterfuzzlite/actions/build_fuzzers@v1 + with: + language: c # Change this to the language you are fuzzing. + github-token: ${{ secrets.GITHUB_TOKEN }} + sanitizer: ${{ matrix.sanitizer }} + # Optional but recommended: used to only run fuzzers that are affected + # by the PR. + # storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/OWNER/STORAGE-REPO-NAME.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: 300 # 5 minutes + mode: 'code-change' + sanitizer: ${{ matrix.sanitizer }} + output-sarif: true + # Optional but recommended: used to download the corpus produced by + # batch fuzzing. + # storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/OWNER/STORAGE-REPO-NAME.git + # storage-repo-branch: main # Optional. Defaults to "main" + # storage-repo-branch-coverage: gh-pages # Optional. Defaults to "gh-pages". \ No newline at end of file diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt deleted file mode 100644 index e57620c5..00000000 --- a/fuzz/CMakeLists.txt +++ /dev/null @@ -1,115 +0,0 @@ -cmake_minimum_required(VERSION 3.10) - -project(cardano_fuzzer C) - -set(CMAKE_C_STANDARD 11) - -set (SDK_PATH $ENV{BOLOS_SDK}) - -include_directories(. ../src) -include_directories( - ${SDK_PATH}/include/ - ${SDK_PATH}/lib_cxng/include/ - ${SDK_PATH}/lib_cxng/src/ - ${SDK_PATH}/lib_ux/include/ - ) - -add_compile_options(-g -ggdb2) -if (FUZZ) -add_compile_options(-O3) -add_compile_options(-fsanitize=fuzzer,address) -add_link_options(-fsanitize=fuzzer,address) -add_compile_definitions(HAVE_PRINTF PRINTF=printf) -endif() - -add_compile_definitions( - FUZZING - OS_IO_SEPROXYHAL - IO_SEPROXYHAL_BUFFER_SIZE_B=300 - IO_HID_EP_LENGTH=64 - HAVE_UX_FLOW - HAVE_BAGL - APPVERSION="0.0.0" -) - -# hack so that core_sc000.h compiles -if (WIN32) -add_compile_definitions(__GNUC__) -endif() - -add_compile_definitions( - HAVE_ECC - HAVE_ECC_WEIERSTRASS - HAVE_SECP256K1_CURVE - HAVE_SECP256R1_CURVE - HAVE_ECC_TWISTED_EDWARDS - HAVE_ED25519_CURVE - HAVE_ECDSA - HAVE_EDDSA - HAVE_HASH - HAVE_SHA256 - HAVE_SHA3 - HAVE_BLAKE2 -) - -set(LIBUX_PATH ${SDK_PATH}/lib_ux) - -set (LIBUX_SRCS - ${LIBUX_PATH}/src/ux_flow_engine.c - ${LIBUX_PATH}/src/ux_layout_bb.c - ${LIBUX_PATH}/src/ux_layout_bn.c - ${LIBUX_PATH}/src/ux_layout_bnn.c - ${LIBUX_PATH}/src/ux_layout_bnnn.c - ${LIBUX_PATH}/src/ux_layout_nn.c - ${LIBUX_PATH}/src/ux_layout_paging.c - ${LIBUX_PATH}/src/ux_layout_paging_compute.c - ${LIBUX_PATH}/src/ux_layout_pbb.c - ${LIBUX_PATH}/src/ux_layout_pn.c - ${LIBUX_PATH}/src/ux_layout_pnn.c - ${LIBUX_PATH}/src/ux_layout_utils.c - ${LIBUX_PATH}/src/ux_stack.c -) - -set(SOURCES - fuzztest.c - os_mocks.c - glyphs.c - - ../src/addressUtilsByron.c - ../src/addressUtilsShelley.c - ../src/assert.c - ../src/auxDataHashBuilder.c - ../src/base58.c - ../src/bech32.c - ../src/bip44.c - ../src/cardano.c - ../src/cbor.c - ../src/crc32.c - ../src/io.c - ../src/ipUtils.c - ../src/keyDerivation.c - ../src/hexUtils.c - ../src/messageSigning.c - ../src/securityPolicy.c - ../src/signOpCert.c - ../src/signTx.c - ../src/signTxOutput.c - ../src/state.c - ../src/signTxPoolRegistration.c - ../src/signTxCVoteRegistration.c - ../src/signTxUtils.c - ../src/textUtils.c - ../src/txHashBuilder.c - ../src/uiHelpers.c - ../src/uiHelpers_nanox.c - ../src/uiScreens.c - ../src/getPublicKeys.c - ${LIBUX_SRCS}) - -add_executable(fuzzer ${SOURCES}) -add_executable(fuzzer_coverage ${SOURCES}) - -target_compile_options(fuzzer_coverage PRIVATE -fprofile-instr-generate -fcoverage-mapping) - -target_link_options(fuzzer PRIVATE) -target_link_options(fuzzer_coverage PRIVATE) \ No newline at end of file diff --git a/fuzz/coverage.py b/fuzz/coverage.py deleted file mode 100644 index de47f195..00000000 --- a/fuzz/coverage.py +++ /dev/null @@ -1,79 +0,0 @@ -import os -import platform -import subprocess -from glob import glob - - -def extract_profiles(corpus_path, cov_executable): - """ Run corpus through coverage executable. This function - avoids a limitation on filename length on Windows """ - # group by packs of N for faster execution - # N has to be low enough that Windows does not - # complain about too long filenames. 512 seems fine. - file_list = glob(os.path.join(corpus_path, "*")) - N = 512 - for p in range(0, len(file_list), N): - subprocess.run([cov_executable, "-close_fd_mask=1", *file_list[p : p + N]]) - - -def merge_profile_data(): - """ Merge profiling data """ - print( - subprocess.run( - [ - "llvm-profdata", - "merge", - "-sparse", - "*.profraw", - "-o", - "default.profdata", - ], - check=True, - ) - ) - - -def show_summary(cov_executable): - """ Displays the main report from llvm-cov """ - print( - subprocess.run( - ["llvm-cov", "report", "--instr-profile=default.profdata", cov_executable] - ) - ) - - -def create_report(cov_executable): - """ Create a report in HTML format into 'coverage/index.html' """ - print( - subprocess.run( - [ - "llvm-cov", - "show", - cov_executable, - "--instr-profile=default.profdata", - "--format=html", - "-o", - "./coverage/", - ] - ) - ) - - -if __name__ == "__main__": - from argparse import ArgumentParser - - argp = ArgumentParser() - argp.add_argument("-path", default="./build/", help="Path to build directory") - args = argp.parse_args() - - cov = os.path.join( - args.path, "fuzzer_coverage" + ".exe" * (platform.system() == "Windows") - ) - - if not os.path.exists(cov): - raise Exception(f"Fuzzer executable ({cov}) cannot be found") - - extract_profiles("./corpus/", cov) - merge_profile_data() - show_summary(cov) - create_report(cov) diff --git a/fuzz/fuzztest.c b/fuzz/fuzztest.c deleted file mode 100644 index 26dd80e9..00000000 --- a/fuzz/fuzztest.c +++ /dev/null @@ -1,69 +0,0 @@ -#include -#include -#include "cx.h" - -#include "signTx.h" -#include "getPublicKeys.h" - -ux_state_t G_ux; -uint8_t G_io_apdu_buffer[IO_APDU_BUFFER_SIZE]; - -#ifdef DEVEL -#include "utils.h" -unsigned int app_stack_canary = APP_STACK_CANARY_MAGIC; -#endif - -void signTx_handleAPDU_no_throw(uint8_t p1, uint8_t p2, const uint8_t *wireBuffer, size_t wireSize, bool isNewCall) { - BEGIN_TRY { - TRY { - signTx_handleAPDU(p1, p2, wireBuffer, wireSize, isNewCall); - } - CATCH_ALL { - } - FINALLY { - } - } END_TRY; -} - -void signOpCert_handleAPDU_no_throw(uint8_t p1, uint8_t p2, const uint8_t *wireBuffer, size_t wireSize, bool isNewCall) { - BEGIN_TRY { - TRY { - signOpCert_handleAPDU(p1, p2, wireBuffer, wireSize, isNewCall); - } - CATCH_ALL { - } - FINALLY { - } - } END_TRY; -} - -int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - - UX_INIT(); - - bool is_first = true; - uint8_t * input = Data; - size_t size = Size; - while ((size > 5) && (input[3] < size-4)) { - io_state = IO_EXPECT_NONE; - uint8_t ins = input[0]; - uint8_t p1 = input[1]; - uint8_t p2 = input[2]; - uint8_t lc = input[3]; - - switch (ins) { - case 0x22: - signOpCert_handleAPDU_no_throw(p1, p2, &input[4], lc, is_first); - break; - case 0x21: - signTx_handleAPDU_no_throw(p1, p2, &input[4], lc, is_first); - break; - default: - return 0; - } - is_first = false; - size -= lc + 4; - input += lc + 4; - } - return 0; -} \ No newline at end of file diff --git a/fuzz/glyphs.c b/fuzz/glyphs.c deleted file mode 100644 index 0cc6f916..00000000 --- a/fuzz/glyphs.c +++ /dev/null @@ -1,8 +0,0 @@ -#include - -const uint8_t C_icon_crossmark[1] = {0}; -const uint8_t C_icon_loader[1] = {0}; -const uint8_t C_icon_eye[1] = {0}; -const uint8_t C_icon_validate_14[1] = {0}; -const uint8_t C_icon_left[1] = {0}; -const uint8_t C_icon_right[1] = {0}; diff --git a/fuzz/glyphs.h b/fuzz/glyphs.h deleted file mode 100644 index 0a6fe956..00000000 --- a/fuzz/glyphs.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include - -extern const uint8_t C_icon_crossmark[1]; -extern const uint8_t C_icon_loader[1]; -extern const uint8_t C_icon_eye[1]; -extern const uint8_t C_icon_validate_14[1]; -extern const uint8_t C_icon_left[1]; -extern const uint8_t C_icon_right[1]; diff --git a/fuzz/os_mocks.c b/fuzz/os_mocks.c deleted file mode 100644 index 2e071eeb..00000000 --- a/fuzz/os_mocks.c +++ /dev/null @@ -1,44 +0,0 @@ -#include "os.h" -#include "cx.h" -#include "ux.h" - -void os_longjmp(unsigned int exception) { - longjmp(try_context_get()->jmp_buf, exception); -} - -try_context_t *current_context = NULL; -try_context_t *try_context_get(void) { - return current_context; -} - -try_context_t *try_context_set(try_context_t *ctx) { - try_context_t *previous_ctx = current_context; - current_context = ctx; - return previous_ctx; -} - -bolos_task_status_t os_sched_last_status(unsigned int task_idx) {return 1;}; -unsigned short io_exchange(unsigned char chan, unsigned short tx_len) {return 0;}; -void * pic(void * linked_addr) {return linked_addr;} - -void io_seproxyhal_display_default(const bagl_element_t * bagl) { - if (bagl->text) { - printf("[-] %s\n", bagl->text); - } -} - -void ui_idle() {}; - -unsigned int os_ux(bolos_ux_params_t * params) {return 0;}; -void io_seproxyhal_init_ux(void) {}; -unsigned int io_seph_is_status_sent (void) {return 0;}; -bolos_bool_t os_perso_isonboarded(void) {return (bolos_bool_t)BOLOS_UX_OK;}; -void io_seproxyhal_general_status(void) {}; -void io_seph_send(const unsigned char * buffer, unsigned short length) {}; -unsigned short io_seph_recv ( unsigned char * buffer, unsigned short maxlength, unsigned int flags ) {return 0;}; -void halt() { for(;;); }; -bolos_bool_t os_global_pin_is_validated(void) {return (bolos_bool_t)BOLOS_UX_OK;}; -cx_err_t cx_hash_no_throw(cx_hash_t *hash, uint32_t mode, const uint8_t *in, size_t len, uint8_t *out, size_t out_len) { return 0;}; -size_t cx_hash_get_size(const cx_hash_t *ctx) { return 32;}; -cx_err_t cx_blake2b_init_no_throw(cx_blake2b_t *hash, size_t size) {return 0;}; -cx_err_t cx_sha3_init_no_throw(cx_sha3_t *hash, size_t size) {return 0;}; diff --git a/fuzz/readme.md b/fuzz/readme.md deleted file mode 100644 index d1a360da..00000000 --- a/fuzz/readme.md +++ /dev/null @@ -1,42 +0,0 @@ -# Cardano Fuzzer - -## Building and fuzzing - -### Linux - -```shell -BOLOS_SDK=/path/to/sdk/ cmake -Bbuild -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DFUZZ=1 -cd build -make -``` - -```shell -mkdir ../corpus -cp ../ref_corpus/* ../corpus/ -./fuzzer ../corpus/ -close_fd_mask=1 -``` - -### Windows - -```shell -$env:BOLOS_SDK = 'C:/path/to/sdk' # (PowerShell) -cmake -Bbuild -GNinja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DFUZZ=1 -cd build -ninja -``` - -```shell -mkdir ../corpus -copy ../ref_corpus/valid_tx ../corpus/valid_tx -./fuzzer.exe ../corpus/ -close_fd_mask=1 -``` - -## Coverage information - -Generating coverage: - -``` -python3 coverage.py -``` - -Will output an HTML report in `./coverage/index.html`. \ No newline at end of file diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt new file mode 100644 index 00000000..fe7e9fe6 --- /dev/null +++ b/fuzzing/CMakeLists.txt @@ -0,0 +1,172 @@ +cmake_minimum_required(VERSION 3.22) + +project(cardano_fuzzers C) + +set(CMAKE_C_STANDARD 11) + +if (NOT CMAKE_C_COMPILER_ID MATCHES "Clang") + message(FATAL_ERROR "Fuzzer needs to be built with Clang") +endif() + +# guard against in-source builds +if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) + message(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt. ") +endif() + + +if (NOT DEFINED ENV{LIB_FUZZING_ENGINE}) + add_compile_options(-fsanitize=address,fuzzer-no-link) + add_link_options(-fsanitize=address,fuzzer) +else() + add_link_options($ENV{LIB_FUZZING_ENGINE}) +endif() + + + +set(SDK_PATH ${BOLOS_SDK}) +set(UX_PATH ${SDK_PATH}/lib_ux) +set(CARDANO_PATH ..) + +set(UX_SOURCE + ${UX_PATH}/src/ux_flow_engine.c + ${UX_PATH}/src/ux_layout_bb.c + ${UX_PATH}/src/ux_layout_bn.c + ${UX_PATH}/src/ux_layout_bnn.c + ${UX_PATH}/src/ux_layout_bnnn.c + ${UX_PATH}/src/ux_layout_nn.c + ${UX_PATH}/src/ux_layout_paging.c + ${UX_PATH}/src/ux_layout_paging_compute.c + ${UX_PATH}/src/ux_layout_pbb.c + ${UX_PATH}/src/ux_layout_pb.c + ${UX_PATH}/src/ux_layout_pn.c + ${UX_PATH}/src/ux_layout_pnn.c + ${UX_PATH}/src/ux_layout_utils.c + ${UX_PATH}/src/ux_stack.c +) + +set(CARDANO_SOURCE + ${CARDANO_PATH}/src/addressUtilsByron.c + ${CARDANO_PATH}/src/addressUtilsShelley.c + ${CARDANO_PATH}/src/app_mode.c + ${CARDANO_PATH}/src/assert.c + ${CARDANO_PATH}/src/auxDataHashBuilder.c + ${CARDANO_PATH}/src/base58.c + ${CARDANO_PATH}/src/bech32.c + ${CARDANO_PATH}/src/bip44.c + ${CARDANO_PATH}/src/cardano.c + ${CARDANO_PATH}/src/cbor.c + ${CARDANO_PATH}/src/crc32.c + ${CARDANO_PATH}/src/crypto.c + ${CARDANO_PATH}/src/deriveAddress.c + ${CARDANO_PATH}/src/deriveNativeScriptHash.c + ${CARDANO_PATH}/src/deriveNativeScriptHash_ui.c + ${CARDANO_PATH}/src/getPublicKeys.c + ${CARDANO_PATH}/src/getPublicKeys_ui.c + ${CARDANO_PATH}/src/getSerial.c + ${CARDANO_PATH}/src/getVersion.c + ${CARDANO_PATH}/src/handlers.c + ${CARDANO_PATH}/src/hexUtils.c + ${CARDANO_PATH}/src/io.c + ${CARDANO_PATH}/src/ipUtils.c + ${CARDANO_PATH}/src/keyDerivation.c + # ${CARDANO_PATH}/src/menu_nanos.c + ${CARDANO_PATH}/src/menu_nanox.c + ${CARDANO_PATH}/src/messageSigning.c + ${CARDANO_PATH}/src/nativeScriptHashBuilder.c + ${CARDANO_PATH}/src/runTests.c + ${CARDANO_PATH}/src/securityPolicy.c + ${CARDANO_PATH}/src/signCVote.c + ${CARDANO_PATH}/src/signCVote_ui.c + ${CARDANO_PATH}/src/signOpCert.c + ${CARDANO_PATH}/src/signTx.c + ${CARDANO_PATH}/src/signTxCVoteRegistration.c + ${CARDANO_PATH}/src/signTxCVoteRegistration_ui.c + ${CARDANO_PATH}/src/signTxMint.c + ${CARDANO_PATH}/src/signTxMint_ui.c + ${CARDANO_PATH}/src/signTxOutput.c + ${CARDANO_PATH}/src/signTxOutput_ui.c + ${CARDANO_PATH}/src/signTxPoolRegistration.c + ${CARDANO_PATH}/src/signTxPoolRegistration_ui.c + ${CARDANO_PATH}/src/signTx_ui.c + ${CARDANO_PATH}/src/signTxUtils.c + ${CARDANO_PATH}/src/state.c + ${CARDANO_PATH}/src/textUtils.c + ${CARDANO_PATH}/src/tokens.c + ${CARDANO_PATH}/src/txHashBuilder.c + ${CARDANO_PATH}/src/uiHelpers.c + ${CARDANO_PATH}/src/uiHelpers_nanos.c + ${CARDANO_PATH}/src/uiHelpers_nanox.c + ${CARDANO_PATH}/src/ui_menu_nbgl.c + ${CARDANO_PATH}/src/ui_nbgl.c + ${CARDANO_PATH}/src/uiScreens_bagl.c + ${CARDANO_PATH}/src/uiScreens_nbgl.c + ${CARDANO_PATH}/src/votecastHashBuilder.c +) + +include_directories( + ${BOLOS_SDK}/include + ${BOLOS_SDK}/target/nanox/include + ${BOLOS_SDK}/lib_cxng/include + ${BOLOS_SDK}/lib_bagl/include + ${BOLOS_SDK}/lib_ux/include + + ${CARDANO_PATH}/src + ./include +) + +add_compile_definitions( + FUZZING + HAVE_BAGL + BAGL_WIDTH=128 + BAGL_HEIGHT=64 + HAVE_UX_FLOW + + MAJOR_VERSION=1 + MINOR_VERSION=1 + PATCH_VERSION=1 + APPVERSION=\"1.1.1\" + + IO_HID_EP_LENGTH=64 + IO_SEPROXYHAL_BUFFER_SIZE_B=300 + OS_IO_SEPROXYHAL + + HAVE_ECC + HAVE_BLAKE2 + HAVE_ECC_WEIERSTRASS + HAVE_SECP256K1_CURVE + HAVE_SECP256R1_CURVE + HAVE_ECC_TWISTED_EDWARDS + HAVE_ED25519_CURVE + HAVE_ECDSA + HAVE_EDDSA + HAVE_HASH + HAVE_SHA256 + HAVE_SHA3 +) + +set(SOURCE + ${UX_SOURCE} + ${CARDANO_SOURCE} + ./src/os_mocks.c + ./src/glyphs.c +) + + +add_library(cardano ${SOURCE}) + +set(harnesses + all_harness + deriveAddress_harness + deriveNativeScriptHash_harness + getPublicKeys_harness + signCVote_harness + signOpCert_harness + signTx_harness +) + +foreach(harness IN LISTS harnesses) + add_executable(${harness} + ./src/${harness}.c + ) + target_link_libraries(${harness} PUBLIC cardano) +endforeach() \ No newline at end of file diff --git a/fuzzing/README.md b/fuzzing/README.md new file mode 100644 index 00000000..a4688c84 --- /dev/null +++ b/fuzzing/README.md @@ -0,0 +1,39 @@ +## Compilation + +In `fuzzing` folder + +``` +cmake -DBOLOS_SDK=/path/to/sdk -DCMAKE_C_COMPILER=/usr/bin/clang -Bbuild -H. +``` + +then + +``` +make -C build +``` + +Harnesses built: +``` +all_harness +deriveAddress_harness +deriveNativeScriptHash_harness +getPublicKeys_harness +signCVote_harness +signOpCert_harness +signTx_harness +``` + +## Run + +To start fuzzing simply do `./build/` where `` is one of the files above. For instance + +``` +./build/deriveAddress_harness +``` + +Since there is an already existing corpus, to start fuzzing with it simply do `./build/ ./corpus` + + + +## Notes +For more context regarding fuzzing check out the app-boilerplate fuzzing [README.md](https://github.com/LedgerHQ/app-boilerplate/blob/master/fuzzing/README.md) diff --git a/fuzz/ref_corpus/signOperationalCertificate b/fuzzing/corpus/signOperationalCertificate similarity index 100% rename from fuzz/ref_corpus/signOperationalCertificate rename to fuzzing/corpus/signOperationalCertificate diff --git a/fuzz/ref_corpus/signTxOrdinaryMary0 b/fuzzing/corpus/signTxOrdinaryMary0 similarity index 100% rename from fuzz/ref_corpus/signTxOrdinaryMary0 rename to fuzzing/corpus/signTxOrdinaryMary0 diff --git a/fuzz/ref_corpus/signTxOrdinaryMary1 b/fuzzing/corpus/signTxOrdinaryMary1 similarity index 100% rename from fuzz/ref_corpus/signTxOrdinaryMary1 rename to fuzzing/corpus/signTxOrdinaryMary1 diff --git a/fuzz/ref_corpus/signTxOrdinaryMary2 b/fuzzing/corpus/signTxOrdinaryMary2 similarity index 100% rename from fuzz/ref_corpus/signTxOrdinaryMary2 rename to fuzzing/corpus/signTxOrdinaryMary2 diff --git a/fuzz/ref_corpus/signTxOrdinaryMary3 b/fuzzing/corpus/signTxOrdinaryMary3 similarity index 100% rename from fuzz/ref_corpus/signTxOrdinaryMary3 rename to fuzzing/corpus/signTxOrdinaryMary3 diff --git a/fuzz/ref_corpus/signTxOrdinaryMary4 b/fuzzing/corpus/signTxOrdinaryMary4 similarity index 100% rename from fuzz/ref_corpus/signTxOrdinaryMary4 rename to fuzzing/corpus/signTxOrdinaryMary4 diff --git a/fuzz/ref_corpus/signTxOrdinaryMary5 b/fuzzing/corpus/signTxOrdinaryMary5 similarity index 100% rename from fuzz/ref_corpus/signTxOrdinaryMary5 rename to fuzzing/corpus/signTxOrdinaryMary5 diff --git a/fuzz/ref_corpus/signTxOrdinaryMary6 b/fuzzing/corpus/signTxOrdinaryMary6 similarity index 100% rename from fuzz/ref_corpus/signTxOrdinaryMary6 rename to fuzzing/corpus/signTxOrdinaryMary6 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOperator0 b/fuzzing/corpus/signTxPoolRegistrationOKOperator0 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOperator0 rename to fuzzing/corpus/signTxPoolRegistrationOKOperator0 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOperator1 b/fuzzing/corpus/signTxPoolRegistrationOKOperator1 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOperator1 rename to fuzzing/corpus/signTxPoolRegistrationOKOperator1 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOperator2 b/fuzzing/corpus/signTxPoolRegistrationOKOperator2 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOperator2 rename to fuzzing/corpus/signTxPoolRegistrationOKOperator2 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOwner0 b/fuzzing/corpus/signTxPoolRegistrationOKOwner0 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOwner0 rename to fuzzing/corpus/signTxPoolRegistrationOKOwner0 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOwner1 b/fuzzing/corpus/signTxPoolRegistrationOKOwner1 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOwner1 rename to fuzzing/corpus/signTxPoolRegistrationOKOwner1 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOwner2 b/fuzzing/corpus/signTxPoolRegistrationOKOwner2 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOwner2 rename to fuzzing/corpus/signTxPoolRegistrationOKOwner2 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOwner3 b/fuzzing/corpus/signTxPoolRegistrationOKOwner3 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOwner3 rename to fuzzing/corpus/signTxPoolRegistrationOKOwner3 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOwner4 b/fuzzing/corpus/signTxPoolRegistrationOKOwner4 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOwner4 rename to fuzzing/corpus/signTxPoolRegistrationOKOwner4 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOwner5 b/fuzzing/corpus/signTxPoolRegistrationOKOwner5 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOwner5 rename to fuzzing/corpus/signTxPoolRegistrationOKOwner5 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOwner6 b/fuzzing/corpus/signTxPoolRegistrationOKOwner6 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOwner6 rename to fuzzing/corpus/signTxPoolRegistrationOKOwner6 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOwner7 b/fuzzing/corpus/signTxPoolRegistrationOKOwner7 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOwner7 rename to fuzzing/corpus/signTxPoolRegistrationOKOwner7 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOwner8 b/fuzzing/corpus/signTxPoolRegistrationOKOwner8 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOwner8 rename to fuzzing/corpus/signTxPoolRegistrationOKOwner8 diff --git a/fuzz/ref_corpus/signtx b/fuzzing/corpus/signtx similarity index 100% rename from fuzz/ref_corpus/signtx rename to fuzzing/corpus/signtx diff --git a/fuzzing/include/glyphs.h b/fuzzing/include/glyphs.h new file mode 100644 index 00000000..1e352b05 --- /dev/null +++ b/fuzzing/include/glyphs.h @@ -0,0 +1,12 @@ +#pragma once +#include +#include + +extern const bagl_icon_details_t C_icon_crossmark; +extern const bagl_icon_details_t C_icon_loader; +extern const bagl_icon_details_t C_icon_eye; +extern const bagl_icon_details_t C_icon_validate_14; +extern const bagl_icon_details_t C_icon_left; +extern const bagl_icon_details_t C_icon_right; +extern const bagl_icon_details_t C_icon_app; +extern const bagl_icon_details_t C_icon_dashboard_x; \ No newline at end of file diff --git a/fuzzing/src/all_harness.c b/fuzzing/src/all_harness.c new file mode 100644 index 00000000..45f8753e --- /dev/null +++ b/fuzzing/src/all_harness.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include + +uint8_t G_io_apdu_buffer[IO_APDU_BUFFER_SIZE]; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + + UX_INIT(); + + uint8_t *input = NULL; + bool is_first = true; + + while (size > 5) { + io_state = IO_EXPECT_NONE; + uint8_t ins = data[0]; + uint8_t p1 = data[1]; + uint8_t p2 = data[2]; + uint8_t lc = data[3]; + + data += sizeof(uint8_t) * 4; + size -= sizeof(uint8_t) * 4; + + if (size < lc) { + return 0; + } + + uint8_t *input = malloc(lc); + if (input == NULL) { + return 0; + } + + memcpy(input, data, lc); + + data += lc; + size -= lc; + + handler_fn_t *handler = lookupHandler(ins); + + if (handler == NULL) { + free(input); + return 0; + } + BEGIN_TRY { + TRY { handler(p1, p2, input, lc, is_first); } + CATCH_ALL {} + FINALLY {} + } + END_TRY; + + is_first = false; + free(input); + } + return 0; +} \ No newline at end of file diff --git a/fuzzing/src/deriveAddress_harness.c b/fuzzing/src/deriveAddress_harness.c new file mode 100644 index 00000000..eece7ada --- /dev/null +++ b/fuzzing/src/deriveAddress_harness.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include +#include + +uint8_t G_io_apdu_buffer[IO_APDU_BUFFER_SIZE]; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + + UX_INIT(); + + uint8_t *input = NULL; + bool is_first = true; + + while (size > 5) { + io_state = IO_EXPECT_NONE; + uint8_t ins = data[0]; + uint8_t p1 = data[1]; + uint8_t p2 = data[2]; + uint8_t lc = data[3]; + + data += sizeof(uint8_t) * 4; + size -= sizeof(uint8_t) * 4; + + if (size < lc) { + return 0; + } + + uint8_t *input = malloc(lc); + if (input == NULL) { + return 0; + } + + memcpy(input, data, lc); + + data += lc; + size -= lc; + + BEGIN_TRY { + TRY { deriveAddress_handleAPDU(p1, p2, input, lc, is_first); } + CATCH_ALL {} + FINALLY {} + } + END_TRY; + + is_first = false; + free(input); + } + return 0; +} \ No newline at end of file diff --git a/fuzzing/src/deriveNativeScriptHash_harness.c b/fuzzing/src/deriveNativeScriptHash_harness.c new file mode 100644 index 00000000..5bc34bde --- /dev/null +++ b/fuzzing/src/deriveNativeScriptHash_harness.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include + +uint8_t G_io_apdu_buffer[IO_APDU_BUFFER_SIZE]; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + + UX_INIT(); + + uint8_t *input = NULL; + bool is_first = true; + + while (size > 5) { + io_state = IO_EXPECT_NONE; + uint8_t ins = data[0]; + uint8_t p1 = data[1]; + uint8_t p2 = data[2]; + uint8_t lc = data[3]; + + data += sizeof(uint8_t) * 4; + size -= sizeof(uint8_t) * 4; + + if (size < lc) { + return 0; + } + + uint8_t *input = malloc(lc); + if (input == NULL) { + return 0; + } + + memcpy(input, data, lc); + + data += lc; + size -= lc; + + BEGIN_TRY { + TRY { deriveNativeScriptHash_handleAPDU(p1, p2, input, lc, is_first); } + CATCH_ALL {} + FINALLY {} + } + END_TRY; + + is_first = false; + free(input); + } + return 0; +} \ No newline at end of file diff --git a/fuzzing/src/getPublicKeys_harness.c b/fuzzing/src/getPublicKeys_harness.c new file mode 100644 index 00000000..204ca81a --- /dev/null +++ b/fuzzing/src/getPublicKeys_harness.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include + +uint8_t G_io_apdu_buffer[IO_APDU_BUFFER_SIZE]; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + + UX_INIT(); + + uint8_t *input = NULL; + bool is_first = true; + + while (size > 5) { + io_state = IO_EXPECT_NONE; + uint8_t ins = data[0]; + uint8_t p1 = data[1]; + uint8_t p2 = data[2]; + uint8_t lc = data[3]; + + data += sizeof(uint8_t) * 4; + size -= sizeof(uint8_t) * 4; + + if (size < lc) { + return 0; + } + + uint8_t *input = malloc(lc); + if (input == NULL) { + return 0; + } + + memcpy(input, data, lc); + + data += lc; + size -= lc; + + BEGIN_TRY { + TRY { getPublicKeys_handleAPDU(p1, p2, input, lc, is_first); } + CATCH_ALL {} + FINALLY {} + } + END_TRY; + + is_first = false; + free(input); + } + return 0; +} \ No newline at end of file diff --git a/fuzzing/src/glyphs.c b/fuzzing/src/glyphs.c new file mode 100644 index 00000000..9d726638 --- /dev/null +++ b/fuzzing/src/glyphs.c @@ -0,0 +1,12 @@ +#include +#include + +const bagl_icon_details_t C_icon_crossmark = {0}; +const bagl_icon_details_t C_icon_loader = {0}; +const bagl_icon_details_t C_icon_eye = {0}; +const bagl_icon_details_t C_icon_validate_14 = {0}; +const bagl_icon_details_t C_icon_left = {0}; +const bagl_icon_details_t C_icon_right = {0}; +const bagl_icon_details_t C_icon_app = {0}; +const bagl_icon_details_t C_icon_dashboard_x = {0}; + diff --git a/fuzzing/src/os_mocks.c b/fuzzing/src/os_mocks.c new file mode 100644 index 00000000..611244a5 --- /dev/null +++ b/fuzzing/src/os_mocks.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include +#include +#include +#include + +void nvm_write(void *dst_adr, void *src_adr, unsigned int src_len) { + memcpy(dst_adr, src_adr, src_len); +} + +unsigned int os_serial(unsigned char *serial, unsigned int maxlength) { + memset(serial, 'A', maxlength); + return maxlength; +} + +void __attribute__((noreturn)) os_sched_exit(bolos_task_status_t exit_code) { + exit(exit_code); +} + +void os_longjmp(unsigned int exception) { + longjmp(try_context_get()->jmp_buf, exception); +} + +try_context_t *current_context = NULL; +try_context_t *try_context_get(void) { return current_context; } + +try_context_t *try_context_set(try_context_t *ctx) { + try_context_t *previous_ctx = current_context; + current_context = ctx; + return previous_ctx; +} + +void *pic(void *linked_addr) { return linked_addr; } +// void ui_idle(){}; +void halt() { + for (;;) + ; +}; +unsigned short io_exchange(unsigned char chan, unsigned short tx_len) { + return 0; +}; +unsigned short io_seph_recv(unsigned char *buffer, unsigned short maxlength, + unsigned int flags) { + return 0; +}; +cx_err_t cx_blake2b_init_no_throw(cx_blake2b_t *hash, size_t size) { + return CX_OK; +}; +cx_err_t cx_hash_no_throw(cx_hash_t *hash, uint32_t mode, const uint8_t *in, + size_t len, uint8_t *out, size_t out_len) { + return CX_OK; +}; +size_t cx_hash_get_size(const cx_hash_t *ctx) { return 32; }; +void io_seph_send(const unsigned char *buffer, unsigned short length){}; +cx_err_t cx_sha3_init_no_throw(cx_sha3_t *hash, size_t size) { return CX_OK; }; +unsigned int io_seph_is_status_sent(void) { return 0; }; +bolos_bool_t os_perso_isonboarded(void) { return (bolos_bool_t)BOLOS_UX_OK; }; +void io_seproxyhal_display_default(const bagl_element_t *bagl) { + if (bagl->text) { + printf("[-] %s\n", bagl->text); + } +} +void io_seproxyhal_init_ux(void){}; +bolos_task_status_t os_sched_last_status(unsigned int task_idx) { return 1; }; +bolos_bool_t os_global_pin_is_validated(void) { + return (bolos_bool_t)BOLOS_UX_OK; +} + +cx_err_t cx_eddsa_get_public_key_no_throw(const cx_ecfp_private_key_t *pv_key, + cx_md_t hashID, + cx_ecfp_public_key_t *pu_key, + uint8_t *a, size_t a_len, uint8_t *h, + size_t h_len) { + pu_key->W_len = 65; + memset(pu_key, 'A', pu_key->W_len); + return CX_OK; +} + +cx_err_t cx_eddsa_sign_no_throw(const cx_ecfp_private_key_t *pvkey, + cx_md_t hashID, const uint8_t *hash, + size_t hash_len, uint8_t *sig, size_t sig_len) { + return CX_OK; +} + +cx_err_t cx_ecdomain_parameters_length(cx_curve_t cv, size_t *length) { + // cardano uses CX_CURVE_Ed25519 + if (cv == CX_CURVE_Ed25519) { + *length = 32; + return CX_OK; + } + + exit(1); + return CX_INVALID_PARAMETER; +} + +void os_perso_derive_node_with_seed_key( + unsigned int mode, cx_curve_t curve, const unsigned int *path, + unsigned int pathLength, unsigned char *privateKey, unsigned char *chain, + unsigned char *seed_key, unsigned int seed_key_length) {} \ No newline at end of file diff --git a/fuzzing/src/signCVote_harness.c b/fuzzing/src/signCVote_harness.c new file mode 100644 index 00000000..e3119912 --- /dev/null +++ b/fuzzing/src/signCVote_harness.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include + +uint8_t G_io_apdu_buffer[IO_APDU_BUFFER_SIZE]; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + + UX_INIT(); + + uint8_t *input = NULL; + bool is_first = true; + + while (size > 5) { + io_state = IO_EXPECT_NONE; + uint8_t ins = data[0]; + uint8_t p1 = data[1]; + uint8_t p2 = data[2]; + uint8_t lc = data[3]; + + data += sizeof(uint8_t) * 4; + size -= sizeof(uint8_t) * 4; + + if (size < lc) { + return 0; + } + + uint8_t *input = malloc(lc); + if (input == NULL) { + return 0; + } + + memcpy(input, data, lc); + + data += lc; + size -= lc; + + BEGIN_TRY { + TRY { signCVote_handleAPDU(p1, p2, input, lc, is_first); } + CATCH_ALL {} + FINALLY {} + } + END_TRY; + + is_first = false; + free(input); + } + return 0; +} \ No newline at end of file diff --git a/fuzzing/src/signOpCert_harness.c b/fuzzing/src/signOpCert_harness.c new file mode 100644 index 00000000..eb89f8f0 --- /dev/null +++ b/fuzzing/src/signOpCert_harness.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include + +uint8_t G_io_apdu_buffer[IO_APDU_BUFFER_SIZE]; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + + UX_INIT(); + + uint8_t *input = NULL; + bool is_first = true; + + while (size > 5) { + io_state = IO_EXPECT_NONE; + uint8_t ins = data[0]; + uint8_t p1 = data[1]; + uint8_t p2 = data[2]; + uint8_t lc = data[3]; + + data += sizeof(uint8_t) * 4; + size -= sizeof(uint8_t) * 4; + + if (size < lc) { + return 0; + } + + uint8_t *input = malloc(lc); + if (input == NULL) { + return 0; + } + + memcpy(input, data, lc); + + data += lc; + size -= lc; + + BEGIN_TRY { + TRY { signOpCert_handleAPDU(p1, p2, input, lc, is_first); } + CATCH_ALL {} + FINALLY {} + } + END_TRY; + + is_first = false; + free(input); + } + return 0; +} \ No newline at end of file diff --git a/fuzzing/src/signTx_harness.c b/fuzzing/src/signTx_harness.c new file mode 100644 index 00000000..48a4c624 --- /dev/null +++ b/fuzzing/src/signTx_harness.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include + +uint8_t G_io_apdu_buffer[IO_APDU_BUFFER_SIZE]; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + + UX_INIT(); + + uint8_t *input = NULL; + bool is_first = true; + + while (size > 5) { + io_state = IO_EXPECT_NONE; + uint8_t ins = data[0]; + uint8_t p1 = data[1]; + uint8_t p2 = data[2]; + uint8_t lc = data[3]; + + data += sizeof(uint8_t) * 4; + size -= sizeof(uint8_t) * 4; + + if (size < lc) { + return 0; + } + + uint8_t *input = malloc(lc); + if (input == NULL) { + return 0; + } + + memcpy(input, data, lc); + + data += lc; + size -= lc; + + BEGIN_TRY { + TRY { signTx_handleAPDU(p1, p2, input, lc, is_first); } + CATCH_ALL {} + FINALLY {} + } + END_TRY; + + is_first = false; + free(input); + } + return 0; +} \ No newline at end of file diff --git a/src/bip44.c b/src/bip44.c index 9f6b62a9..883a98e9 100644 --- a/src/bip44.c +++ b/src/bip44.c @@ -4,9 +4,9 @@ #include "hash.h" #include "keyDerivation.h" -static const uint32_t CARDANO_CHAIN_EXTERNAL = 0; -static const uint32_t CARDANO_CHAIN_INTERNAL = 1; -static const uint32_t CARDANO_CHAIN_STAKING_KEY = 2; +#define CARDANO_CHAIN_EXTERNAL 0 +#define CARDANO_CHAIN_INTERNAL 1 +#define CARDANO_CHAIN_STAKING_KEY 2 static const uint32_t MAX_REASONABLE_ACCOUNT = 100; static const uint32_t MAX_REASONABLE_ADDRESS = 1000000; diff --git a/src/keyDerivation.c b/src/keyDerivation.c index 6e820042..5f733f71 100644 --- a/src/keyDerivation.c +++ b/src/keyDerivation.c @@ -49,7 +49,6 @@ void deriveExtendedPublicKey( // if the path is invalid, it's a bug in previous validation ASSERT(policyForDerivePrivateKey(pathSpec) != POLICY_DENY); - #ifndef FUZZING { cx_err_t error = crypto_get_pubkey(pathSpec->path, pathSpec->length, @@ -60,7 +59,6 @@ void deriveExtendedPublicKey( ASSERT(false); } } - #endif extractRawPublicKey(rawPubkey, out->pubKey, SIZEOF(out->pubKey)); diff --git a/src/uiHelpers.h b/src/uiHelpers.h index b7627844..bc6c8eb9 100644 --- a/src/uiHelpers.h +++ b/src/uiHelpers.h @@ -42,7 +42,7 @@ extern bolos_ux_params_t G_ux_params; #define UI_STEP(NEXT_STEP) \ *__ui_step_ptr = NEXT_STEP; \ } \ - __attribute__((fallthrough)); + __attribute__((fallthrough)); \ case NEXT_STEP: { #else #define UI_STEP(NEXT_STEP) \ diff --git a/src/uiScreens_bagl.c b/src/uiScreens_bagl.c index 0c2791a7..1e158a0c 100644 --- a/src/uiScreens_bagl.c +++ b/src/uiScreens_bagl.c @@ -768,7 +768,9 @@ void ui_displayPoolRelayScreen( char firstLine[20] = {0}; explicit_bzero(firstLine, SIZEOF(firstLine)); { + #ifndef FUZZING STATIC_ASSERT(sizeof(relayIndex + 1) <= sizeof(unsigned), "oversized type for %u"); + #endif STATIC_ASSERT(!IS_SIGNED(relayIndex + 1), "signed type for %u"); // indexed from 0 as discussed with IOHK on Slack snprintf(firstLine, SIZEOF(firstLine), "Relay #%u", relayIndex); diff --git a/src/utils.h b/src/utils.h index a8be7df5..7d54ec09 100644 --- a/src/utils.h +++ b/src/utils.h @@ -17,6 +17,7 @@ #define ARRAY_LEN(arr) \ (sizeof(arr) / sizeof((arr)[0]) + ARRAY_NOT_A_PTR(arr)) +#ifndef FUZZING // Does not compile if x *might* be a pointer of some kind // Might produce false positives on small structs... // Note: ARRAY_NOT_A_PTR does not compile if arg is a struct so this is a workaround @@ -27,6 +28,9 @@ #define SIZEOF(var) \ (sizeof(var) + SIZEOF_NOT_A_PTR(var)) +#else +#define SIZEOF(var) sizeof(var) +#endif #define ASSERT_TYPE(expr, expected_type) \ STATIC_ASSERT( \