LCOV - code coverage report
Current view: top level - flamenco/runtime/tests - fd_sol_compat.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 208 0.0 %
Date: 2025-12-18 05:07:35 Functions: 0 13 0.0 %

          Line data    Source code
       1             : #include "fd_solfuzz.h"
       2             : #include "fd_solfuzz_private.h"
       3             : #define _GNU_SOURCE
       4             : #include "fd_sol_compat.h"
       5             : 
       6             : #include "../fd_executor_err.h"
       7             : #include "../../capture/fd_solcap_writer.h"
       8             : #include "../../../ballet/shred/fd_shred.h"
       9             : 
      10             : #include "generated/block.pb.h"
      11             : #include "generated/elf.pb.h"
      12             : #include "generated/invoke.pb.h"
      13             : #include "generated/shred.pb.h"
      14             : #include "generated/vm.pb.h"
      15             : #include "generated/txn.pb.h"
      16             : 
      17             : #if FD_HAS_FLATCC
      18             : #include "flatbuffers/generated/elf_reader.h"
      19             : #include "flatbuffers/generated/flatbuffers_common_reader.h"
      20             : #endif
      21             : 
      22             : #include <assert.h>
      23             : #include <errno.h>
      24             : #include <fcntl.h>
      25             : #include <stdio.h>
      26             : #include <unistd.h>
      27             : 
      28             : static fd_wksp_t *           wksp   = NULL;
      29             : static fd_solfuzz_runner_t * runner = NULL;
      30             : 
      31             : static fd_solfuzz_runner_t *
      32           0 : sol_compat_setup_runner( fd_solfuzz_runner_options_t const * options ) {
      33           0 :   runner = fd_solfuzz_runner_new( wksp, 3UL, options );
      34           0 :   if( FD_UNLIKELY( !runner ) ) {
      35           0 :     FD_LOG_ERR(( "fd_solfuzz_runner_new() failed" ));
      36           0 :     return NULL;
      37           0 :   }
      38             : 
      39           0 :   char const * solcap_path = getenv( "FD_SOLCAP" );
      40           0 :   if( solcap_path ) {
      41           0 :     int fd = open( solcap_path, O_WRONLY | O_CREAT | O_TRUNC, 0644 );
      42           0 :     if( FD_UNLIKELY( fd == -1 ) ) {
      43           0 :       FD_LOG_ERR(( "open($FD_SOLCAP=%s) failed (%i-%s)", solcap_path, errno, fd_io_strerror( errno ) ));
      44           0 :     }
      45           0 :     runner->solcap_file = (void *)(ulong)fd;
      46           0 :     FD_LOG_NOTICE(( "Logging to solcap file %s", solcap_path ));
      47             : 
      48           0 :     void * solcap_mem = fd_wksp_alloc_laddr( runner->wksp, fd_solcap_writer_align(), fd_solcap_writer_footprint(), 1UL );
      49           0 :     runner->solcap = fd_solcap_writer_init( solcap_mem, fd );
      50           0 :     FD_TEST( runner->solcap );
      51           0 :   }
      52             : 
      53           0 :   return runner;
      54           0 : }
      55             : 
      56             : static void
      57           0 : sol_compat_cleanup_runner( fd_solfuzz_runner_t * runner ) {
      58             :   /* Cleanup test runner */
      59           0 :   if( runner->solcap ) {
      60           0 :     fd_wksp_free_laddr( ( runner->solcap ) );
      61           0 :     runner->solcap = NULL;
      62           0 :     if( runner->solcap_file ) {
      63           0 :       close( (int)(ulong)runner->solcap_file );
      64           0 :       runner->solcap_file = NULL;
      65           0 :     }
      66           0 :   }
      67           0 :   fd_solfuzz_runner_delete( runner );
      68           0 : }
      69             : 
      70             : void
      71           0 : sol_compat_init( int log_level ) {
      72           0 :   int argc = 1;
      73           0 :   char * argv[2] = { (char *)"fd_exec_sol_compat", NULL };
      74           0 :   char ** argv_ = argv;
      75           0 :   if( !getenv( "FD_LOG_PATH" ) ) {
      76           0 :     setenv( "FD_LOG_PATH", "", 1 );
      77           0 :   }
      78             : 
      79           0 :   char const * enable_vm_tracing_env  = getenv( "ENABLE_VM_TRACING");
      80           0 :   int enable_vm_tracing               = enable_vm_tracing_env!=NULL;
      81           0 :   fd_solfuzz_runner_options_t options = {
      82           0 :     .enable_vm_tracing = enable_vm_tracing
      83           0 :   };
      84             : 
      85           0 :   fd_log_enable_unclean_exit();
      86           0 :   fd_boot( &argc, &argv_ );
      87             : 
      88           0 :   if( FD_UNLIKELY( wksp || runner ) ) {
      89           0 :     FD_LOG_ERR(( "sol_compat_init() called multiple times" ));
      90           0 :   }
      91             : 
      92           0 :   ulong footprint = 7UL<<30;
      93           0 :   ulong part_max  = fd_wksp_part_max_est( footprint, 64UL<<10 );
      94           0 :   ulong data_max  = fd_wksp_data_max_est( footprint, part_max );
      95           0 :   wksp = fd_wksp_demand_paged_new( "sol_compat", 42U, part_max, data_max );
      96           0 :   if( FD_UNLIKELY( !wksp ) ) FD_LOG_ERR(( "fd_wksp_demand_paged_new() failed" ));
      97             : 
      98           0 :   runner = sol_compat_setup_runner( &options );
      99           0 :   if( FD_UNLIKELY( !runner ) ) FD_LOG_ERR(( "sol_compat_setup_runner() failed" ));
     100             : 
     101           0 :   fd_log_level_logfile_set( log_level );
     102           0 :   fd_log_level_core_set(4);  /* abort on FD_LOG_ERR */
     103           0 : }
     104             : 
     105             : void
     106           0 : sol_compat_fini( void ) {
     107           0 :   sol_compat_cleanup_runner( runner );
     108           0 :   fd_wksp_delete_anonymous( wksp );
     109           0 :   wksp   = NULL;
     110           0 :   runner = NULL;
     111           0 :   fd_halt();
     112           0 : }
     113             : 
     114             : sol_compat_features_t const *
     115           0 : sol_compat_get_features_v1( void ) {
     116           0 :   static sol_compat_features_t features;
     117           0 :   static ulong hardcoded_features[ FD_FEATURE_ID_CNT ];
     118           0 :   static ulong supported_features[ FD_FEATURE_ID_CNT ];
     119             : 
     120           0 :   FD_ONCE_BEGIN {
     121           0 :     features.struct_size = sizeof(sol_compat_features_t);
     122           0 :     features.hardcoded_features = hardcoded_features;
     123           0 :     features.supported_features = supported_features;
     124           0 :     for( fd_feature_id_t const * iter = fd_feature_iter_init();
     125           0 :          !fd_feature_iter_done( iter );
     126           0 :          iter = fd_feature_iter_next( iter ) ) {
     127           0 :       if( iter->reverted ) continue; /* skip reverted features */
     128             : 
     129             :       /* Pretend that features activated on all clusters are hardcoded */
     130           0 :       if( iter->hardcode_for_fuzzing ) {
     131           0 :         hardcoded_features[ features.hardcoded_features_cnt++ ] = iter->id.ul[0];
     132           0 :       } else {
     133           0 :         supported_features[ features.supported_feature_cnt++  ] = iter->id.ul[0];
     134           0 :       }
     135           0 :     }
     136           0 :   }
     137           0 :   FD_ONCE_END;
     138             : 
     139           0 :   return &features;
     140           0 : }
     141             : 
     142             : /*
     143             :  * execute_v1
     144             :  */
     145             : 
     146             : int
     147             : sol_compat_instr_execute_v1( uchar *       out,
     148             :                              ulong *       out_sz,
     149             :                              uchar const * in,
     150           0 :                              ulong         in_sz ) {
     151           0 :   fd_exec_test_instr_context_t input[1] = {0};
     152           0 :   void * res = sol_compat_decode_lenient( &input, in, in_sz, &fd_exec_test_instr_context_t_msg );
     153           0 :   if( FD_UNLIKELY( !res ) ) return 0;
     154             : 
     155           0 :   int ok = 0;
     156           0 :   fd_spad_push( runner->spad );
     157           0 :   void * output = NULL;
     158           0 :   fd_solfuzz_pb_execute_wrapper( runner, input, &output, fd_solfuzz_pb_instr_run );
     159           0 :   if( output ) {
     160           0 :     ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_instr_effects_t_msg );
     161           0 :   }
     162           0 :   fd_spad_pop( runner->spad );
     163             : 
     164           0 :   pb_release( &fd_exec_test_instr_context_t_msg, input );
     165           0 :   fd_solfuzz_runner_leak_check( runner );
     166           0 :   return ok;
     167           0 : }
     168             : 
     169             : int
     170             : sol_compat_txn_execute_v1( uchar *       out,
     171             :                            ulong *       out_sz,
     172             :                            uchar const * in,
     173           0 :                            ulong         in_sz ) {
     174           0 :   fd_exec_test_txn_context_t input[1] = {0};
     175           0 :   void * res = sol_compat_decode_lenient( &input, in, in_sz, &fd_exec_test_txn_context_t_msg );
     176           0 :   if( FD_UNLIKELY( !res ) ) return 0;
     177             : 
     178           0 :   int ok = 0;
     179           0 :   fd_spad_push( runner->spad );
     180           0 :   void * output = NULL;
     181           0 :   fd_solfuzz_pb_execute_wrapper( runner, input, &output, fd_solfuzz_pb_txn_run );
     182           0 :   if( output ) {
     183           0 :     ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_txn_result_t_msg );
     184           0 :   }
     185           0 :   fd_spad_pop( runner->spad );
     186             : 
     187           0 :   pb_release( &fd_exec_test_txn_context_t_msg, input );
     188           0 :   fd_solfuzz_runner_leak_check( runner );
     189           0 :   return ok;
     190           0 : }
     191             : 
     192             : int
     193             : sol_compat_block_execute_v1( uchar *       out,
     194             :                              ulong *       out_sz,
     195             :                              uchar const * in,
     196           0 :                              ulong         in_sz ) {
     197           0 :   fd_exec_test_block_context_t input[1] = {0};
     198           0 :   void * res = sol_compat_decode_lenient( &input, in, in_sz, &fd_exec_test_block_context_t_msg );
     199           0 :   if( FD_UNLIKELY( !res ) ) return 0;
     200             : 
     201           0 :   fd_spad_push( runner->spad );
     202           0 :   int ok = 0;
     203           0 :   void * output = NULL;
     204           0 :   fd_solfuzz_pb_execute_wrapper( runner, input, &output, fd_solfuzz_pb_block_run );
     205           0 :   if( output ) {
     206           0 :     ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_block_effects_t_msg );
     207           0 :   }
     208           0 :   fd_spad_pop( runner->spad );
     209             : 
     210           0 :   pb_release( &fd_exec_test_block_context_t_msg, input );
     211           0 :   fd_solfuzz_runner_leak_check( runner );
     212           0 :   return ok;
     213           0 : }
     214             : 
     215             : int
     216             : sol_compat_elf_loader_v1( uchar *       out,
     217             :                           ulong *       out_sz,
     218             :                           uchar const * in,
     219           0 :                           ulong         in_sz ) {
     220           0 :   fd_exec_test_elf_loader_ctx_t input[1] = {0};
     221           0 :   void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_elf_loader_ctx_t_msg );
     222           0 :   if( FD_UNLIKELY( !res ) ) return 0;
     223             : 
     224           0 :   fd_spad_push( runner->spad );
     225           0 :   int ok = 0;
     226           0 :   void * output = NULL;
     227           0 :   fd_solfuzz_pb_execute_wrapper( runner, input, &output, fd_solfuzz_pb_elf_loader_run );
     228           0 :   if( output ) {
     229           0 :     ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_elf_loader_effects_t_msg );
     230           0 :   }
     231           0 :   fd_spad_pop( runner->spad );
     232             : 
     233           0 :   pb_release( &fd_exec_test_elf_loader_ctx_t_msg, input );
     234           0 :   fd_solfuzz_runner_leak_check( runner );
     235           0 :   return ok;
     236           0 : }
     237             : 
     238             : int
     239             : sol_compat_vm_syscall_execute_v1( uchar *       out,
     240             :                                   ulong *       out_sz,
     241             :                                   uchar const * in,
     242           0 :                                   ulong         in_sz ) {
     243           0 :   fd_exec_test_syscall_context_t input[1] = {0};
     244           0 :   void * res = sol_compat_decode_lenient( &input, in, in_sz, &fd_exec_test_syscall_context_t_msg );
     245           0 :   if( FD_UNLIKELY( !res ) ) return 0;
     246             : 
     247           0 :   fd_spad_push( runner->spad );
     248           0 :   int ok = 0;
     249           0 :   void * output = NULL;
     250           0 :   fd_solfuzz_pb_execute_wrapper( runner, input, &output, fd_solfuzz_pb_syscall_run );
     251           0 :   if( output ) {
     252           0 :     ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_syscall_effects_t_msg );
     253           0 :   }
     254           0 :   fd_spad_pop( runner->spad );
     255             : 
     256           0 :   pb_release( &fd_exec_test_syscall_context_t_msg, input );
     257           0 :   fd_solfuzz_runner_leak_check( runner );
     258           0 :   return ok;
     259           0 : }
     260             : 
     261             : int
     262             : sol_compat_vm_interp_v1( uchar *       out,
     263             :                          ulong *       out_sz,
     264             :                          uchar const * in,
     265           0 :                          ulong         in_sz ) {
     266           0 :   fd_exec_test_syscall_context_t input[1] = {0};
     267           0 :   void * res = sol_compat_decode_lenient( &input, in, in_sz, &fd_exec_test_syscall_context_t_msg );
     268           0 :   if( FD_UNLIKELY( !res ) ) return 0;
     269             : 
     270           0 :   fd_spad_push( runner->spad );
     271           0 :   int ok = 0;
     272           0 :   void * output = NULL;
     273           0 :   fd_solfuzz_pb_execute_wrapper( runner, input, &output, fd_solfuzz_pb_vm_interp_run );
     274           0 :   if( output ) {
     275           0 :     ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_syscall_effects_t_msg );
     276           0 :   }
     277           0 :   fd_spad_pop( runner->spad );
     278             : 
     279           0 :   pb_release( &fd_exec_test_syscall_context_t_msg, input );
     280           0 :   fd_solfuzz_runner_leak_check( runner );
     281           0 :   return ok;
     282           0 : }
     283             : 
     284             : int
     285             : sol_compat_shred_parse_v1( uchar *       out,
     286             :                            ulong *       out_sz,
     287             :                            uchar const * in,
     288           0 :                            ulong         in_sz ) {
     289           0 :     fd_exec_test_shred_binary_t input[1] = {0};
     290           0 :     void                      * res      = sol_compat_decode_lenient( &input, in, in_sz, &fd_exec_test_shred_binary_t_msg );
     291           0 :     if( FD_UNLIKELY( res==NULL ) ) {
     292           0 :         return 0;
     293           0 :     }
     294           0 :     if( FD_UNLIKELY( input[0].data==NULL ) ) {
     295           0 :         pb_release( &fd_exec_test_shred_binary_t_msg, input );
     296           0 :         return 0;
     297           0 :     }
     298           0 :     fd_exec_test_accepts_shred_t output[1] = {0};
     299           0 :     output[0].valid                        = !!fd_shred_parse( input[0].data->bytes, input[0].data->size );
     300           0 :     pb_release( &fd_exec_test_shred_binary_t_msg, input );
     301           0 :     return !!sol_compat_encode( out, out_sz, output, &fd_exec_test_accepts_shred_t_msg );
     302           0 : }
     303             : 
     304             : /*
     305             :  * execute_v2
     306             :    Unlike sol_compat_execute_v1 APIs, v2 APIs use flatbuffers for
     307             :    zero-copy decoding. Returns SOL_COMPAT_V2_SUCCESS on success and
     308             :    SOL_COMPAT_V2_FAILURE on failure.
     309             : 
     310             :    out: output buffer
     311             :    out_sz: output buffer size
     312             :    in: input buffer
     313             :    in_sz: input buffer size (unused)
     314             : 
     315             :    Since flatbuffers utilizes zero-copy decoding, the v2 API does not
     316             :    require an input buffer size. Therefore, it is the caller's
     317             :    responsibility to ensure the input buffer is well-formed (preferably
     318             :    using a call to _verify_as_root) to avoid any OOB reads.
     319             : 
     320             :    TODO: Make sol_compat_v2 APIs infallible???
     321             :  */
     322             : 
     323             : #if FD_HAS_FLATCC
     324             : 
     325             : int
     326             : sol_compat_elf_loader_v2( uchar *            out,
     327             :                           ulong *            out_sz,
     328             :                           uchar const *      in,
     329           0 :                           ulong FD_FN_UNUSED in_sz ) {
     330           0 :   SOL_COMPAT_NS(ELFLoaderCtx_table_t) input = SOL_COMPAT_NS(ELFLoaderCtx_as_root( in ));
     331           0 :   if( FD_UNLIKELY( !input ) ) return 0;
     332             : 
     333           0 :   int err = fd_solfuzz_fb_execute_wrapper( runner, input, fd_solfuzz_fb_elf_loader_run );
     334           0 :   if( FD_UNLIKELY( err==SOL_COMPAT_V2_FAILURE ) ) return err;
     335             : 
     336           0 :   ulong buffer_sz = flatcc_builder_get_buffer_size( runner->fb_builder );
     337           0 :   flatcc_builder_copy_buffer( runner->fb_builder, out, buffer_sz );
     338           0 :   *out_sz = buffer_sz;
     339             : 
     340           0 :   return SOL_COMPAT_V2_SUCCESS;
     341           0 : }
     342             : 
     343             : #endif /* FD_HAS_FLATCC */

Generated by: LCOV version 1.14