Skip to content

Commit 92c7f7e

Browse files
committed
fuzzer fixes
1 parent aa7c0ac commit 92c7f7e

7 files changed

Lines changed: 66 additions & 12 deletions

File tree

CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,13 @@ if(ENABLE_SANITIZERS)
113113

114114
string(APPEND CMAKE_C_FLAGS " -fstack-protector-strong")
115115
string(APPEND CMAKE_CXX_FLAGS " -fstack-protector-strong")
116+
117+
# Disable sanitizers for crypto_helper.c as it uses picohash, which triggers many sanitizer warnings.
118+
# This is a workaround to allow using sanitizers for the rest of the codebase during fuzzing.
119+
set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/app/src/crypto_helper.c
120+
APPEND PROPERTY
121+
COMPILE_FLAGS "-fno-sanitize=address,undefined,integer,bounds"
122+
)
116123
endif()
117124

118125
set (RETRIEVE_MAJOR_CMD

app/src/common/parser.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ extern "C" {
2525
const char *parser_getErrorDescription(parser_error_t err);
2626
const char *parser_getMsgPackTypeDescription(uint8_t type);
2727

28+
//// initializes the parser context
29+
parser_error_t parser_init_context(parser_context_t *ctx, const uint8_t *buffer, uint16_t bufferSize);
30+
2831
//// parses a tx buffer
2932
parser_error_t parser_parse(parser_context_t *ctx, const uint8_t *data, size_t dataLen, parser_tx_t *tx_obj);
3033

app/src/schema_proof.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,10 @@ parser_error_t get_root_hash(const merkle_proof_t *metadata, uint8_t *hash) {
278278
CHECK_INPUT(metadata);
279279
CHECK_INPUT(hash);
280280

281+
if (metadata->lemmas.entries == 0) {
282+
return parser_unexpected_buffer_end;
283+
}
284+
281285
proof_t proof = {0};
282286
proof.leaves = metadata->leaves;
283287
proof.lemmas = metadata->lemmas;
@@ -294,6 +298,12 @@ parser_error_t get_root_hash(const merkle_proof_t *metadata, uint8_t *hash) {
294298
return parser_ok;
295299
}
296300

301+
/**
302+
* @brief Verify the merkle proofs.
303+
*
304+
* @param metadata Pointer to the merkle_proof_t structure containing the necessary data.
305+
* @return parser_error_t Error code indicating the result of the operation.
306+
*/
297307
parser_error_t verify_merkle_proofs(const merkle_proof_t *metadata) {
298308
CHECK_INPUT(metadata);
299309
CHECK_INPUT(metadata->root_hash.ptr);

app/src/schema_reader.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "schema_reader.h"
1818

19+
#include <stdint.h>
1920
#include "borsh.h"
2021
#include "crypto_helper.h"
2122
#include "schema_helper.h"
@@ -812,6 +813,11 @@ parser_error_t schema_merkle_proofs_read(parser_context_t *ctx, parser_tx_t *txO
812813

813814
// read lemmas
814815
CHECK_ERROR(read_u32(ctx, &txObj->merkle_proof.lemmas.entries));
816+
817+
if (txObj->merkle_proof.lemmas.entries > UINT16_MAX / 32) {
818+
return parser_value_out_of_range;
819+
}
820+
815821
txObj->merkle_proof.lemmas.data.buffer.ptr = ctx->buffer.ptr + ctx->offset;
816822
txObj->merkle_proof.lemmas.data.buffer.len = txObj->merkle_proof.lemmas.entries * 32;
817823
CTX_CHECK_AND_ADVANCE(ctx, txObj->merkle_proof.lemmas.data.buffer.len);

app/src/schema_txn_parser.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,11 @@ parser_error_t schema_parser_transaction(parser_context_t *ctx, parser_tx_t *txO
482482
uint64_t root_index = 0;
483483
CHECK_ERROR(schema_get_unsigned_transaction_index(txObj, &root_index));
484484

485-
CHECK_ERROR(schema_display_generic_by_index(ctx, txObj, root_index));
485+
if (root_index > UINT32_MAX) {
486+
return parser_value_out_of_range;
487+
}
488+
489+
CHECK_ERROR(schema_display_generic_by_index(ctx, txObj, (uint32_t)root_index));
486490

487491
txObj->unsigned_transaction_raw.buffer.len = ctx->offset - offset_mem_txn;
488492

fuzz/run-fuzz-crashes.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,36 @@ def analyze_crash(fuzzer, crash_file, fuzz_path):
5858
print(f"Command: {' '.join(shlex.quote(c) for c in cmd)}")
5959

6060
try:
61+
# Read crash file data
62+
with open(crash_file, 'rb') as f:
63+
crash_data = f.read()
64+
6165
# Run with timeout and capture output
6266
with open(log_file, 'w') as log:
6367
log.write(f"Crash analysis for: {crash_file}\n")
6468
log.write(f"Command: {' '.join(cmd)}\n")
6569
log.write(f"Timestamp: {time.strftime('%Y-%m-%d %H:%M:%S')}\n")
6670
log.write("=" * 50 + "\n\n")
71+
72+
# Log the crash data blob
73+
log.write("CRASH DATA BLOB:\n")
74+
log.write(f"Size: {len(crash_data)} bytes\n")
75+
76+
# Hex string format
77+
hex_string = ''.join(f'{b:02x}' for b in crash_data)
78+
log.write(f'\nBlob: "{hex_string}"\n')
79+
80+
log.write("\nHex dump:\n")
81+
# Write hex dump with ASCII representation
82+
for i in range(0, len(crash_data), 16):
83+
hex_part = ' '.join(f'{b:02x}' for b in crash_data[i:i+16])
84+
ascii_part = ''.join(chr(b) if 32 <= b <= 126 else '.' for b in crash_data[i:i+16])
85+
log.write(f"{i:08x}: {hex_part:<48} |{ascii_part}|\n")
86+
87+
log.write("\nRaw bytes (Python repr):\n")
88+
log.write(repr(crash_data))
89+
log.write("\n")
90+
log.write("=" * 50 + "\n\n")
6791
log.flush()
6892

6993
result = subprocess.run(

tests/parser_impl.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -281,16 +281,16 @@ TEST(SCALE, MultiProofTest) {
281281
EXPECT_EQ(memcmp(tx_obj.schema.chain_hash.ptr, expected_hash, CX_SHA256_SIZE), 0) << "Chain hash mismatch";
282282
}
283283

284-
TEST(SCALE, Fuzzer) {
285-
parser_context_t ctx = {0};
286-
parser_tx_t tx_obj = {0};
287-
parser_error_t err;
288-
uint8_t buffer[12000];
289-
auto bufferLen = parseHexString(buffer, sizeof(buffer), "0a");
284+
// TEST(SCALE, test_parser_impl) {
285+
// parser_context_t ctx = {0};
286+
// parser_tx_t tx_obj = {0};
287+
// parser_error_t err;
288+
// uint8_t buffer[12000];
289+
// auto bufferLen = parseHexString(buffer, sizeof(buffer), "000000000000000002000000000000000000000000008181818181818181818581818181818181818181818183818181818a8181816c5f02007060000081818181e70000ff00818181818181818100000000000000000093939393939393939393939393939393939393939393939393939393939393939393939393939393939393139393939393939393939393939300000d8181");
290290

291-
ctx.buffer.ptr = buffer;
292-
ctx.buffer.len = bufferLen;
291+
// ctx.buffer.ptr = buffer;
292+
// ctx.buffer.len = bufferLen;
293293

294-
// err = parser_parse(&ctx, ctx.buffer.ptr, ctx.buffer.len, &tx_obj);
295-
// EXPECT_EQ(err, parser_ok) << parser_getErrorDescription(err);
296-
}
294+
// err = parser_parse(&ctx, buffer, bufferLen, &tx_obj);
295+
// EXPECT_EQ(err, parser_ok) << parser_getErrorDescription(err);
296+
// }

0 commit comments

Comments
 (0)