Skip to content

Commit

Permalink
flamenco, fuzz: initial support for CPI syscall fuzzing
Browse files Browse the repository at this point in the history
  • Loading branch information
ravyu-jump committed Aug 9, 2024
1 parent 491461d commit a2ca6a2
Show file tree
Hide file tree
Showing 7 changed files with 221 additions and 42 deletions.
14 changes: 7 additions & 7 deletions src/flamenco/runtime/fd_executor.c
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ dump_sorted_features( const fd_features_t * features, fd_exec_test_feature_set_t
}

static void
dump_account_state( fd_borrowed_account_t * borrowed_account,
dump_account_state( fd_borrowed_account_t const * borrowed_account,
fd_exec_test_acct_state_t * output_account ) {
// Address
fd_memcpy(output_account->address, borrowed_account->pubkey, sizeof(fd_pubkey_t));
Expand All @@ -515,10 +515,10 @@ dump_account_state( fd_borrowed_account_t * borrowed_account,
output_account->has_seed_addr = false;
}

static void
create_instr_context_protobuf_from_instructions( fd_exec_test_instr_context_t * instr_context,
fd_exec_txn_ctx_t *txn_ctx,
fd_instr_info_t *instr ) {
void
fd_create_instr_context_protobuf_from_instructions( fd_exec_test_instr_context_t * instr_context,
fd_exec_txn_ctx_t const *txn_ctx,
fd_instr_info_t const *instr ) {
/*
NOTE: Calling this function requires the caller to have a scratch frame ready (see dump_instr_to_protobuf)
*/
Expand Down Expand Up @@ -546,7 +546,7 @@ create_instr_context_protobuf_from_instructions( fd_exec_test_instr_context_t *
instr_context->accounts = fd_scratch_alloc(alignof(fd_exec_test_acct_state_t), (instr_context->accounts_count + num_sysvar_entries + txn_ctx->executable_cnt) * sizeof(fd_exec_test_acct_state_t));
for( ulong i = 0; i < txn_ctx->accounts_cnt; i++ ) {
// Copy account information over
fd_borrowed_account_t * borrowed_account = &txn_ctx->borrowed_accounts[i];
fd_borrowed_account_t const * borrowed_account = &txn_ctx->borrowed_accounts[i];
fd_exec_test_acct_state_t * output_account = &instr_context->accounts[i];
dump_account_state( borrowed_account, output_account );
}
Expand Down Expand Up @@ -670,7 +670,7 @@ dump_instr_to_protobuf( fd_exec_txn_ctx_t *txn_ctx,
}

fd_exec_test_instr_context_t instr_context = FD_EXEC_TEST_INSTR_CONTEXT_INIT_DEFAULT;
create_instr_context_protobuf_from_instructions( &instr_context, txn_ctx, instr );
fd_create_instr_context_protobuf_from_instructions( &instr_context, txn_ctx, instr );

/* Output to file */
ulong out_buf_size = 100 * 1024 * 1024;
Expand Down
10 changes: 10 additions & 0 deletions src/flamenco/runtime/fd_executor.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@

FD_PROTOTYPES_BEGIN

/* Create an InstrContext protobuf struct from a given
transaction context and instr info.
NOTE: Calling this function requires the caller to have a scratch
frame ready and pushed (see dump_instr_to_protobuf) */
void
fd_create_instr_context_protobuf_from_instructions( fd_exec_test_instr_context_t * instr_context,
fd_exec_txn_ctx_t const * txn_ctx,
fd_instr_info_t const * instr );

/* fd_exec_instr_fn_t processes an instruction. Returns an error code
in FD_EXECUTOR_INSTR_{ERR_{...},SUCCESS}. */

Expand Down
45 changes: 32 additions & 13 deletions src/flamenco/runtime/tests/fd_exec_instr_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ _instr_context_create( fd_exec_instr_test_runner_t * runner,

/* Initial variables */
txn_ctx->loaded_accounts_data_size_limit = FD_VM_LOADED_ACCOUNTS_DATA_SIZE_LIMIT;
txn_ctx->heap_size = FD_VM_HEAP_SIZE;
txn_ctx->heap_size = fd_ulong_max( txn_ctx->heap_size, FD_VM_HEAP_SIZE ); /* FIXME: bound this to FD_VM_HEAP_MAX?*/

/* Set up epoch context */
fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( epoch_ctx );
Expand Down Expand Up @@ -521,6 +521,9 @@ _instr_context_create( fd_exec_instr_test_runner_t * runner,
}
info->acct_cnt = (uchar)test_ctx->instr_accounts_count;

// FIXME: Specifically for CPI syscalls, flag guard this?
fd_instr_info_sum_account_lamports( info, &info->starting_lamports_h, &info->starting_lamports_l );

/* This function is used to create context both for instructions and for syscalls,
however some of the remaining checks are only relevant for program instructions. */
if( !is_syscall ) {
Expand Down Expand Up @@ -1658,7 +1661,10 @@ fd_exec_vm_syscall_test_run( fd_exec_instr_test_runner_t * runner,
/* Create execution context */
const fd_exec_test_instr_context_t * input_instr_ctx = &input->instr_ctx;
fd_exec_instr_ctx_t ctx[1];
if( !_instr_context_create( runner, ctx, input_instr_ctx, alloc, true ) )
// Skip extra checks for non-CPI syscalls
bool skip_extra_checks = strncmp( (const char *)input->syscall_invocation.function_name.bytes, "sol_invoke_signed", 17 );

if( !_instr_context_create( runner, ctx, input_instr_ctx, alloc, skip_extra_checks ) )
goto error;
fd_valloc_t valloc = fd_scratch_virtual();

Expand Down Expand Up @@ -1793,7 +1799,7 @@ fd_exec_vm_syscall_test_run( fd_exec_instr_test_runner_t * runner,

/* Capture the effects */
effects->error = -syscall_err;
effects->r0 = vm->reg[0];
effects->r0 = syscall_err ? 0 : vm->reg[0]; // Save only on success
effects->cu_avail = (ulong)vm->cu;

effects->heap = FD_SCRATCH_ALLOC_APPEND(
Expand All @@ -1805,16 +1811,7 @@ fd_exec_vm_syscall_test_run( fd_exec_instr_test_runner_t * runner,
l, alignof(uint), PB_BYTES_ARRAY_T_ALLOCSIZE( FD_VM_STACK_MAX ) );
effects->stack->size = (uint)FD_VM_STACK_MAX;
fd_memcpy( effects->stack->bytes, vm->stack, FD_VM_STACK_MAX );

if( input_data_sz ) {
effects->inputdata = FD_SCRATCH_ALLOC_APPEND(
l, alignof(uint), PB_BYTES_ARRAY_T_ALLOCSIZE( input_data_sz ) );
effects->inputdata->size = (uint)input_data_sz;
fd_memcpy( effects->inputdata->bytes, (const void*)vm->input_mem_regions[0].haddr, input_data_sz );
} else {
effects->inputdata = NULL;
}


if( vm->rodata_sz ) {
effects->rodata = FD_SCRATCH_ALLOC_APPEND(
l, alignof(uint), PB_BYTES_ARRAY_T_ALLOCSIZE( rodata_sz ) );
Expand All @@ -1824,6 +1821,28 @@ fd_exec_vm_syscall_test_run( fd_exec_instr_test_runner_t * runner,
effects->rodata = NULL;
}

/* Flatten input data regions into a single region.
FIXME: Have SyscallEffects store repeated InputDataRegions instead
for more granularity. May need to regenerate fixtures/test-vectors. */
ulong input_regions_total_sz = 0;
for( ulong i=0; i<vm->input_mem_regions_cnt; i++ ) {
input_regions_total_sz += vm->input_mem_regions[i].region_sz;
}
if( input_regions_total_sz == 0 ) {
effects->inputdata = NULL;
} else {
effects->inputdata = FD_SCRATCH_ALLOC_APPEND(
l, alignof(uint), PB_BYTES_ARRAY_T_ALLOCSIZE( input_regions_total_sz ) );

effects->inputdata->size = (uint)input_regions_total_sz;
uchar * inputdata_ptr = effects->inputdata->bytes;
for( ulong i=0; i<vm->input_mem_regions_cnt; i++ ) {
fd_memcpy( inputdata_ptr, (void *) vm->input_mem_regions[i].haddr, vm->input_mem_regions[i].region_sz );
inputdata_ptr += vm->input_mem_regions[i].region_sz;
}
}

effects->frame_count = vm->frame_cnt;

if( vm->log_sz ) {
Expand Down
44 changes: 31 additions & 13 deletions src/flamenco/runtime/tests/fd_exec_sol_compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,17 @@ sol_compat_check_wksp_usage( void ) {
}
}

sol_compat_features_t const *
sol_compat_get_features_v1( void ) {
return &features;
}

fd_exec_instr_test_runner_t *
sol_compat_setup_scratch_and_runner( void * fmem ) {
// Setup scratch
fd_scratch_attach( smem, fmem, smax, 64UL );
/* Push frame */
fd_scratch_push();

// Setup test runner
void * runner_mem = fd_wksp_alloc_laddr( wksp, fd_exec_instr_test_runner_align(), fd_exec_instr_test_runner_footprint(), WKSP_TAG );
Expand All @@ -109,6 +116,9 @@ void
sol_compat_cleanup_scratch_and_runner( fd_exec_instr_test_runner_t * runner ) {
/* Cleanup test runner */
fd_wksp_free_laddr( fd_exec_instr_test_runner_delete( runner ) );

/* Pop frame */
fd_scratch_pop();
/* Cleanup scratch */
fd_scratch_detach( NULL );
}
Expand Down Expand Up @@ -152,19 +162,20 @@ sol_compat_execute_wrapper( fd_exec_instr_test_runner_t * runner,
void * input,
void ** output,
exec_test_run_fn_t * exec_test_run_fn ) {
// fd_scratch_push();
do {
ulong out_bufsz = 100000000; /* 100 MB */
void * out0 = fd_scratch_prepare( 1UL );
assert( out_bufsz < fd_scratch_free() );
fd_scratch_publish( (void *)( (ulong)out0 + out_bufsz ) );

assert( fd_scratch_prepare_is_safe( 1UL ) );
ulong out_bufsz = 100000000; /* 100 MB */
void * out0 = fd_scratch_prepare( 1UL );
assert( out_bufsz < fd_scratch_free() );
fd_scratch_publish( (void *)( (ulong)out0 + out_bufsz ) );

FD_SCRATCH_SCOPE_BEGIN {
ulong out_used = exec_test_run_fn( runner, input, output, out0, out_bufsz );
if( FD_UNLIKELY( !out_used ) ) {
*output = NULL;
break;
}
} while(0);
// fd_scratch_pop();
} FD_SCRATCH_SCOPE_END;
}

/*
Expand Down Expand Up @@ -484,10 +495,6 @@ sol_compat_elf_loader_v1( uchar * out,
return ok;
}

sol_compat_features_t const *
sol_compat_get_features_v1( void ) {
return &features;
}

int
sol_compat_vm_syscall_execute_v1( uchar * out,
Expand Down Expand Up @@ -530,7 +537,7 @@ int
sol_compat_vm_validate_v1( uchar * out,
ulong * out_sz,
uchar const * in,
ulong in_sz) {
ulong in_sz ) {
// Setup
ulong fmem[ 64 ];
fd_exec_instr_test_runner_t * runner = sol_compat_setup_scratch_and_runner( fmem );
Expand Down Expand Up @@ -562,3 +569,14 @@ sol_compat_vm_validate_v1( uchar * out,

return ok;
}

/* We still need a separate entrypoint since other harnesses (namely sfuzz-agave)
do something other than wrap their vm_syscall equivalent */
int
sol_compat_vm_cpi_syscall_v1( uchar * out,
ulong * out_sz,
uchar const * in,
ulong in_sz ) {
/* Just a wrapper to vm_syscall_execute_v1 */
return sol_compat_vm_syscall_execute_v1( out, out_sz, in, in_sz );
}
3 changes: 0 additions & 3 deletions src/flamenco/runtime/tests/test_exec_sol_compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,7 @@ main( int argc,
// Init runner
fd_exec_instr_test_runner_t * runner = sol_compat_setup_scratch_and_runner( fmem );

FD_TEST( fd_scratch_frame_used()==0UL );
fd_scratch_push();
fail_cnt += !run_test( runner, argv[j] );
fd_scratch_pop();

// Free runner
sol_compat_cleanup_scratch_and_runner( runner );
Expand Down
10 changes: 10 additions & 0 deletions src/flamenco/vm/fd_vm_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,16 @@
#define FD_VM_SH_OVERFLOW (-37) /* detected a shift overflow, equivalent to VeriferError::ShiftWithOverflow */
#define FD_VM_TEXT_SZ_UNALIGNED (-38) /* detected a text section that is not a multiple of 8 */

/* Error codes related to CPI syscall.
FIXME: Should this be in fd_executor_err.h instead?
Or a separate file for syscall errors? */

#define FD_VM_CPI_ERR_TOO_MANY_SIGNERS (-39) /* detected too many signers */
#define FD_VM_CPI_ERR_TOO_MANY_ACC_INFOS (-40) /* detected too many account infos */
#define FD_VM_CPI_ERR_INSTR_TOO_LARGE (-41) /* detected too many account infos meta */
#define FD_VM_CPI_ERR_INSTR_DATA_TOO_LARGE (-42) /* detected instruction data too large */
#define FD_VM_CPI_ERR_TOO_MANY_ACC_METAS (-43) /* detected too many account metas */

FD_PROTOTYPES_BEGIN

/* fd_vm_strerror converts an FD_VM_SUCCESS / FD_VM_ERR_* code into
Expand Down
Loading

0 comments on commit a2ca6a2

Please sign in to comment.