Skip to content

Commit 804d148

Browse files
committed
fuzzer fixes
1 parent 92c7f7e commit 804d148

6 files changed

Lines changed: 122 additions & 20 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ set(HUNTER_TLS_VERIFY OFF)
4141
enable_testing()
4242

4343
option(ENABLE_FUZZING "Build with fuzzing instrumentation and build fuzz targets" OFF)
44-
option(ENABLE_COVERAGE "Build with source code coverage instrumentation" OFF)
44+
option(ENABLE_COVERAGE "Build with source code coverage instrumentation" ON)
4545
option(ENABLE_SANITIZERS "Build with ASAN and UBSAN" OFF)
4646

4747
string(APPEND CMAKE_C_FLAGS " -fno-omit-frame-pointer -g")

app/src/schema_helper.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,15 @@ parser_error_t schema_move_leaf_offset(merkle_leaves_data_t *leaves, uint64_t in
6161
uint32_t data_length = 0;
6262
for (uint64_t i = 0; i < index; i++) {
6363
CHECK_ERROR(read_u32(&leaves->data, &data_length));
64+
65+
if (data_length > UINT16_MAX) {
66+
return parser_unexpected_buffer_end;
67+
}
68+
69+
if (leaves->data.offset > UINT16_MAX - data_length) {
70+
return parser_unexpected_buffer_end;
71+
}
72+
6473
if (leaves->data.offset + data_length > leaves->data.buffer.len) {
6574
return parser_unexpected_buffer_end;
6675
}

app/src/schema_reader.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "schema_reader.h"
1818

1919
#include <stdint.h>
20+
2021
#include "borsh.h"
2122
#include "crypto_helper.h"
2223
#include "schema_helper.h"

fuzz/parser_parse.cpp

Lines changed: 107 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include "parser.h"
66
#include "parser_common.h"
77
#include "parser_txdef.h"
8+
#include "schema_reader.h"
9+
#include "schema_txn_parser.h"
810
#include "zxmacros_x64.h"
911

1012
#ifdef NDEBUG
@@ -16,36 +18,101 @@ using std::size_t;
1618
namespace {
1719
char PARSER_KEY[16384];
1820
char PARSER_VALUE[16384];
19-
} // namespace
2021

21-
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
22-
parser_tx_t txObj;
23-
MEMZERO(&txObj, sizeof(txObj));
24-
parser_context_t ctx;
25-
parser_error_t rc;
22+
// Helper function to test individual parsing functions with fresh contexts
23+
void test_individual_functions(const parser_context_t &base_ctx, const parser_tx_t &base_txObj) {
24+
// Test merkle proofs reading independently
25+
{
26+
parser_context_t ctx = base_ctx;
27+
parser_tx_t txObj = base_txObj;
28+
schema_merkle_proofs_read(&ctx, &txObj);
29+
}
2630

27-
rc = parser_parse(&ctx, data, size, &txObj);
28-
if (rc != parser_ok) {
29-
return 0;
31+
// Test extra data reading independently
32+
{
33+
parser_context_t ctx = base_ctx;
34+
parser_tx_t txObj = base_txObj;
35+
schema_extra_data_read(&ctx, &txObj);
3036
}
3137

32-
rc = parser_validate(&txObj);
33-
if (rc != parser_ok) {
34-
return 0;
38+
// Test transaction parsing independently
39+
{
40+
parser_context_t ctx = base_ctx;
41+
parser_tx_t txObj = base_txObj;
42+
schema_parser_transaction(&ctx, &txObj);
43+
}
44+
45+
// Test chain hash reading independently
46+
{
47+
parser_context_t ctx = base_ctx;
48+
parser_tx_t txObj = base_txObj;
49+
schema_chain_hash_read(&ctx, &txObj);
50+
}
51+
}
52+
53+
// Helper function to test partial pipelines and return successful result
54+
bool test_partial_pipelines(const parser_context_t &base_ctx, const parser_tx_t &base_txObj, parser_tx_t &result_txObj) {
55+
// Test pipeline starting from merkle proofs
56+
{
57+
parser_context_t ctx = base_ctx;
58+
parser_tx_t txObj = base_txObj;
59+
60+
if (schema_merkle_proofs_read(&ctx, &txObj) == parser_ok) {
61+
schema_extra_data_read(&ctx, &txObj);
62+
if (schema_parser_transaction(&ctx, &txObj) == parser_ok) {
63+
schema_chain_hash_read(&ctx, &txObj);
64+
result_txObj = txObj;
65+
return true;
66+
}
67+
}
68+
}
69+
70+
// Test pipeline starting from extra data (skip merkle)
71+
{
72+
parser_context_t ctx = base_ctx;
73+
parser_tx_t txObj = base_txObj;
74+
75+
schema_extra_data_read(&ctx, &txObj);
76+
if (schema_parser_transaction(&ctx, &txObj) == parser_ok) {
77+
schema_chain_hash_read(&ctx, &txObj);
78+
result_txObj = txObj;
79+
return true;
80+
}
81+
}
82+
83+
// Test pipeline starting from transaction parsing (skip merkle and extra)
84+
{
85+
parser_context_t ctx = base_ctx;
86+
parser_tx_t txObj = base_txObj;
87+
88+
if (schema_parser_transaction(&ctx, &txObj) == parser_ok) {
89+
schema_chain_hash_read(&ctx, &txObj);
90+
result_txObj = txObj;
91+
return true;
92+
}
93+
}
94+
95+
return false;
96+
}
97+
98+
// Helper function to test and iterate through parsed items
99+
void test_parser_output(parser_tx_t &txObj) {
100+
if (parser_validate(&txObj) != parser_ok) {
101+
return;
35102
}
36103

37104
uint8_t num_items;
38-
rc = parser_getNumItems(&txObj, &num_items);
39-
if (rc != parser_ok) {
105+
if (parser_getNumItems(&txObj, &num_items) != parser_ok) {
40106
assert(false);
41107
}
42108

43109
for (uint8_t i = 0; i < num_items; i += 1) {
44110
uint8_t page_idx = 0;
45111
uint8_t page_count = 1;
112+
46113
while (page_idx < page_count) {
47-
rc = parser_getItem(&txObj, i, PARSER_KEY, sizeof(PARSER_KEY), PARSER_VALUE, sizeof(PARSER_VALUE), page_idx,
48-
&page_count);
114+
const parser_error_t rc = parser_getItem(&txObj, i, PARSER_KEY, sizeof(PARSER_KEY), PARSER_VALUE, sizeof(PARSER_VALUE),
115+
page_idx, &page_count);
49116

50117
if (rc != parser_ok) {
51118
(void)fprintf(stderr, "error getting item %u at page index %u: %s\n", (unsigned)i, (unsigned)page_idx,
@@ -56,6 +123,30 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
56123
page_idx += 1;
57124
}
58125
}
126+
}
127+
128+
} // namespace
129+
130+
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
131+
parser_tx_t txObj;
132+
MEMZERO(&txObj, sizeof(txObj));
133+
parser_context_t ctx;
134+
135+
const parser_error_t rc = parser_init_context(&ctx, data, size);
136+
if (rc != parser_ok) {
137+
return 0;
138+
}
139+
140+
// Test individual parsing functions independently to maximize coverage
141+
// This prevents early validation failures from blocking coverage of later stages
142+
test_individual_functions(ctx, txObj);
143+
144+
// Test partial pipelines with different entry points
145+
parser_tx_t result_txObj;
146+
if (test_partial_pipelines(ctx, txObj, result_txObj)) {
147+
// Test parser output with the successful result (no redundant parsing)
148+
test_parser_output(result_txObj);
149+
}
59150

60151
return 0;
61152
}

fuzz/run-fuzzers.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import shlex
66
import subprocess
77

8-
MAX_SECONDS_PER_RUN = 600
8+
MAX_SECONDS_PER_RUN = 6
99
MUTATE_DEPTH = random.randint(1, 20)
1010

1111
# Create coverage directory specifically in fuzz/coverage
@@ -69,7 +69,7 @@
6969
cmd = [fuzz_path, f'-max_total_time={max_time}',
7070
f'-timeout=20',
7171
f'-rss_limit_mb=2048',
72-
f'-jobs=16',
72+
f'-jobs=8',
7373
f'-max_len={max_len}',
7474
f'-mutate_depth={MUTATE_DEPTH}',
7575
f'-artifact_prefix={artifact_dir}/',

tests/parser_impl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,8 @@ TEST(SCALE, MultiProofTest) {
286286
// parser_tx_t tx_obj = {0};
287287
// parser_error_t err;
288288
// uint8_t buffer[12000];
289-
// auto bufferLen = parseHexString(buffer, sizeof(buffer), "000000000000000002000000000000000000000000008181818181818181818581818181818181818181818183818181818a8181816c5f02007060000081818181e70000ff00818181818181818100000000000000000093939393939393939393939393939393939393939393939393939393939393939393939393939393939393139393939393939393939393939300000d8181");
289+
// auto bufferLen = parseHexString(buffer, sizeof(buffer),
290+
// "000000000000000002000000000000000000000000008181818181818181818581818181818181818181818183818181818a8181816c5f02007060000081818181e70000ff00818181818181818100000000000000000093939393939393939393939393939393939393939393939393939393939393939393939393939393939393139393939393939393939393939300000d8181");
290291

291292
// ctx.buffer.ptr = buffer;
292293
// ctx.buffer.len = bufferLen;

0 commit comments

Comments
 (0)