-
Notifications
You must be signed in to change notification settings - Fork 82
Gjo fuzzing template #180
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
Gustavo-Jodar
wants to merge
31
commits into
master
Choose a base branch
from
gjo_fuzzing_template
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Gjo fuzzing template #180
Changes from all commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
9faf339
Update CMakeLists to use Fuzzing Framework
154681b
Update README
06a761e
Add macro generation code
2443964
Add specific mocks
1a795eb
Add run script
eb8a40c
Update harnesses
3b73ef6
Simplified version of macros generation
5eb1e12
Move context functions to app mocks.h
054865d
Delete fuzzing/macros/generated/macros.txt
Gustavo-Jodar 766a9d4
Delete fuzzing/macros/generated/used_macros.json
Gustavo-Jodar 1ac8d25
Ignore generated macros and verify if macros/generated exists
43ad9ef
Ignore generated macros and verify if macros/generated exists
e5e395b
Simplify local_run and CMakeLists
46f416b
CLang format
cc567bd
Fix try_context os_long_jump mock
9ec1455
Minor fixes for long_jump_mock
4b8c174
Remove unused variables
acab7fb
Use sigsetjmp
2e66a0d
Add custom_macros command
00497f2
Use the interface from the sdk and make it more simple
e5d5019
Move harness to folder
2888dc8
pre-commit
9130cb7
move to harness
8536afa
Improve structure of framework
a94414a
Exclude USE_OS_IO_STACK macro
3a277cb
Update READMe.md
5e85d76
Update clusterFuzz
db2e8a4
Update README
c53f23a
remove casting warning
29ef6a8
Use macro USE_OS_IO_STACK
ced17aa
cast to handle warning
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,14 +1,17 @@ | ||
| FROM ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest AS LITE_BUILDER | ||
| FROM ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools:latest AS app-builder | ||
|
|
||
| # Base image with clang toolchain | ||
| FROM gcr.io/oss-fuzz-base/base-builder:v1 | ||
|
|
||
| RUN pip3 install --break-system-packages --no-cache-dir pillow>=3.4.0 | ||
| RUN apt update && apt install -y ninja-build zip | ||
|
|
||
| # Copy the project's source code. | ||
| COPY . $SRC/app-boilerplate | ||
| COPY --from=LITE_BUILDER /opt/ledger-secure-sdk $SRC/app-boilerplate/BOLOS_SDK | ||
| COPY . /app | ||
| COPY --from=app-builder /opt/flex-secure-sdk /ledger-secure-sdk | ||
|
|
||
| # Working directory for build.sh | ||
| WORKDIR $SRC/app-boilerplate | ||
| WORKDIR /app | ||
|
|
||
| # Copy build.sh into $SRC dir. | ||
| COPY ./.clusterfuzzlite/build.sh $SRC/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,48 +1,53 @@ | ||
| cmake_minimum_required(VERSION 3.10) | ||
| include_guard() | ||
| cmake_minimum_required(VERSION 3.14) | ||
|
|
||
| if(${CMAKE_VERSION} VERSION_LESS 3.10) | ||
| cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) | ||
| if(${CMAKE_VERSION} VERSION_LESS 3.14) | ||
| cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) | ||
| endif() | ||
|
|
||
| # project information | ||
| project(FuzzTxParser | ||
| VERSION 1.0 | ||
| DESCRIPTION "Fuzzing of transaction parser" | ||
| LANGUAGES C) | ||
|
|
||
| # guard against bad build-type strings | ||
| if (NOT CMAKE_BUILD_TYPE) | ||
| set(CMAKE_BUILD_TYPE "Debug") | ||
| endif() | ||
|
|
||
| if (NOT CMAKE_C_COMPILER_ID MATCHES "Clang") | ||
| message(FATAL_ERROR "Fuzzer needs to be built with Clang") | ||
| endif() | ||
|
|
||
| if (NOT DEFINED BOLOS_SDK) | ||
| message(FATAL_ERROR "BOLOS_SDK environment variable not found.") | ||
| endif() | ||
| project( | ||
| BoilerPlateFuzzer | ||
| VERSION 1.0 | ||
| DESCRIPTION "App Boilerplate example Fuzzer" | ||
| LANGUAGES C) | ||
|
|
||
| # 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() | ||
| set(DEFINES FUZZ) | ||
|
|
||
| # compatible with ClusterFuzzLite | ||
| if (NOT DEFINED ENV{LIB_FUZZING_ENGINE}) | ||
| set(COMPILATION_FLAGS_ "-g -Wall -fsanitize=fuzzer,address,undefined") | ||
| else() | ||
| set(COMPILATION_FLAGS_ "$ENV{LIB_FUZZING_ENGINE} $ENV{CXXFLAGS}") | ||
| if(NOT DEFINED BOLOS_SDK) | ||
| message(FATAL_ERROR "BOLOS_SDK must be defined, CMake will exit.") | ||
| return() | ||
| endif() | ||
|
|
||
| set(CMAKE_EXPORT_COMPILE_COMMANDS ON) | ||
|
|
||
| string(REPLACE " " ";" COMPILATION_FLAGS ${COMPILATION_FLAGS_}) | ||
|
|
||
| include(extra/TxParser.cmake) | ||
|
|
||
| add_executable(fuzz_tx_parser fuzz_tx_parser.c) | ||
|
|
||
| target_compile_options(fuzz_tx_parser PUBLIC ${COMPILATION_FLAGS}) | ||
| target_link_options(fuzz_tx_parser PUBLIC ${COMPILATION_FLAGS}) | ||
| target_link_libraries(fuzz_tx_parser PUBLIC txparser) | ||
| add_subdirectory(${BOLOS_SDK}/fuzzing ${CMAKE_CURRENT_BINARY_DIR}/ledger-secure-sdk EXCLUDE_FROM_ALL) | ||
|
|
||
| file(GLOB_RECURSE C_SOURCES "${CMAKE_SOURCE_DIR}/../src/*.c" "${CMAKE_SOURCE_DIR}/mock/*.c") | ||
| list(REMOVE_ITEM C_SOURCES "${CMAKE_SOURCE_DIR}/../src/app_main.c") | ||
|
|
||
| add_library(code_lib ${C_SOURCES}) | ||
|
|
||
| target_include_directories( | ||
| code_lib | ||
| PUBLIC ${CMAKE_SOURCE_DIR}/../src/ | ||
| ${CMAKE_SOURCE_DIR}/../src/apdu/ | ||
| ${CMAKE_SOURCE_DIR}/../src/swap/ | ||
| ${CMAKE_SOURCE_DIR}/../src/handler/ | ||
| ${CMAKE_SOURCE_DIR}/../src/helper/ | ||
| ${CMAKE_SOURCE_DIR}/../src/transaction/ | ||
| ${CMAKE_SOURCE_DIR}/../src/ui/ | ||
| ${CMAKE_SOURCE_DIR}/../src/ui/action/ | ||
| ${CMAKE_SOURCE_DIR}/mock/ | ||
| ${CMAKE_SOURCE_DIR}/) | ||
|
|
||
| target_link_libraries(code_lib PUBLIC secure_sdk) | ||
| target_compile_definitions(code_lib PUBLIC ${DEFINES} FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1) | ||
|
|
||
| # fuzz_dispatcher | ||
| add_executable(fuzz_dispatcher "${CMAKE_SOURCE_DIR}/harness/fuzz_dispatcher.c") | ||
| target_compile_definitions(fuzz_dispatcher PUBLIC macros FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1) | ||
| target_link_libraries(fuzz_dispatcher PUBLIC secure_sdk code_lib) | ||
|
|
||
| # fuzz_tx_parser | ||
| add_executable(fuzz_tx_parser "${CMAKE_SOURCE_DIR}/harness/fuzz_tx_parser.c") | ||
| target_compile_definitions(fuzz_tx_parser PUBLIC macros FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1) | ||
| target_link_libraries(fuzz_tx_parser PUBLIC secure_sdk code_lib) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,72 +1,126 @@ | ||
| <!-- markdownlint-disable MD013 --> | ||
|
|
||
| # Fuzzing on transaction parser | ||
|
|
||
| ## Fuzzing | ||
|
|
||
| Fuzzing allows us to test how a program behaves when provided with invalid, unexpected, or random data as input. | ||
| Fuzzing allows us to test how a program behaves when provided with invalid, unexpected, or random | ||
| data as input. | ||
|
|
||
| In the case of the harness `fuzz_tx_parser.c`, we want to test the code that is responsible for | ||
| parsing the transaction data, which is `transaction_deserialize()`. | ||
|
|
||
| To test `transaction_deserialize()`, our fuzz target, `fuzz_tx_parser.c`, needs to implement | ||
| `int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)`, which provides an array of random | ||
| bytes that can be used to simulate a serialized transaction. | ||
|
|
||
| In the case of `app-boilerplate` we want to test the code that is responsible for parsing the transaction data, | ||
| which is `transaction_deserialize()`. | ||
| To test `transaction_deserialize()`, our fuzz target, `fuzz_tx_parser.c`, | ||
| needs to implement `int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)`, | ||
| which provides an array of random bytes that can be used to simulate a serialized transaction. | ||
| If the application crashes, or a [sanitizer](https://github.com/google/sanitizers) detects any kind of | ||
| access violation, the fuzzing process is stopped, a report regarding the vulnerability is shown, | ||
| If the application crashes, or a [sanitizer](https://github.com/google/sanitizers) detects any kind | ||
| of access violation, the fuzzing process is stopped, a report regarding the vulnerability is shown, | ||
| and the input that triggered the bug is written to disk under the name `crash-*`. | ||
|
|
||
| The vulnerable input file created can be passed as an argument to the fuzzer to triage the issue. | ||
|
|
||
| > **Note**: Usually we want to write a separate fuzz target for each functionality. | ||
|
|
||
| However, it is also possible to target the main function/dispatcher, so that we can cover more code, | ||
| as it is done in `fuzz_dispatcher.c`. | ||
|
|
||
| ## Manual usage based on Ledger container | ||
|
|
||
| ### Preparation | ||
|
|
||
| The fuzzer can run from the docker `ledger-app-builder-legacy`. You can download it from the `ghcr.io` docker repository: | ||
| The fuzzer can be run using the Docker image `ledger-app-dev-tools`. You can download it from the | ||
| `ghcr.io` docker repository: | ||
|
|
||
| ```console | ||
| sudo docker pull ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-legacy:latest | ||
| ```bash | ||
| docker pull ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools:latest | ||
| ``` | ||
|
|
||
| You can then enter this development environment by executing the following command from the repository root directory: | ||
| You can then enter this development environment by executing the following command from the | ||
| repository root directory: | ||
|
|
||
| ```console | ||
| sudo docker run --rm -ti --user "$(id -u):$(id -g)" -v "$(realpath .):/app" ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-legacy:latest | ||
| ```bash | ||
| docker run --rm -ti -v "$(realpath .):/app" ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools:latest | ||
| ``` | ||
|
|
||
| ### Compilation | ||
| ### Writing your Harness | ||
|
|
||
| Once in the container, go into the `fuzzing` folder to compile the fuzzer: | ||
| When writing your harness, keep the following points in mind: | ||
|
|
||
| ```console | ||
| cd fuzzing | ||
| - An SDK's interface for compilation is provided via the target `secure_sdk` in CMakeLists.txt | ||
| - If you are running it for the first time, consider using the script `local_run` from inside the | ||
| Docker container using the flag build=1, if you need to manually | ||
| add/remove macros you can then do it using the files macros/add_macros.txt or | ||
| macros/exclude_macros.txt and rerunning it, or directly change the macros/generated/macros.txt. | ||
| - A typical harness looks like this: | ||
|
|
||
| # cmake initialization | ||
| cmake -DBOLOS_SDK=/opt/ledger-secure-sdk -DCMAKE_C_COMPILER=/usr/bin/clang -Bbuild -H. | ||
| ```C | ||
|
|
||
| # Fuzzer compilation | ||
| make -C build | ||
| ``` | ||
| int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { | ||
| if (sigsetjmp(fuzz_exit_jump_ctx.jmp_buf, 1)) return 0; | ||
|
|
||
| ### Run | ||
| ### harness code ### | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| ``` | ||
|
|
||
| ```console | ||
| ./build/fuzz_tx_parser | ||
| This allows a return point when the `os_sched_exit()` function is mocked. | ||
|
|
||
| - To provide an SDK interface, we automatically generate syscall mock functions located in | ||
| `SECURE_SDK_PATH/fuzzing/mock/generated/generated_syscalls.c`, if you need a more specific mock, | ||
| you can define it in `APP_PATH/fuzzing/mock` with the same name and without the WEAK attribute. | ||
|
|
||
| ### Compile and run the fuzzer from the container | ||
|
|
||
| Once inside the container, navigate to the `fuzzing` folder to compile the fuzzer: | ||
|
|
||
| ```bash | ||
| export BOLOS_SDK=/opt/flex-secure-sdk | ||
|
|
||
| cd fuzzing | ||
|
|
||
| ${BOLOS_SDK}/fuzzing/local_run.sh --build=1 \ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be rather use the script from the SDK? |
||
| --BOLOS_SDK=${BOLOS_SDK} \ | ||
| --fuzzer=build/fuzz_dispatcher \ | ||
| --j=4 \ | ||
| --run-fuzzer=1 \ | ||
| --compute-coverage=1 | ||
| ``` | ||
|
|
||
| ## Full usage based on `clusterfuzzlite` container | ||
| ### About local_run.sh | ||
|
|
||
| | Parameter | Type | Description | | ||
| | :--------------------- | :------------------ | :------------------------------------------------------------------- | | ||
| | `--BOLOS_SDK` | `PATH TO BOLOS SDK` | **Required**. Path to the BOLOS SDK | | ||
| | `--build` | `bool` | **Optional**. Whether to build the project (default: 0) | | ||
| | `--fuzzer` | `PATH` | **Required**. Path to the fuzzer binary | | ||
| | `--compute-coverage` | `bool` | **Optional**. Whether to compute coverage after fuzzing (default: 0) | | ||
| | `--run-fuzzer` | `bool` | **Optional**. Whether to run or not the fuzzer (default: 0) | | ||
| | `--run-crash` | `FILENAME` | **Optional**. Run the on a specific crash input file (default: 0) | | ||
| | `--sanitizer` | `address or memory` | **Optional**. Compile with sanitizer (default: address) | | ||
| | `--j` | `int` | **Optional**. N-parallel jobs for build and fuzzing (default: 1) | | ||
| | `--help` | | **Optional**. Display help message | | ||
|
|
||
| ### Visualizing code coverage | ||
|
|
||
| After running your fuzzer, if `--compute-coverage=1` the coverage will be available in your browser. | ||
|
|
||
| ## Full usage based on `clusterfuzzlite` container - TODO after SDK FUZZING RELEASE | ||
|
|
||
| Exactly the same context as the CI, directly using the `clusterfuzzlite` environment. | ||
|
|
||
| More info can be found here: | ||
| <https://google.github.io/clusterfuzzlite/> | ||
| More info can be found here: <https://google.github.io/clusterfuzzlite/> | ||
|
|
||
| ### Preparation | ||
|
|
||
| The principle is to build the container, and run it to perform the fuzzing. | ||
|
|
||
| > **Note**: The container contains a copy of the sources (they are not cloned), | ||
| > which means the `docker build` command must be re-executed after each code modification. | ||
| > **Note**: The container contains a copy of the sources (they are not cloned), which means the | ||
| > `docker build` command must be re-executed after each code modification. | ||
|
|
||
| ```console | ||
| ```bash | ||
| # Prepare directory tree | ||
| mkdir fuzzing/{corpus,out} | ||
| # Container generation | ||
|
|
@@ -75,12 +129,14 @@ docker build -t app-boilerplate --file .clusterfuzzlite/Dockerfile . | |
|
|
||
| ### Compilation | ||
|
|
||
| ```console | ||
| ```bash | ||
| docker run --rm --privileged -e FUZZING_LANGUAGE=c -v "$(realpath .)/fuzzing/out:/out" -ti app-boilerplate | ||
| ``` | ||
|
|
||
| ### Run | ||
|
|
||
| ```console | ||
| docker run --rm --privileged -e FUZZING_ENGINE=libfuzzer -e RUN_FUZZER_MODE=interactive -v "$(realpath .)/fuzzing/corpus:/tmp/fuzz_corpus" -v "$(realpath .)/fuzzing/out:/out" -ti gcr.io/oss-fuzz-base/base-runner run_fuzzer fuzz_tx_parser | ||
| ```bash | ||
| docker run --rm --privileged -e FUZZING_ENGINE=libfuzzer -e RUN_FUZZER_MODE=interactive -v | ||
| "$(realpath .)/fuzzing/corpus:/tmp/fuzz_corpus" -v "$(realpath .)/fuzzing/out:/out" | ||
| -ti gcr.io/oss-fuzz-base/base-runner run_fuzzer fuzz_tx_parser | ||
| ``` | ||
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not calling here directly the
build.shfrom the SDK? It seems it is a duplicate file 🤔 ?