From 7be62cfb6bdc58000caa0dec517a6db727a2489a Mon Sep 17 00:00:00 2001 From: ibhatt-jumptrading Date: Wed, 27 Nov 2024 20:11:06 +0000 Subject: [PATCH] flamenco: reordering preflights --- .../try_find_program_address.list | 4 + src/flamenco/vm/syscall/fd_vm_syscall.h | 21 ++- .../vm/syscall/fd_vm_syscall_cpi_common.c | 20 ++- src/flamenco/vm/syscall/fd_vm_syscall_pda.c | 121 +++++++++++++----- 4 files changed, 129 insertions(+), 37 deletions(-) diff --git a/contrib/test/test-vectors-fixtures/syscall-fixtures/try_find_program_address.list b/contrib/test/test-vectors-fixtures/syscall-fixtures/try_find_program_address.list index dcec705c74..9e493d18ad 100644 --- a/contrib/test/test-vectors-fixtures/syscall-fixtures/try_find_program_address.list +++ b/contrib/test/test-vectors-fixtures/syscall-fixtures/try_find_program_address.list @@ -83,3 +83,7 @@ dump/test-vectors/syscall/fixtures/try_find_program_address/f30544e4b2f72739681e dump/test-vectors/syscall/fixtures/try_find_program_address/f4b7a01b4ceb0af56928b5ef5206761a148b853a_2674779.fix dump/test-vectors/syscall/fixtures/try_find_program_address/facc8d7b50876a0d569413cd09cc958d9fa2a124_2676665.fix dump/test-vectors/syscall/fixtures/try_find_program_address/fcf25f0fd5d1174ed9be1926096c4f373a890c78_2681303.fix +dump/test-vectors/syscall/fixtures/try_find_program_address/093a7d5392b925027fee2322dd43ffd772687246_2071515.fix +dump/test-vectors/syscall/fixtures/try_find_program_address/6f8a4f57275722c8688bc278091ca4b99b717b5e_1718428.fix +dump/test-vectors/syscall/fixtures/try_find_program_address/b4b8a7b54c2b0356e7e5370fe0948f55e3970da0_1837893.fix +dump/test-vectors/syscall/fixtures/try_find_program_address/bc322c44298746ad781c5913b2fa1845dcee8df7_1922460.fix diff --git a/src/flamenco/vm/syscall/fd_vm_syscall.h b/src/flamenco/vm/syscall/fd_vm_syscall.h index 9e40a6d331..4e34644457 100644 --- a/src/flamenco/vm/syscall/fd_vm_syscall.h +++ b/src/flamenco/vm/syscall/fd_vm_syscall.h @@ -8,6 +8,14 @@ #include "../../log_collector/fd_log_collector.h" #define FD_VM_RETURN_DATA_MAX (1024UL) /* FIXME: DOCUMENT AND DOES THIS BELONG HERE? */ + +/* The maximum number of seeds a PDA can have + https://github.com/solana-labs/solana/blob/2afde1b028ed4593da5b6c735729d8994c4bfac6/sdk/program/src/pubkey.rs#L21 */ +#define FD_VM_PDA_SEEDS_MAX (16UL) +/* The maximum length of a PDA seed + https://github.com/solana-labs/solana/blob/2afde1b028ed4593da5b6c735729d8994c4bfac6/sdk/program/src/pubkey.rs#L19 */ +#define FD_VM_PDA_SEED_MEM_MAX (32UL) + /* https://github.com/solana-labs/solana/blob/2afde1b028ed4593da5b6c735729d8994c4bfac6/sdk/program/src/pubkey.rs#L22 */ /* FIXME: CONSIDER NOT PREFIXING SYSCALLS WITH SOL_? (OR MAYBE THIS @@ -819,12 +827,21 @@ FD_VM_SYSCALL_DECL( sol_curve_multiscalar_mul ); int fd_vm_derive_pda( fd_vm_t * vm, fd_pubkey_t const * program_id, - ulong program_id_vaddr, - ulong seeds_vaddr, + void const * * seed_haddrs, + ulong * seed_szs, ulong seeds_cnt, uchar * bump_seed, fd_pubkey_t * out ); +int +fd_vm_translate_and_check_program_address_inputs( fd_vm_t * vm, + ulong seeds_vaddr, + ulong seeds_cnt, + ulong program_id_vaddr, + void const * * out_seed_haddrs, + ulong * out_seed_szs, + fd_pubkey_t const * * out_program_id ); + FD_PROTOTYPES_END #endif /* HEADER_src_flamenco_vm_syscall_fd_vm_syscall_h */ diff --git a/src/flamenco/vm/syscall/fd_vm_syscall_cpi_common.c b/src/flamenco/vm/syscall/fd_vm_syscall_cpi_common.c index 2949b92a1f..11abea8648 100644 --- a/src/flamenco/vm/syscall/fd_vm_syscall_cpi_common.c +++ b/src/flamenco/vm/syscall/fd_vm_syscall_cpi_common.c @@ -618,8 +618,26 @@ VM_SYSCALL_CPI_ENTRYPOINT( void * _vm, FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_ERR_SYSCALL_TOO_MANY_SIGNERS ); return FD_VM_ERR_SYSCALL_TOO_MANY_SIGNERS; } + for( ulong i=0UL; isha ); - for ( ulong i=0UL; iFD_VM_PDA_SEED_MEM_MAX ) ) { - FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_ERR_SYSCALL_BAD_SEEDS ); - return FD_VM_ERR_INVAL; - } + for( ulong i=0UL; isha, seed_haddr, seed_sz ); } @@ -81,11 +64,10 @@ fd_vm_derive_pda( fd_vm_t * vm, fd_sha256_append( vm->sha, bump_seed, 1UL ); } - if ( program_id != NULL ) { + if( FD_LIKELY( program_id )) { fd_sha256_append( vm->sha, program_id, FD_PUBKEY_FOOTPRINT ); } else { - fd_pubkey_t const * program_id_translated = FD_VM_MEM_HADDR_LD( vm, program_id_vaddr, FD_VM_ALIGN_RUST_PUBKEY, FD_PUBKEY_FOOTPRINT ); - fd_sha256_append( vm->sha, program_id_translated, FD_PUBKEY_FOOTPRINT ); + FD_LOG_ERR(( "No program id passed in" )); } fd_sha256_append( vm->sha, "ProgramDerivedAddress", 21UL ); /* TODO: use marker constant */ @@ -101,6 +83,49 @@ fd_vm_derive_pda( fd_vm_t * vm, return FD_VM_SUCCESS; } +/* fd_vm_translate_and_check_program_address_inputs is responsible for doing + the preflight checks and translation of the seeds and program id. + https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L719 */ + +int +fd_vm_translate_and_check_program_address_inputs( fd_vm_t * vm, + ulong seeds_vaddr, + ulong seeds_cnt, + ulong program_id_vaddr, + void const * * out_seed_haddrs, + ulong * out_seed_szs, + fd_pubkey_t const * * out_program_id ) { + + fd_vm_vec_t const * untranslated_seeds = FD_VM_MEM_SLICE_HADDR_LD( vm, seeds_vaddr, FD_VM_ALIGN_RUST_SLICE_U8_REF, + fd_ulong_sat_mul( seeds_cnt, FD_VM_VEC_SIZE ) ); + + /* This is a preflight check that is performed in Agave before deriving PDAs but after checking the seeds vaddr. + https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L728-L730 */ + if( FD_UNLIKELY( seeds_cnt>FD_VM_PDA_SEEDS_MAX ) ) { + FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_ERR_SYSCALL_BAD_SEEDS ); + return FD_VM_ERR_INVAL; + + } + for( ulong i=0UL; iFD_VM_PDA_SEED_MEM_MAX ) ) { + FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_ERR_SYSCALL_BAD_SEEDS ); + return FD_VM_ERR_INVAL; + } + void const * seed_haddr = FD_VM_MEM_SLICE_HADDR_LD( vm, untranslated_seeds[i].addr, FD_VM_ALIGN_RUST_U8, seed_sz ); + out_seed_haddrs[ i ] = seed_haddr; + out_seed_szs [ i ] = seed_sz; + } + + /* We only want to do this check if the user requires it. */ + if( out_program_id ) { + *out_program_id = FD_VM_MEM_HADDR_LD( vm, program_id_vaddr, FD_VM_ALIGN_RUST_PUBKEY, FD_PUBKEY_FOOTPRINT ); + } + return 0; +} + /* fd_vm_syscall_sol_create_program_address is the entrypoint for the sol_create_program_address syscall: https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L729 @@ -138,8 +163,24 @@ fd_vm_syscall_sol_create_program_address( /**/ void * _vm, FD_VM_CU_UPDATE( vm, FD_VM_CREATE_PROGRAM_ADDRESS_UNITS ); + void const * seed_haddrs[ FD_VM_PDA_SEEDS_MAX ]; + ulong seed_szs [ FD_VM_PDA_SEEDS_MAX ]; + fd_pubkey_t const * program_id; + + int err = fd_vm_translate_and_check_program_address_inputs( vm, + seeds_vaddr, + seeds_cnt, + program_id_vaddr, + seed_haddrs, + seed_szs, + &program_id ); + if( FD_UNLIKELY( err ) ) { + *_ret = 0UL; + return err; + } + fd_pubkey_t derived[1]; - int err = fd_vm_derive_pda( vm, NULL, program_id_vaddr, seeds_vaddr, seeds_cnt, bump_seed, derived ); + err = fd_vm_derive_pda( vm, program_id, seed_haddrs, seed_szs, seeds_cnt, bump_seed, derived ); /* Agave does their translation before the calculation, so if the translation fails we should fail the syscall. @@ -196,19 +237,31 @@ fd_vm_syscall_sol_try_find_program_address( void * _vm, uchar bump_seed[1]; - /* Agave performs preflight checks on the seed lengths and translation before doing any - derivation and deducting CUs, whereas we do it on the fly in a single iteration. - To maintain CU conformance at a fuzzing level, we should perform the CU deduction only if - our adjacent preflight checks do not fail. If they do at some point in the derivation, - no extra CUs will be charged. */ + /* First we need to do the preflight checks */ + void const * seed_haddrs[ FD_VM_PDA_SEEDS_MAX ]; + ulong seed_szs [ FD_VM_PDA_SEEDS_MAX ]; + fd_pubkey_t const * program_id; + + int err = fd_vm_translate_and_check_program_address_inputs( vm, + seeds_vaddr, + seeds_cnt, + program_id_vaddr, + seed_haddrs, + seed_szs, + &program_id ); + if( FD_UNLIKELY( err ) ) { + *_ret = 0UL; + return err; + } + for( ulong i=0UL; i<255UL; i++ ) { bump_seed[0] = (uchar)(255UL - i); fd_pubkey_t derived[1]; - int err = fd_vm_derive_pda( vm, NULL, program_id_vaddr, seeds_vaddr, seeds_cnt, bump_seed, derived ); + err = fd_vm_derive_pda( vm, program_id, seed_haddrs, seed_szs, seeds_cnt, bump_seed, derived ); if( FD_LIKELY( err==FD_VM_SUCCESS ) ) { /* Stop looking if we have found a valid PDA */ - int err = 0; + err = 0; fd_pubkey_t * out_haddr = FD_VM_MEM_HADDR_ST_( vm, out_vaddr, FD_VM_ALIGN_RUST_U8, sizeof(fd_pubkey_t), &err ); if( FD_UNLIKELY( 0 != err ) ) { *_ret = 0UL;