Skip to content

Commit ec43c02

Browse files
committed
fuzzer fixes
1 parent 59e2fcf commit ec43c02

6 files changed

Lines changed: 68 additions & 21 deletions

File tree

app/src/borsh.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
parser_error_t read_u8(parser_context_t *ctx, uint8_t *val) {
2424
CHECK_INPUT(ctx);
2525
CHECK_INPUT(val);
26+
if (ctx->offset + OFFSET_U8 > ctx->buffer.len) {
27+
return parser_unexpected_buffer_end;
28+
}
2629
*val = *(uint8_t *)(ctx->buffer.ptr + ctx->offset);
2730
CTX_CHECK_AND_ADVANCE(ctx, OFFSET_U8);
2831
return parser_ok;
@@ -31,23 +34,32 @@ parser_error_t read_u8(parser_context_t *ctx, uint8_t *val) {
3134
parser_error_t read_u16(parser_context_t *ctx, uint16_t *val) {
3235
CHECK_INPUT(ctx);
3336
CHECK_INPUT(val);
34-
*val = *(uint16_t *)(ctx->buffer.ptr + ctx->offset);
37+
if (ctx->offset + OFFSET_U16 > ctx->buffer.len) {
38+
return parser_unexpected_buffer_end;
39+
}
40+
MEMCPY(val, ctx->buffer.ptr + ctx->offset, sizeof(uint16_t));
3541
CTX_CHECK_AND_ADVANCE(ctx, OFFSET_U16);
3642
return parser_ok;
3743
}
3844

3945
parser_error_t read_u32(parser_context_t *ctx, uint32_t *val) {
4046
CHECK_INPUT(ctx);
4147
CHECK_INPUT(val);
42-
*val = *(uint32_t *)(ctx->buffer.ptr + ctx->offset);
48+
if (ctx->offset + OFFSET_U32 > ctx->buffer.len) {
49+
return parser_unexpected_buffer_end;
50+
}
51+
MEMCPY(val, ctx->buffer.ptr + ctx->offset, sizeof(uint32_t));
4352
CTX_CHECK_AND_ADVANCE(ctx, OFFSET_U32);
4453
return parser_ok;
4554
}
4655

4756
parser_error_t read_u64(parser_context_t *ctx, uint64_t *val) {
4857
CHECK_INPUT(ctx);
4958
CHECK_INPUT(val);
50-
*val = *(uint64_t *)(ctx->buffer.ptr + ctx->offset);
59+
if (ctx->offset + OFFSET_U64 > ctx->buffer.len) {
60+
return parser_unexpected_buffer_end;
61+
}
62+
MEMCPY(val, ctx->buffer.ptr + ctx->offset, sizeof(uint64_t));
5163
CTX_CHECK_AND_ADVANCE(ctx, OFFSET_U64);
5264
return parser_ok;
5365
}
@@ -105,7 +117,7 @@ void print_string(const char *str) {
105117
MEMCPY(print, str, strlen(str));
106118
ZEMU_LOGF(100, "%s\n", print);
107119
#else
108-
printf("%s\n", str);
120+
// printf("%s\n", str);
109121
#endif
110122
}
111123

app/src/schema_proof.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,14 @@ static parser_error_t hash_index_leaf(merkle_leaves_data_t *leaves, uint64_t ind
112112
uint32_t data_length = 0;
113113
CHECK_ERROR(read_u32(&leaves->data, &data_length));
114114

115+
// Bounds check to prevent buffer overflow
116+
// Check for integer overflow and ensure we have enough bytes remaining
117+
if (data_length == 0 ||
118+
data_length > UINT32_MAX - leaves->data.offset ||
119+
leaves->data.offset + data_length > leaves->data.buffer.len) {
120+
return parser_unexpected_buffer_end;
121+
}
122+
115123
// Compute hash from entry and store it in proof->hash
116124
crypto_sha256_init();
117125
crypto_sha256_update(&LEAF_PREFIX, 1);

app/src/schema_reader.c

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -115,14 +115,17 @@ parser_error_t read_structured_display_overrides(parser_context_t *ctx, structur
115115
CHECK_INPUT(ctx);
116116

117117
// read has_title_elements
118-
CHECK_ERROR(read_u8(ctx, (uint8_t *)&display->has_title_elements));
118+
uint8_t tmp = 0;
119+
CHECK_ERROR(read_u8(ctx, &tmp));
120+
display->has_title_elements = (tmp != 0);
119121
if (display->has_title_elements) {
120122
// read title_elements
121123
CHECK_ERROR(read_u64(ctx, (uint64_t *)&display->title_elements));
122124
}
123125

124126
// read has_title_lines
125-
CHECK_ERROR(read_u8(ctx, (uint8_t *)&display->has_title_lines));
127+
CHECK_ERROR(read_u8(ctx, &tmp));
128+
display->has_title_lines = (tmp != 0);
126129
if (display->has_title_lines) {
127130
// read title_lines
128131
CHECK_ERROR(read_u64(ctx, (uint64_t *)&display->title_lines));
@@ -155,7 +158,9 @@ parser_error_t read_primitive_byte_array(parser_context_t *ctx, primitive_byte_a
155158
CHECK_ERROR(read_byte_display(ctx, &primitive->display));
156159

157160
// read has_name_registry
158-
CHECK_ERROR(read_u8(ctx, (uint8_t *)&primitive->has_name_registry));
161+
uint8_t tmp = 0;
162+
CHECK_ERROR(read_u8(ctx, &tmp));
163+
primitive->has_name_registry = (tmp != 0);
159164

160165
// read name_registry
161166
if (primitive->has_name_registry) {
@@ -177,7 +182,9 @@ parser_error_t read_primitive_byte_vec(parser_context_t *ctx, primitive_byte_vec
177182
CHECK_ERROR(read_byte_display(ctx, &primitive->display));
178183

179184
// read has_name_registry
180-
CHECK_ERROR(read_u8(ctx, (uint8_t *)&primitive->has_name_registry));
185+
uint8_t tmp = 0;
186+
CHECK_ERROR(read_u8(ctx, &tmp));
187+
primitive->has_name_registry = (tmp != 0);
181188

182189
// read name_registry
183190
if (primitive->has_name_registry) {
@@ -269,7 +276,9 @@ parser_error_t read_enum_variant(parser_context_t *ctx, enum_variant_t *variant)
269276
CHECK_ERROR(read_u8(ctx, (uint8_t *)&variant->hide_tag));
270277

271278
// read has_value
272-
CHECK_ERROR(read_u8(ctx, (uint8_t *)&variant->has_value));
279+
uint8_t tmp = 0;
280+
CHECK_ERROR(read_u8(ctx, &tmp));
281+
variant->has_value = (tmp != 0);
273282
if (variant->has_value) {
274283
// read value
275284
CHECK_ERROR(read_link(ctx, &variant->value));
@@ -374,7 +383,9 @@ parser_error_t read_struct(parser_context_t *ctx, schema_struct_t *schema_struct
374383
}
375384

376385
// read has_show_as
377-
CHECK_ERROR(read_u8(ctx, (uint8_t *)&schema_struct->has_show_as));
386+
uint8_t tmp = 0;
387+
CHECK_ERROR(read_u8(ctx, &tmp));
388+
schema_struct->has_show_as = (tmp != 0);
378389
if (schema_struct->has_show_as) {
379390
CHECK_ERROR(read_u32(ctx, (uint32_t *)&schema_struct->show_as.len));
380391
if (schema_struct->show_as.len == 0) {
@@ -387,7 +398,8 @@ parser_error_t read_struct(parser_context_t *ctx, schema_struct_t *schema_struct
387398
}
388399

389400
// read has_structured_show_as
390-
CHECK_ERROR(read_u8(ctx, (uint8_t *)&schema_struct->has_structured_show_as));
401+
CHECK_ERROR(read_u8(ctx, &tmp));
402+
schema_struct->has_structured_show_as = (tmp != 0);
391403
if (schema_struct->has_structured_show_as) {
392404
CHECK_ERROR(read_u32(ctx, (uint32_t *)&schema_struct->structured_show_as.len));
393405
if (schema_struct->structured_show_as.len == 0) {
@@ -424,7 +436,9 @@ parser_error_t read_tuple(parser_context_t *ctx, schema_tuple_t *schema_tuple) {
424436
CHECK_INPUT(ctx);
425437

426438
// read has_show_as
427-
CHECK_ERROR(read_u8(ctx, (uint8_t *)&schema_tuple->has_show_as));
439+
uint8_t tmp = 0;
440+
CHECK_ERROR(read_u8(ctx, &tmp));
441+
schema_tuple->has_show_as = (tmp != 0);
428442
if (schema_tuple->has_show_as) {
429443
CHECK_ERROR(read_u32(ctx, (uint32_t *)&schema_tuple->show_as.len));
430444
if (schema_tuple->show_as.len == 0) {
@@ -437,7 +451,8 @@ parser_error_t read_tuple(parser_context_t *ctx, schema_tuple_t *schema_tuple) {
437451
}
438452

439453
// read has_structured_show_as
440-
CHECK_ERROR(read_u8(ctx, (uint8_t *)&schema_tuple->has_structured_show_as));
454+
CHECK_ERROR(read_u8(ctx, &tmp));
455+
schema_tuple->has_structured_show_as = (tmp != 0);
441456
if (schema_tuple->has_structured_show_as) {
442457
CHECK_ERROR(read_u32(ctx, (uint32_t *)&schema_tuple->structured_show_as.len));
443458
if (schema_tuple->structured_show_as.len == 0) {
@@ -762,6 +777,10 @@ parser_error_t schema_merkle_proofs_read(parser_context_t *ctx, parser_tx_t *txO
762777
CHECK_INPUT(ctx);
763778
CHECK_INPUT(txObj);
764779

780+
if (ctx->buffer.len < 4) {
781+
return parser_no_data;
782+
}
783+
765784
// read leaf data
766785
CHECK_ERROR(read_u32(ctx, &txObj->merkle_proof.leaves.entries));
767786
const uint8_t *ptr_mem = ctx->buffer.ptr + ctx->offset;

app/src/ui_item_manager.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,5 @@ parser_error_t push_item(parser_tx_t *txObj, primitive_t *primitive, parser_cont
149149
txObj->ui_items_new.items[txObj->ui_items_new.qty].data_context = *data_context;
150150
txObj->ui_items_new.qty++;
151151

152-
for (uint16_t i = 0; i < txObj->ui_items_new.qty; i++) {
153-
print_string("Push item NEW: ");
154-
print_string(txObj->ui_items_new.items[i].title);
155-
print_buffer(&txObj->ui_items_new.items[i].data_context.buffer, "data context");
156-
}
157-
158152
return parser_ok;
159153
}

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 = 5
8+
MAX_SECONDS_PER_RUN = 60
99
MUTATE_DEPTH = random.randint(1, 20)
1010

1111
# (fuzzer name, max length, max time scale factor)
@@ -30,7 +30,7 @@
3030
env['UBSAN_OPTIONS'] = 'halt_on_error=1:print_stacktrace=1'
3131

3232
cmd = [fuzz_path, f'-max_total_time={max_time}',
33-
f'-jobs=2'
33+
f'-jobs=1'
3434
f'-max_len={max_len}',
3535
f'-mutate_depth={MUTATE_DEPTH}',
3636
f'-artifact_prefix={artifact_dir}/',

tests/parser_impl.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,3 +282,17 @@ TEST(SCALE, MultiProofTest) {
282282

283283
EXPECT_EQ(memcmp(tx_obj.schema.chain_hash.ptr, expected_hash, CX_SHA256_SIZE), 0) << "Chain hash mismatch";
284284
}
285+
286+
TEST(SCALE, Fuzzer) {
287+
parser_context_t ctx = {0};
288+
parser_tx_t tx_obj = {0};
289+
parser_error_t err;
290+
uint8_t buffer[12000];
291+
auto bufferLen = parseHexString(buffer, sizeof(buffer), "0a");
292+
293+
ctx.buffer.ptr = buffer;
294+
ctx.buffer.len = bufferLen;
295+
296+
// err = parser_parse(&ctx, ctx.buffer.ptr, ctx.buffer.len, &tx_obj);
297+
// EXPECT_EQ(err, parser_ok) << parser_getErrorDescription(err);
298+
}

0 commit comments

Comments
 (0)