Skip to content

Commit

Permalink
ballet, sbpf loader: manually register entrypoint to calldests
Browse files Browse the repository at this point in the history
address PR feedback

add unit test

incorrect makefile params

reformat test file
  • Loading branch information
ravyu-jump committed May 16, 2024
1 parent ec41e5b commit d728b24
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 6 deletions.
2 changes: 2 additions & 0 deletions src/ballet/sbpf/Local.mk
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@ $(call add-hdrs,fd_sbpf_instr.h fd_sbpf_loader.h fd_sbpf_opcodes.h)
$(call add-objs,fd_sbpf_loader,fd_ballet)
ifdef FD_HAS_HOSTED
$(call make-unit-test,test_sbpf_load_prog,test_sbpf_load_prog,fd_ballet fd_util)
$(call make-unit-test,test_sbpf_loader,test_sbpf_loader,fd_ballet fd_util)
$(call run-unit-test,test_sbpf_loader)
endif
$(call make-fuzz-test,fuzz_sbpf_loader,fuzz_sbpf_loader,fd_ballet fd_util)
16 changes: 10 additions & 6 deletions src/ballet/sbpf/fd_sbpf_loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -937,15 +937,17 @@ fd_sbpf_r_bpf_64_32( fd_sbpf_loader_t const * loader,
/* Register new entry */
uint hash;
if( name_len >= 10UL && 0==strncmp( name, "entrypoint", name_len ) ) {
/* TODO register entrypoint */
/* Skip insertion of "entrypoint" relocation entries to calldests. This
emulates Solana/Agave's behavior of unregistering these entries before
registering the entrypoint manually.
Entrypoint is registered in fd_sbpf_program_load.
Hash is still applied. */
hash = 0x71e3cf81;
} else {
hash = fd_murmur3_32( &target_pc, 8UL, 0U );
if( FD_LIKELY( target_pc < (info->rodata_sz / 8UL ) ) )
fd_sbpf_calldests_insert( loader->calldests, target_pc );
}

if( FD_LIKELY( target_pc < (info->rodata_sz / 8UL ) ) )
fd_sbpf_calldests_insert( loader->calldests, target_pc );

V = (uint)hash;
} else {
/* FIXME Should cache Murmur hashes.
Expand Down Expand Up @@ -1028,7 +1030,6 @@ fd_sbpf_hash_calls( fd_sbpf_loader_t * loader,
ulong target_pc = (ulong)target_pc_s;
REQUIRE( target_pc<insn_cnt ); /* bounds check target */

/* Derive hash and insert */
fd_sbpf_calldests_insert( calldests, target_pc );

/* Replace immediate with hash */
Expand Down Expand Up @@ -1191,6 +1192,9 @@ fd_sbpf_program_load( fd_sbpf_program_t * prog,
/* Load dynamic section */
if( FD_UNLIKELY( (err=fd_sbpf_load_dynamic( &loader, elf, elf_sz ))!=0 ) )
return err;

/* Register entrypoint to calldests. */
fd_sbpf_calldests_insert( prog->calldests, prog->entry_pc );

/* Copy rodata segment */
fd_memcpy( prog->rodata, elf->bin, prog->info.rodata_footprint );
Expand Down
Binary file not shown.
80 changes: 80 additions & 0 deletions src/ballet/sbpf/test_sbpf_loader.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#include "fd_sbpf_loader.h"
#include "../../util/fd_util.h"

uint const _syscalls[] = {
0xb6fc1a11, 0x686093bb, 0x207559bd, 0x5c2a3178, 0x52ba5096,
0x7ef088ca, 0x9377323c, 0x48504a38, 0x11f49d86, 0xd7793abb,
0x17e40350, 0x174c5122, 0xaa2607ca, 0xdd1c41a6, 0xd56b5fe9,
0x23a29a61, 0x3b97b73c, 0xbf7188f6, 0x717cc4a3, 0x434371f8,
0x5fdcde31, 0x3770fb22, 0xa22b9c85, 0xd7449092, 0x83f00e8f,
0xa226d3eb, 0x5d2245e4, 0x7317b434, 0xadb8efc8, 0x85532d94,
0U
};

#define LOAD_ELF(id) \
FD_IMPORT_BINARY( id##_elf, "src/ballet/sbpf/fixtures/" #id ".elf" );

LOAD_ELF( duplicate_entrypoint_entry )

/* Properties of duplicate_entrypoint_entry.elf we are testing:
* Two symbol entries with the "entrypoint" as st_name:
Num: Value Size Type Bind Vis Ndx Name
21: 0000000000001380 1264 FUNC GLOBAL DEFAULT 1 entrypoint
30: 0000000000007b68 1392 FUNC GLOBAL DEFAULT 1 entrypoint
- Second entry is the actual entrypoint
- First entry is a bad dynsym entry
- First entry would be PC 595
- This entry should not be registered in calldests
- So in a call to fd_sbpf_calldests_test( prog->calldests, 595 ), we should get 0
* Entrypoint is not referenced in text section or relocation table
- Yet it must be in calldests, since we register it by default
- So in a call to fd_sbpf_calldests_test( prog->calldests, 3920 ), we should still get 1
*/

void test_duplicate_entrypoint_entry( void ) {
// TODO: boilerplate
fd_valloc_t valloc = fd_scratch_virtual();
fd_sbpf_elf_info_t info;

fd_sbpf_elf_peek( &info, duplicate_entrypoint_entry_elf, duplicate_entrypoint_entry_elf_sz );

void* rodata = fd_valloc_malloc( valloc, 8UL, info.rodata_footprint );
FD_TEST( rodata );



fd_sbpf_program_t * prog = fd_sbpf_program_new( fd_valloc_malloc( valloc, fd_sbpf_program_align(), fd_sbpf_program_footprint( &info ) ), &info, rodata );

fd_sbpf_syscalls_t * syscalls = fd_sbpf_syscalls_new( fd_valloc_malloc( valloc, fd_sbpf_syscalls_align(), fd_sbpf_syscalls_footprint() ));
for( uint const * x = _syscalls; *x; x++ )
fd_sbpf_syscalls_insert( syscalls, *x );

int res = fd_sbpf_program_load( prog, duplicate_entrypoint_entry_elf, duplicate_entrypoint_entry_elf_sz, syscalls );
FD_TEST( res == 0 );

// end of boilerplate

FD_TEST( fd_sbpf_calldests_test( prog->calldests, 595 ) == 0 );
FD_TEST( fd_sbpf_calldests_test( prog->calldests, 3920 ) == 1 );

}

int
main( int argc,
char ** argv ) {
fd_boot( &argc, &argv );

static uchar scratch_mem [ 1<<25 ]; /* 32MB */
static ulong scratch_fmem[ 4UL ] __attribute((aligned(FD_SCRATCH_FMEM_ALIGN)));
fd_scratch_attach( scratch_mem, scratch_fmem, 1UL<<25, 4UL );

// testing here
test_duplicate_entrypoint_entry();

fd_scratch_detach( NULL );
fd_halt();
return 0;
}

0 comments on commit d728b24

Please sign in to comment.