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 */
|