LCOV - code coverage report
Current view: top level - flamenco/runtime/tests - fd_elf_harness.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 150 0.0 %
Date: 2025-11-25 04:50:41 Functions: 0 3 0.0 %

          Line data    Source code
       1             : #include "fd_solfuzz.h"
       2             : #include "fd_solfuzz_private.h"
       3             : #include "generated/elf.pb.h"
       4             : #include "../../../ballet/sbpf/fd_sbpf_loader.h"
       5             : #include "../program/fd_bpf_loader_program.h"
       6             : #include "../../vm/fd_vm_base.h"
       7             : #include "../../progcache/fd_prog_load.h"
       8             : 
       9             : #if FD_HAS_FLATCC
      10             : #include "flatbuffers/generated/flatbuffers_common_builder.h"
      11             : #include "flatbuffers/generated/flatbuffers_common_reader.h"
      12             : #include "flatbuffers/generated/elf_reader.h"
      13             : #include "flatbuffers/generated/elf_builder.h"
      14             : #endif
      15             : 
      16             : #define SORT_NAME        sort_ulong
      17           0 : #define SORT_KEY_T       ulong
      18           0 : #define SORT_BEFORE(a,b) (a)<(b)
      19             : #include "../../../util/tmpl/fd_sort.c"
      20             : 
      21             : ulong
      22             : fd_solfuzz_pb_elf_loader_run( fd_solfuzz_runner_t * runner,
      23             :                               void const *          input_,
      24             :                               void **               output_,
      25             :                               void *                output_buf,
      26           0 :                               ulong                 output_bufsz ) {
      27           0 :   fd_exec_test_elf_loader_ctx_t const * input  = fd_type_pun_const( input_ );
      28           0 :   fd_exec_test_elf_loader_effects_t **  output = fd_type_pun( output_ );
      29             : 
      30           0 :   fd_sbpf_elf_info_t info;
      31           0 :   fd_spad_t * spad = runner->spad;
      32             : 
      33           0 :   if( FD_UNLIKELY( !input->has_elf ) ) {
      34           0 :     return 0UL;
      35           0 :   }
      36             : 
      37             :   /* Occasionally testing elf_sz = 0 and NULL elf_bin */
      38           0 :   ulong  elf_sz  = 0UL;
      39           0 :   void * elf_bin = NULL;
      40           0 :   if( FD_LIKELY( input->elf.data ) ) {
      41           0 :     elf_sz  = input->elf.data->size;
      42           0 :     elf_bin = input->elf.data->bytes;
      43           0 :   }
      44             : 
      45             :   // Allocate space for captured effects
      46           0 :   ulong output_end = (ulong)output_buf + output_bufsz;
      47           0 :   FD_SCRATCH_ALLOC_INIT( l, output_buf );
      48             : 
      49           0 :   fd_exec_test_elf_loader_effects_t * elf_effects =
      50           0 :     FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_exec_test_elf_loader_effects_t),
      51           0 :                                 sizeof (fd_exec_test_elf_loader_effects_t) );
      52           0 :   if( FD_UNLIKELY( _l > output_end ) ) {
      53             :     /* return 0 on fuzz-specific failures */
      54           0 :     return 0UL;
      55           0 :   }
      56           0 :   fd_memset( elf_effects, 0, sizeof(fd_exec_test_elf_loader_effects_t) );
      57             : 
      58             :   /* wrap the loader code in do-while(0) block so that we can exit
      59             :      immediately if execution fails at any point */
      60           0 :   int err = FD_SBPF_ELF_SUCCESS;
      61           0 :   do{
      62           0 :     fd_features_t feature_set = {0};
      63           0 :     fd_solfuzz_pb_restore_features( &feature_set, &input->features );
      64             : 
      65           0 :     fd_sbpf_loader_config_t config = {
      66           0 :       .elf_deploy_checks = input->deploy_checks,
      67           0 :     };
      68             : 
      69           0 :     fd_prog_versions_t versions = fd_prog_versions( &feature_set, UINT_MAX );
      70           0 :     config.sbpf_min_version = versions.min_sbpf_version;
      71           0 :     config.sbpf_max_version = versions.max_sbpf_version;
      72             : 
      73           0 :     err = fd_sbpf_elf_peek( &info, elf_bin, elf_sz, &config );
      74           0 :     if( FD_UNLIKELY( err ) ) {
      75           0 :       break;
      76           0 :     }
      77             : 
      78           0 :     void *               rodata   = fd_spad_alloc_check( spad, FD_SBPF_PROG_RODATA_ALIGN, info.bin_sz );
      79           0 :     fd_sbpf_program_t *  prog     = fd_sbpf_program_new( fd_spad_alloc_check( spad, fd_sbpf_program_align(), fd_sbpf_program_footprint( &info ) ), &info, rodata );
      80           0 :     fd_sbpf_syscalls_t * syscalls = fd_sbpf_syscalls_new( fd_spad_alloc_check( spad, fd_sbpf_syscalls_align(), fd_sbpf_syscalls_footprint() ));
      81             : 
      82             :     /* Register any syscalls given the active feature set */
      83           0 :     fd_vm_syscall_register_slot(
      84           0 :         syscalls,
      85           0 :         UINT_MAX /* Arbitrary slot, doesn't matter */,
      86           0 :         &feature_set,
      87           0 :         !!config.elf_deploy_checks );
      88             : 
      89           0 :     void * scratch = fd_spad_alloc( spad, 1UL, elf_sz );
      90           0 :     err = fd_sbpf_program_load( prog, elf_bin, elf_sz, syscalls, &config, scratch, elf_sz );
      91           0 :     if( FD_UNLIKELY( err ) ) {
      92           0 :       break;
      93           0 :     }
      94             : 
      95           0 :     fd_memset( elf_effects, 0, sizeof(fd_exec_test_elf_loader_effects_t) );
      96           0 :     elf_effects->rodata_sz = prog->rodata_sz;
      97             : 
      98             :     // Load rodata section
      99           0 :     elf_effects->rodata = FD_SCRATCH_ALLOC_APPEND(l, 8UL, PB_BYTES_ARRAY_T_ALLOCSIZE( prog->rodata_sz ));
     100           0 :     if( FD_UNLIKELY( _l > output_end ) ) {
     101           0 :       return 0UL;
     102           0 :     }
     103           0 :     elf_effects->rodata->size = (pb_size_t) prog->rodata_sz;
     104           0 :     fd_memcpy( elf_effects->rodata->bytes, prog->rodata, prog->rodata_sz );
     105             : 
     106           0 :     elf_effects->text_cnt = prog->info.text_cnt;
     107           0 :     elf_effects->text_off = prog->info.text_off;
     108           0 :     elf_effects->entry_pc = prog->entry_pc;
     109             : 
     110           0 :     pb_size_t max_calldests_sz = 1U;
     111           0 :     if( FD_LIKELY( prog->calldests ) ) {
     112           0 :       max_calldests_sz += (pb_size_t)fd_sbpf_calldests_cnt( prog->calldests);
     113           0 :     }
     114             : 
     115           0 :     elf_effects->calldests     = FD_SCRATCH_ALLOC_APPEND(l, 8UL, max_calldests_sz * sizeof(uint64_t));
     116           0 :     if( FD_UNLIKELY( _l > output_end ) ) {
     117           0 :       return 0UL;
     118           0 :     }
     119             : 
     120             :     /* Add the entrypoint to the calldests */
     121           0 :     elf_effects->calldests[elf_effects->calldests_count++] = prog->entry_pc;
     122             : 
     123             :     /* Add the rest of the calldests */
     124           0 :     if( FD_LIKELY( prog->calldests ) ) {
     125           0 :       for( ulong target_pc=fd_sbpf_calldests_const_iter_init(prog->calldests);
     126           0 :                           !fd_sbpf_calldests_const_iter_done(target_pc);
     127           0 :                 target_pc=fd_sbpf_calldests_const_iter_next(prog->calldests, target_pc) ) {
     128           0 :         if( FD_LIKELY( target_pc!=prog->entry_pc ) ) {
     129           0 :           elf_effects->calldests[elf_effects->calldests_count++] = target_pc;
     130           0 :         }
     131           0 :       }
     132           0 :     }
     133             : 
     134             :     /* Sort the calldests in ascending order */
     135           0 :     sort_ulong_inplace( elf_effects->calldests, elf_effects->calldests_count );
     136           0 :   } while(0);
     137             : 
     138           0 :   elf_effects->error = -err;
     139           0 :   ulong actual_end = FD_SCRATCH_ALLOC_FINI( l, 1UL );
     140             : 
     141           0 :   *output = elf_effects;
     142           0 :   return actual_end - (ulong) output_buf;
     143           0 : }
     144             : 
     145             : #if FD_HAS_FLATCC
     146             : 
     147             : void
     148           0 : fd_solfuzz_fb_elf_loader_build_err_effects( fd_solfuzz_runner_t * runner, int err ) {
     149           0 :   FD_TEST( !SOL_COMPAT_NS(ELFLoaderEffects_start_as_root)( runner->fb_builder ) );
     150           0 :   FD_TEST( !SOL_COMPAT_NS(ELFLoaderEffects_err_code_add)( runner->fb_builder, (uchar)(-err) ) );
     151           0 :   FD_TEST( SOL_COMPAT_NS(ELFLoaderEffects_end_as_root)( runner->fb_builder ) );
     152           0 : }
     153             : 
     154             : int
     155             : fd_solfuzz_fb_elf_loader_run( fd_solfuzz_runner_t * runner,
     156           0 :                               void const *          input_ ) {
     157           0 :   SOL_COMPAT_NS(ELFLoaderCtx_table_t) input = fd_type_pun_const( input_ );
     158             : 
     159           0 :   fd_spad_t *             spad     = runner->spad;
     160           0 :   flatbuffers_uint8_vec_t elf_bin_ = SOL_COMPAT_NS(ELFLoaderCtx_elf_data( input ));
     161           0 :   uchar const *           elf_bin  = (uchar const*)elf_bin_;
     162           0 :   ulong                   elf_sz   = flatbuffers_uint8_vec_len( elf_bin_ );
     163             : 
     164             :   /* Restore feature set */
     165           0 :   fd_features_t feature_set = {0};
     166           0 :   fd_solfuzz_fb_restore_features( &feature_set, SOL_COMPAT_NS(ELFLoaderCtx_features( input )));
     167             : 
     168           0 :   fd_sbpf_loader_config_t config = {
     169           0 :     .elf_deploy_checks = SOL_COMPAT_NS(ELFLoaderCtx_deploy_checks( input )),
     170           0 :   };
     171             : 
     172           0 :   fd_prog_versions_t versions = fd_prog_versions( &feature_set, UINT_MAX );
     173           0 :   config.sbpf_min_version = versions.min_sbpf_version;
     174           0 :   config.sbpf_max_version = versions.max_sbpf_version;
     175             : 
     176             :   /* Peek */
     177           0 :   fd_sbpf_elf_info_t info;
     178           0 :   int err = fd_sbpf_elf_peek( &info, elf_bin, elf_sz, &config );
     179           0 :   if( err ) {
     180           0 :     fd_solfuzz_fb_elf_loader_build_err_effects( runner, err );
     181           0 :     return SOL_COMPAT_V2_SUCCESS;
     182           0 :   }
     183             : 
     184             :   /* Set up loading context */
     185           0 :   void *               rodata         = fd_spad_alloc_check( spad, FD_SBPF_PROG_RODATA_ALIGN, info.bin_sz );
     186           0 :   fd_sbpf_program_t *  prog           = fd_sbpf_program_new( fd_spad_alloc_check( spad, fd_sbpf_program_align(), fd_sbpf_program_footprint( &info ) ), &info, rodata );
     187           0 :   fd_sbpf_syscalls_t * syscalls       = fd_sbpf_syscalls_new( fd_spad_alloc_check( spad, fd_sbpf_syscalls_align(), fd_sbpf_syscalls_footprint() ));
     188           0 :   void *               rodata_scratch = fd_spad_alloc_check( spad, 1UL, elf_sz );
     189             : 
     190             :   /* Register syscalls given the active feature set. We can pass in an
     191             :      arbitrary slot as its just used to check if features should be
     192             :      active or not. */
     193           0 :   FD_TEST( !fd_vm_syscall_register_slot( syscalls, UINT_MAX, &feature_set, !!config.elf_deploy_checks ) );
     194             : 
     195             :   /* Load */
     196           0 :   err = fd_sbpf_program_load( prog, elf_bin, elf_sz, syscalls, &config, rodata_scratch, elf_sz );
     197           0 :   if( err ) {
     198           0 :     fd_solfuzz_fb_elf_loader_build_err_effects( runner, err );
     199           0 :     return SOL_COMPAT_V2_SUCCESS;
     200           0 :   }
     201             : 
     202             :   /**** Capture effects ****/
     203             : 
     204             :   /* Error code */
     205           0 :   uchar out_err_code = FD_SBPF_ELF_SUCCESS;
     206             : 
     207             :   /* Rodata */
     208           0 :   ulong out_rodata_hash_u64 = fd_hash( 0UL, prog->rodata, prog->rodata_sz );
     209           0 :   SOL_COMPAT_NS(XXHash_t) out_rodata_hash;
     210           0 :   fd_memcpy( out_rodata_hash.hash, &out_rodata_hash_u64, sizeof(ulong) );
     211             : 
     212             :   /* Text count */
     213           0 :   ulong out_text_cnt = prog->info.text_cnt;
     214             : 
     215             :   /* Text off */
     216           0 :   ulong out_text_off = prog->info.text_off;
     217             : 
     218             :   /* Entry PC */
     219           0 :   ulong out_entry_pc = prog->entry_pc;
     220             : 
     221             :   /* Calldests */
     222           0 :   ulong   max_out_calldests_cnt = 1UL + ( prog->calldests ? fd_sbpf_calldests_cnt( prog->calldests ) : 0UL );
     223           0 :   ulong * tmp_out_calldests     = fd_spad_alloc_check( spad, alignof(ulong), sizeof(ulong)*max_out_calldests_cnt );
     224           0 :   ulong   out_calldests_cnt     = 0UL;
     225             : 
     226             :   /* Add the entrypoint to the calldests */
     227           0 :   tmp_out_calldests[out_calldests_cnt++] = prog->entry_pc;
     228             : 
     229             :   /* Add the rest of the calldests */
     230           0 :   if( FD_LIKELY( prog->calldests ) ) {
     231           0 :     for( ulong target_pc=fd_sbpf_calldests_const_iter_init(prog->calldests);
     232           0 :                         !fd_sbpf_calldests_const_iter_done(target_pc);
     233           0 :                target_pc=fd_sbpf_calldests_const_iter_next(prog->calldests, target_pc) ) {
     234           0 :       if( FD_LIKELY( target_pc!=prog->entry_pc ) ) {
     235           0 :         tmp_out_calldests[out_calldests_cnt++] = target_pc;
     236           0 :       }
     237           0 :     }
     238           0 :   }
     239             : 
     240             :   /* Sort the calldests in ascending order */
     241           0 :   sort_ulong_inplace( tmp_out_calldests, out_calldests_cnt );
     242             : 
     243             :   /* Create output calldests vector */
     244           0 :   ulong out_calldests_hash_u64 = fd_hash( 0UL, tmp_out_calldests, sizeof(ulong) * out_calldests_cnt );
     245           0 :   SOL_COMPAT_NS(XXHash_t) out_calldests_hash;
     246           0 :   fd_memcpy( out_calldests_hash.hash, &out_calldests_hash_u64, sizeof(ulong) );
     247             : 
     248             :   /* Build effects */
     249           0 :   SOL_COMPAT_NS(ELFLoaderEffects_create_as_root)( runner->fb_builder, out_err_code, &out_rodata_hash, out_text_cnt, out_text_off, out_entry_pc, &out_calldests_hash );
     250             : 
     251           0 :   return SOL_COMPAT_V2_SUCCESS;
     252           0 : }
     253             : 
     254             : #endif /* FD_HAS_FLATCC */

Generated by: LCOV version 1.14