Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Makefile.rules
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ ifeq ($(ENABLE_DYNAMIC_ALLOC), 1)
SDK_SOURCE_PATH += lib_alloc
endif

SDK_SOURCE_PATH += lib_c_list

ifneq ($(IS_STANDARD_APP),1)
ifneq ($(DISABLE_OS_IO_STACK_USE), 1)
ifeq (,$(filter $(DEFINES),HAVE_LEGACY_PID))
Expand Down
2 changes: 2 additions & 0 deletions doc/Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,8 @@ INPUT = \
lib_cxng/doc \
lib_cxng/include \
lib_cxng/src \
lib_c_list \
lib_c_list/doc \
lib_nbgl/doc \
lib_nbgl/include \
lib_nbgl/src \
Expand Down
4 changes: 4 additions & 0 deletions doc/mainpage.dox
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ The @subpage ble_mainpage page contains all information necessary to interact wi

The @subpage cxng_mainpage page contains all information necessary to understand Cryptographic Library

@section list_presentation Generic Linked List Library

The @subpage c_list_mainpage page contains all information necessary to use the Generic Linked List library.

@section mem_presentation Dynamic Memory Allocator Interface

The @subpage mem_alloc_mainpage page contains all information necessary to interact with Dynamic Memory Allocator.
Expand Down
1 change: 1 addition & 0 deletions fuzzing/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ if(NOT ${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR})
secure_sdk
INTERFACE macros
alloc
c_list
cxng
io
nbgl
Expand Down
25 changes: 13 additions & 12 deletions fuzzing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Manual usage based on Ledger container

### About Fuzzing Framework

The code is divided into the following folders:

```bash
Expand Down Expand Up @@ -49,23 +50,22 @@ export BOLOS_SDK=/app

cd fuzzing # You must run it from the fuzzing folder

./local_run.sh --build=1 --fuzzer=build/fuzz_bip32 --j=4 --run-fuzzer=1 --compute-coverage=1 --BOLOS_SDK=${BOLOS_SDK}
./local_run.sh --BOLOS_SDK=${BOLOS_SDK} --j=4 --build=1 --fuzzer=build/fuzz_bip32 --run-fuzzer=1 --compute-coverage=1
```

### 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 fuzzer on a specific crash input file (default: 0) |
| `--sanitizer` | `address or memory` | **Optional**. Compile fuzzer with sanitizer (default: address) |
| 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 fuzzer on a specific crash input file (default: 0) |
| `--sanitizer` | `address or memory` | **Optional**. Compile fuzzer with sanitizer (default: address) |
| `--j` | `int` | **Optional**. Number of parallel jobs/CPUs for build and fuzzing (default: 1) |
| `--help` | | **Optional**. Display help message |

| `--help` | | **Optional**. Display help message |

### Writing your Harness

Expand Down Expand Up @@ -138,6 +138,7 @@ cmake -S . -B build -DCMAKE_C_COMPILER=clang -DSANITIZER=address -G Ninja -DTARG
./build/fuzz_apdu_parser
./build/fuzz_base58
./build/fuzz_bip32
./build/fuzz_c_list
./build/fuzz_qrcodegen
./build/fuzz_alloc
./build/fuzz_alloc_utils
Expand Down
227 changes: 227 additions & 0 deletions fuzzing/docs/fuzz_c_list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
# Fuzzing lib_c_list

## Overview

This fuzzer tests the generic linked list library (`lib_c_list`) for memory safety issues, edge cases, and potential crashes. It exercises both **forward lists** (`c_flist_*`) and **doubly-linked lists** (`c_dlist_*`) with all available operations including insertion, removal, sorting, reversing, and traversal.

## List Type Selection

The **first byte** determines which type of list to test:

- **Bit 7 = 0**: Forward list (singly-linked)
- **Bit 7 = 1**: Doubly-linked list

This allows the fuzzer to test both implementations independently within a single harness.

## Operations Tested

### Forward List Operations (c_flist_*)

The fuzzer uses the lower 4 bits of each input byte to select operations:

| Op Code | Operation | Description |
|---------|-------------------|------------------------------------------------|
| 0x00 | `push_front` | Add node at the beginning (O(1)) |
| 0x01 | `push_back` | Add node at the end (O(n)) |
| 0x02 | `pop_front` | Remove first node (O(1)) |
| 0x03 | `pop_back` | Remove last node (O(n)) |
| 0x04 | `insert_after` | Insert node after reference node (O(1)) |
| 0x05 | `remove` | Remove specific node (O(n)) |
| 0x06 | `clear` | Remove all nodes (O(n)) |
| 0x07 | `sort` | Sort list by node ID (O(n²)) |
| 0x08 | `size` | Get list size (O(n)) |
| 0x09 | `reverse` | Reverse list order (O(n)) |
| 0x0A | `empty` | Check if list is empty (O(1)) |

### Doubly-Linked List Operations (c_dlist_*)

| Op Code | Operation | Description |
|---------|-------------------|------------------------------------------------|
| 0x00 | `push_front` | Add node at the beginning (O(1)) |
| 0x01 | `push_back` | Add node at the end (O(1) ⚡) |
| 0x02 | `pop_front` | Remove first node (O(1) ⚡) |
| 0x03 | `pop_back` | Remove last node (O(1) ⚡) |
| 0x04 | `insert_after` | Insert node after reference (O(1)) |
| 0x05 | `insert_before` | Insert node before reference (O(1) ⚡) |
| 0x06 | `remove` | Remove specific node (O(1) ⚡) |
| 0x07 | `clear` | Remove all nodes (O(n)) |
| 0x08 | `sort` | Sort list by node ID (O(n²)) |
| 0x09 | `size` | Get list size (O(n)) |
| 0x0A | `reverse` | Reverse list order (O(n)) |
| 0x0B | `empty` | Check if list is empty (O(1)) |

## Features

### Dual List Testing

The fuzzer tests both list implementations:

- **Forward Lists** (`c_flist_node_t`): Singly-linked, minimal memory overhead
- **Doubly-Linked Lists** (`c_dlist_node_t`): Bidirectional traversal, O(1) operations

### Safety Checks

- **Type safety**: Separate tracking for forward and doubly-linked nodes
- **Node tracking**: All allocated nodes are tracked for cleanup
- **Memory leak prevention**: Automatic cleanup at end of fuzzing iteration
- **Size limits**: Prevents excessive memory usage

### Test Data

Each node contains:

- Unique ID (auto-incremented)
- 16 bytes of fuzzer-provided data
- Standard list node structure (with or without prev pointer)

### Limits

- `MAX_NODES`: 1000 (prevents excessive memory usage)
- `MAX_TRACKERS`: 100 (limits number of tracked nodes)
- Minimum input length: 2 bytes (1 for type selection, 1+ for operations)

## Building

From the SDK root:

```bash
cd fuzzing
mkdir -p build && cd build
cmake -S .. -B . -DCMAKE_C_COMPILER=clang -DSANITIZER=address -DBOLOS_SDK=/path/to/sdk
cmake --build . --target fuzz_c_list
```

## Running

### Basic run

```bash
./fuzz_c_list
```

### With specific options

```bash
# Run for 10000 iterations
./fuzz_c_list -runs=10000

# Limit input size to 128 bytes
./fuzz_c_list -max_len=128

# Use corpus directory
./fuzz_c_list corpus/

# Timeout per input (in seconds)
./fuzz_c_list -timeout=10
```

### Using the helper script

```bash
cd /path/to/sdk/fuzzing
./local_run.sh --build=1 --fuzzer=build/fuzz_c_list --j=4 --run-fuzzer=1 --BOLOS_SDK=/path/to/sdk
```

## Corpus

Initial corpus files can be placed in:

```bash
fuzzing/harness/fuzz_c_list/
```

Example corpus files:

**Forward list operations** (first byte < 0x80):

```bash
# Simple forward list operations
00 00 <16 bytes> # push_front
00 01 <16 bytes> # push_back
00 02 # pop_front

# Complex forward list sequence
00 00 <16 bytes> 01 <16 bytes> 07 09 # push_front, push_back, sort, reverse
```

**Doubly-linked list operations** (first byte >= 0x80):

```bash
# Simple doubly-linked operations
80 00 <16 bytes> # push_front
80 01 <16 bytes> # push_back (O(1) - fast!)
80 05 00 <16 bytes> # insert_before (unique to doubly-linked)

# Complex doubly-linked sequence
80 00 <16 bytes> 01 <16 bytes> 08 0A # push_front, push_back, sort, reverse
```

## Input Format

```bash
Byte 0: [1 bit: list type] [7 bits: unused]
- Bit 7 = 0: Forward list
- Bit 7 = 1: Doubly-linked list

Byte 1+: [Operation code] [Optional parameters]
- Lower 4 bits: operation type (0x00-0x0F)
- Upper 4 bits: unused

Parameters:
- Node creation: 16 bytes of data
- Node reference: 1 byte index (for insert/remove operations)
```

## Debugging

Enable debug output by uncommenting `#define DEBUG_CRASH` in `fuzzer_c_list.c`:

```c
#define DEBUG_CRASH
```

This will print:

- Node creation/deletion
- Operation execution
- List size changes
- Cleanup operations

## Crash Analysis

If a crash is found:

1. The fuzzer will save the crashing input to `crash-*` or `leak-*` files
2. Reproduce the crash:

```bash
./fuzz_c_list crash-HASH
```

3. Debug with AddressSanitizer output
4. Fix the issue in `lib_c_list/c_list.c`
5. Verify fix by re-running fuzzer

## Expected Behavior

The fuzzer should:

- ✅ Handle all operations safely
- ✅ Prevent memory leaks (all nodes cleaned up)
- ✅ Detect invalid operations (return false)
- ✅ Handle edge cases (empty list, single node, etc.)
- ✅ Maintain list integrity (no cycles, no corruption)

## Known Issues

None currently. If you find a crash, please report it!

## Coverage

To generate coverage report:

```bash
./local_run.sh --build=1 --fuzzer=build/fuzz_c_list --compute-coverage=1 --BOLOS_SDK=/path/to/sdk
```

Coverage files will be in `fuzzing/out/coverage/`.
13 changes: 13 additions & 0 deletions fuzzing/extra/lib_c_list.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
include_guard()

# Include required libraries
include(${BOLOS_SDK}/fuzzing/libs/lib_c_list.cmake)
include(${BOLOS_SDK}/fuzzing/mock/mock.cmake)

# Define the executable and its properties here
add_executable(fuzz_c_list ${BOLOS_SDK}/fuzzing/harness/fuzzer_c_list.c)
target_compile_options(fuzz_c_list PUBLIC ${COMPILATION_FLAGS})
target_link_options(fuzz_c_list PUBLIC ${LINK_FLAGS})

# Link with required libraries
target_link_libraries(fuzz_c_list PUBLIC c_list mock)
Loading