Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
4a3c193
Replace tests/fuzzing with Absolution-based fuzzing/
N3ur0sis Apr 17, 2026
d1bdd0b
Add fuzzing state-init hooks under HAVE_AUTOAPPROVE_FOR_PERF_TESTS
N3ur0sis Apr 17, 2026
6403c24
Expose tlv_cleanup() helper in tlv_apdu
N3ur0sis Apr 17, 2026
7b42d40
Harden unreachable-via-APDU paths against corrupted state
N3ur0sis Apr 17, 2026
f6259bf
Avoid signed-int shift UB in rlp_decode_length
N3ur0sis Apr 17, 2026
7b59c71
Migrate fuzzing to SDK-native ledger_fuzz_add_app_target
N3ur0sis Apr 20, 2026
4c70d08
Guard memcpy and memmove against NULL TLV value pointers
N3ur0sis Apr 20, 2026
0fcf88f
Compute EIP-155 v-byte in 64-bit with explicit truncation
N3ur0sis Apr 20, 2026
c977f0f
Validate wire-side sizes before narrowing to internal types
N3ur0sis Apr 20, 2026
0662ff5
Widen duration days and guard datetime timestamp narrowing
N3ur0sis Apr 20, 2026
899666e
Make path array/slice start/end sign-change explicit
N3ur0sis Apr 20, 2026
5f34f50
Widen v-byte parity and xGTn adjustment to avoid narrowing UB
N3ur0sis Apr 20, 2026
aec843c
fuzzing: use fuzz_tlv_dispatch_mutate helper and add optional SIGUSR1…
N3ur0sis Apr 28, 2026
6229e0d
fuzzing: promote base corpus and align docs/manifest
N3ur0sis May 4, 2026
5e7321f
Merge origin/develop into aymeric-wip
N3ur0sis May 4, 2026
54d6aee
fuzzing: promote latest base corpus
N3ur0sis May 4, 2026
b7c0dfe
fuzzing: update harness architecture and separation of concern
N3ur0sis May 4, 2026
bcfc69d
chore: ignore compile_commands.json
N3ur0sis May 6, 2026
393e530
refactor: replace app-side #ifdef fuzz gates with link-time mocks and…
N3ur0sis May 13, 2026
f9113f4
fix: realign app sources before fuzz PR merge
N3ur0sis May 13, 2026
86f555c
Merge remote-tracking branch 'origin/develop' into aymeric-wip
N3ur0sis May 13, 2026
881bcf1
fix: stabilize ethereum fuzzing after develop merge
N3ur0sis May 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
9 changes: 5 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ __version__.py
.idea

# Fuzzing
tests/fuzzing/corpus/
tests/fuzzing/out/
tests/fuzzing/CMakeFiles/
tests/fuzzing/macros/generated/
fuzzing/build/
fuzzing/corpus/
fuzzing/out/
.fuzz-artifacts/

default.profraw
default.profdata
Expand All @@ -33,6 +33,7 @@ report.html

# LSP
.cache/
compile_commands.json

# Doxygen
doxygen/
120 changes: 120 additions & 0 deletions fuzzing/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
include_guard()
cmake_minimum_required(VERSION 3.14)

if(${CMAKE_VERSION} VERSION_LESS 3.14)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
endif()

project(
EthereumAppFuzzer
VERSION 1.0
DESCRIPTION "Ledger Ethereum App Fuzzer"
LANGUAGES C)

if(NOT DEFINED BOLOS_SDK)
message(FATAL_ERROR "BOLOS_SDK must be defined, CMake will exit.")
return()
endif()

include(${BOLOS_SDK}/fuzzing/cmake/LedgerAppFuzz.cmake)
ledger_fuzz_setup()
find_package(Python3 COMPONENTS Interpreter REQUIRED)

set(APP_SOURCE_DIR ${CMAKE_SOURCE_DIR}/..)
set(COVERAGE_SIGUSR1_SOURCE "${CMAKE_SOURCE_DIR}/mock/coverage_sigusr1.c")
set(FUZZ_SUPPORT_SOURCES
"${CMAKE_SOURCE_DIR}/harness/fuzz_apdu_adapter.c"
"${CMAKE_SOURCE_DIR}/harness/fuzz_apdu_dispatch.c"
"${CMAKE_SOURCE_DIR}/harness/fuzz_command_registry.c"
"${CMAKE_SOURCE_DIR}/harness/fuzz_non_apdu.c"
"${CMAKE_SOURCE_DIR}/harness/fuzz_tlv_config.c"
)

execute_process(
COMMAND
${Python3_EXECUTABLE}
"${CMAKE_SOURCE_DIR}/scripts/check_dispatch_conformance.py"
--main "${APP_SOURCE_DIR}/src/main.c"
--dispatch "${CMAKE_SOURCE_DIR}/harness/fuzz_apdu_dispatch.c"
--constants "${APP_SOURCE_DIR}/src/apdu_constants.h"
--manifest "${CMAKE_SOURCE_DIR}/fuzz-manifest.toml"
RESULT_VARIABLE ETH_FUZZ_CONFORMANCE_RESULT
OUTPUT_VARIABLE ETH_FUZZ_CONFORMANCE_STDOUT
ERROR_VARIABLE ETH_FUZZ_CONFORMANCE_STDERR
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_STRIP_TRAILING_WHITESPACE
)
if(NOT ETH_FUZZ_CONFORMANCE_RESULT EQUAL 0)
message(FATAL_ERROR
"Ethereum fuzz dispatch conformance check failed:\n"
"${ETH_FUZZ_CONFORMANCE_STDOUT}\n${ETH_FUZZ_CONFORMANCE_STDERR}")
elseif(ETH_FUZZ_CONFORMANCE_STDOUT)
message(STATUS "${ETH_FUZZ_CONFORMANCE_STDOUT}")
endif()

# Glob all app and plugin SDK sources
file(GLOB_RECURSE C_SOURCES
"${APP_SOURCE_DIR}/src/*.c"
"${APP_SOURCE_DIR}/ethereum-plugin-sdk/src/*.c"
"${CMAKE_SOURCE_DIR}/mock/*.c"
)
list(REMOVE_ITEM C_SOURCES "${COVERAGE_SIGUSR1_SOURCE}")

# Exclude main entry points, generated-file dependents, and files replaced by
# link-time mock overrides.
list(REMOVE_ITEM C_SOURCES
"${APP_SOURCE_DIR}/src/main.c"
"${APP_SOURCE_DIR}/ethereum-plugin-sdk/src/main.c"
"${APP_SOURCE_DIR}/src/nbgl/network_icons.c"
"${APP_SOURCE_DIR}/src/nbgl/ui_safe_account.c"
"${APP_SOURCE_DIR}/src/ledger_pki.c"
)

# Dynamically discover ALL include directories from app headers
file(GLOB_RECURSE _all_hdrs
"${APP_SOURCE_DIR}/src/*.h"
"${APP_SOURCE_DIR}/ethereum-plugin-sdk/src/*.h"
)
set(_inc_dirs "")
foreach(_h ${_all_hdrs})
get_filename_component(_d ${_h} DIRECTORY)
list(APPEND _inc_dirs ${_d})
endforeach()
list(REMOVE_DUPLICATES _inc_dirs)

set(_fuzz_extra_sources "")
if(FUZZ_ENABLE_SOURCE_COVERAGE AND EXISTS "${COVERAGE_SIGUSR1_SOURCE}")
list(APPEND _fuzz_extra_sources "${COVERAGE_SIGUSR1_SOURCE}")
message(STATUS "Ethereum fuzz build: SIGUSR1 coverage dump hook enabled")
endif()

ledger_fuzz_add_app_target(
SOURCES
${C_SOURCES}
${FUZZ_SUPPORT_SOURCES}
${_fuzz_extra_sources}
EXTRA_TARGETS
${LEDGER_FUZZ_TLV_MUTATOR_SOURCE}
INCLUDE_DIRECTORIES
${_inc_dirs}
${CMAKE_SOURCE_DIR}/mock/
${CMAKE_SOURCE_DIR}/harness/
${CMAKE_SOURCE_DIR}/
COMPILE_DEFINITIONS
IS_NOT_A_PLUGIN
HAVE_ETH2
HAVE_SWAP
HAVE_SDK_LL_LIB
HAVE_BOLOS_APP_STACK_CANARY
HAVE_GATING_SUPPORT
HAVE_TRANSACTION_CHECKS
HAVE_EIP7702_WHITELIST_TEST
HAVE_DYNAMIC_ALLOC
APPNAME="Ethereum"
APP_TICKER="ETH"
APP_CHAIN_ID=1
APP_COIN_TYPE=60
CX_ECDSA_SHA256_SIG_MAX_ASN1_LENGTH=72
CX_ECDSA_SHA256_SIG_MIN_ASN1_LENGTH=70
CX_SECP256_PUB_KEY_SIZE=65
)
162 changes: 162 additions & 0 deletions fuzzing/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# Ethereum App Fuzzing

Absolution-based fuzzing for the Ledger Ethereum app. The canonical path stays
fuzz-only: `fuzz_harness_entry()` restores the prefix, picks one fuzz command,
rewraps it as a real APDU buffer, runs `apdu_parser()`, and then dispatches
through a fuzz-side APDU mirror that is checked against production `main.c` at
configure time. Supplemental non-APDU coverage surfaces (swap helpers, plugin
utils) live in a separate fuzz-only extension module instead of inside the main
APDU dispatcher.

## Prerequisites

- `BOLOS_SDK` set to a checkout of the Ledger Secure SDK that contains the
fuzzing framework.
- Clang ≥ 14 with `llvm-profdata` and `llvm-cov` for coverage reports.
- The SDK's `ledger_fuzz_setup()` step fetches Absolution automatically on the
first configure. Set `LEDGER_FUZZ_ABSOLUTION_LOCAL_DIR` if you want to point
the build at a local Absolution install instead.

## Run it

From the workspace root:

```bash
BOLOS_SDK=$(pwd)/ledger-secure-sdk \
"$BOLOS_SDK"/fuzzing/scripts/app-campaign.sh \
--app-dir "$(pwd)/app-ethereum" ethereum-smoke
```

- `ethereum-smoke` is the optional campaign name. Omit it to let the SDK script
pick a UTC timestamp under `.fuzz-artifacts/`.
- The command builds the app, syncs the invariant, updates
`mock/scenario_layout.h`, generates seeds, runs fuzzing, and writes coverage.
- The promoted base corpus at `fuzzing/base-corpus/` is folded into the
bootstrap corpus automatically when it exists and its `.compat-key` matches
the current build.

### Useful overrides

| Variable / flag | Default | Meaning |
|--------------------|---------|---------|
| `WARMUP_SEC` | `30` | Warmup seconds per worker |
| `MAIN_SEC` | `60` | Main phase seconds per worker |
| `WORKERS` | `min(2, nproc)` | Parallel LibFuzzer workers |
| `EXTRA_CORPUS` | unset | Colon-separated extra corpus dirs merged into bootstrap |
| `BASE_CORPUS_DIR` | `fuzzing/base-corpus` if present | Promoted seeds; `BASE_CORPUS_DIR=` skips |
| `BUILD_JOBS` | CPU-based | Parallel compile jobs |
| `OVERWRITE=1` | unset | Replace an existing `.fuzz-artifacts/<name>/` |
| `--clean` | off | Wipe build dirs before configure |

## Architecture

The fuzz integration is intentionally split so `app-ethereum/src/` stays
untouched:

- `harness/fuzz_dispatcher.c` is the tiny boundary file required by the SDK.
- `harness/fuzz_command_registry.*` is the single source of truth for command
indices, canonical APDU vs extension grouping, and TLV grammar selection.
- `harness/fuzz_apdu_adapter.c` re-encodes the selected fuzz command as a real
APDU buffer and runs `apdu_parser()` before local dispatch.
- `harness/fuzz_apdu_dispatch.c` mirrors the production APDU switch for the
canonical app entry surface only.
- `harness/fuzz_non_apdu.c` contains the fuzz-only swap/plugin helper shims.
- `harness/fuzz_tlv_config.c` contains the TLV grammar-aware mutator setup.
- `mock/app_runtime.c` owns the globals that normally come from excluded
`src/main.c` and performs the per-iteration runtime reset.

`scripts/check_dispatch_conformance.py` runs during CMake configure and fails
the fuzz build if the canonical fuzz APDU inventory drifts from
`src/main.c`, `src/apdu_constants.h`, or `fuzz-manifest.toml`.

## Files

| Path | Purpose |
|---|---|
| `fuzz-manifest.toml` | App-local config: CLA/INS list, coverage files, dictionary, seed strategy |
| `CMakeLists.txt` | App sources, explicit fuzz support sources, and the build-time conformance check |
| `harness/fuzz_dispatcher.c` | Thin SDK boundary: mutator hook, reset hook, dispatch hook, `fuzz_entry()` |
| `harness/fuzz_command_registry.*` | Canonical fuzz command list shared by C harness code and Python seed tooling |
| `harness/fuzz_apdu_adapter.c` | APDU re-encoding plus `apdu_parser()` fidelity step |
| `harness/fuzz_apdu_dispatch.c` | Canonical APDU-only fuzz dispatch mirror |
| `harness/fuzz_non_apdu.c` | Supplemental swap/plugin helper coverage surfaces |
| `harness/fuzz_tlv_config.c` | TLV tag grammars and custom mutator wiring |
| `mock/mocks.h` / `mock/mocks.c` | Engine globals, exit jump buffer, and BSS-zero no-op |
| `mock/app_runtime.c` | Fuzz-owned replacements for globals that normally live in excluded `src/main.c` |
| `mock/scenario_layout.h` | Prefix offsets used by the harness and seed generators |
| `invariants/fuzz_globals.zon` | Synced Absolution invariant |
| `invariants/zero-symbols.txt` | App globals removed from the prefix |
| `invariants/domain-overrides.txt` | Enum and state constraints that improve convergence |
| `base-corpus/` | Promoted corpus snapshot checked into the app |
| `macros/exclude_macros.txt` | SDK macro exclusions needed by the fuzz build |
| `scripts/generate_seed_corpus.py` | Custom seed corpus generator driven by the shared command registry |
| `scripts/check_dispatch_conformance.py` | Production/fuzz parity check for canonical APDU commands |

## Notes on mocks and link-time overrides

The fuzz build uses **link-time mock overrides** instead of compile-time
`#ifdef` gates. Source files that need mocking are excluded from the build
in `CMakeLists.txt` and replaced by mock implementations in `mock/mocks.c`:

- **`check_signature_with_pubkey`** (`ledger_pki.c` excluded): always returns
`true`. ECDSA verification is a pure cryptographic gate that fuzzing cannot
solve (2^-128 probability). Without this mock, every signature-gated TLV
handler would bail at verification, leaving all downstream parsers at 0%
coverage. The sacrificed code has no memory-sensitive operations and is
better served by unit tests with known key-pairs.

- **`ui_display_safe_account`**: no-op. The production function triggers an
NBGL review flow that blocks on user interaction. Mocking it allows the
fuzzer to reach the post-validation success path in `cmd_safe_account.c`.

- **`parseBip32`**: uses the **real production implementation** (from
`src/main.c`), not a simplified stub. This ensures the fuzzer exercises
the same BIP32 validation and `bip32_path_read` call that runs on-device.

The `eth_ustream.c` no-progress guard is active under
`FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION` (set automatically by libFuzzer).
This prevents infinite loops from Absolution-injected txContext state where
normal progress invariants may be violated.

### Harness-side state bootstraps

Deep code (GTP, EIP-712, safe accounts) requires multi-APDU prerequisite
state that cannot be produced in a single-command-per-iteration harness.
The dispatcher (`fuzz_apdu_adapter.c`) conditionally bootstraps this state
before dispatching the target command:

- **GTP**: when `appState == SIGNING_TX` and the command is `INS_GTP_FIELD`
or `INS_GTP_TRANSACTION_INFO`, the bootstrap creates a `tx_ctx` with
parked calldata (selector 0xAABBCCDD), finds the matching context, and
attaches a synthetic `tx_info` with fields_hash=0xFF... The field-table
init runs as part of `tx_ctx_init`. This allows GTP FIELD seeds to
exercise deep TLV parsing, data-path traversal, and format dispatch.

- **EIP-712**: when `appState == SIGNING_EIP712` and the command is
`INS_EIP712_STRUCT_IMPL`, `INS_EIP712_FILTERING`, or
`INS_SIGN_EIP_712_MESSAGE`, the bootstrap allocates the context, registers
a minimal type schema (EIP712Domain with name/chainId/verifyingContract,
and Mail with value/to), sets both root types via `path_set_root`, and
enables `EIP712_FILTERING_FULL` mode. This unlocks the deep EIP-712 code:
`filtering.c`, `encode_field.c`, `type_hash.c`, `format_hash_field_type.c`,
`field_hash.c`, `schema_hash.c`, and the full typed-data path navigation.

- **Safe account**: when the command is `INS_PROVIDE_SAFE_ACCOUNT` with
`P2 == SIGNER_DESCRIPTOR`, the bootstrap allocates a `SAFE_DESC` with
threshold=1, signers_count=1, role=SIGNER. This allows signer descriptor
seeds to exercise the signer TLV parsing and address verification logic.

- **Enum values**: the GTP bootstrap also seeds a 4×4 grid of synthetic
enum entries (id 0..3, value 0..3) keyed to the bootstrapped contract
address and selector. These entries are registered through the production
`handle_enum_value_tlv_payload` + `verify_enum_value_struct` path (with
the signature check mocked) so `format_param_enum`'s `get_matching_enum()`
can find matches and exercise the success tail.

Trade-off: these bootstraps skip the APDU-level parsing that normally
builds the prerequisite structures (INS_SIGN for tx_ctx, INS_EIP712_STRUCT_DEF
for eip712 types, INS_PROVIDE_SAFE_ACCOUNT P2=SAFE_DESCRIPTOR for SAFE_DESC,
INS_PROVIDE_ENUM_VALUE for enum entries). That parsing is already fuzzed by
seeds that target those INS directly. The bootstrap only provides the
minimum prerequisite state so dependent handlers can exercise their own
deep parsing and memory logic.
1 change: 1 addition & 0 deletions fuzzing/base-corpus/.compat-key
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
318d07dc66631c956b6044646591fc3916faebda9456b387831d20b7dd1f3fb6
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Loading