Line data Source code
1 : #include "fd_accdb_svm.h"
2 : #include "sysvar/fd_sysvar_rent.h"
3 : #include "program/fd_bpf_loader_program.h"
4 : #include "program/fd_builtin_programs.h"
5 : #include "program/fd_program_util.h"
6 : #include "fd_runtime_stack.h"
7 : #include "fd_pubkey_utils.h"
8 : #include "fd_system_ids.h"
9 : #include "../accdb/fd_accdb_sync.h"
10 : #include "../../ballet/sha256/fd_sha256.h"
11 : #include "../../ballet/sbpf/fd_sbpf_loader.h"
12 : #include "../progcache/fd_prog_load.h"
13 : #include "../vm/fd_vm.h"
14 : #include <assert.h>
15 :
16 : static fd_pubkey_t
17 0 : get_program_data_address( fd_pubkey_t const * program_addr ) {
18 0 : uchar const * seed = program_addr->uc;
19 0 : ulong seed_sz = 32UL;
20 0 : fd_pubkey_t out;
21 0 : uint custom_err;
22 0 : uchar out_bump_seed;
23 0 : int err = fd_pubkey_find_program_address( &fd_solana_bpf_loader_upgradeable_program_id, 1UL, &seed, &seed_sz, &out, &out_bump_seed, &custom_err );
24 0 : if( FD_UNLIKELY( err ) ) {
25 : /* https://github.com/anza-xyz/solana-sdk/blob/address%40v2.1.0/address/src/syscalls.rs#L277-L279 */
26 0 : FD_LOG_ERR(( "Unable to find a viable program address bump seed" ));
27 0 : }
28 0 : return out;
29 0 : }
30 :
31 : fd_tmp_account_t *
32 : tmp_account_new( fd_tmp_account_t * acc,
33 0 : ulong acc_sz ) {
34 0 : acc->data_sz = acc_sz;
35 0 : fd_memset( acc->data, 0, acc_sz );
36 0 : fd_memset( &acc->meta, 0, sizeof(fd_account_meta_t) );
37 0 : return acc;
38 0 : }
39 :
40 : fd_tmp_account_t *
41 : tmp_account_read( fd_tmp_account_t * acc,
42 : fd_accdb_user_t * accdb,
43 : fd_funk_txn_xid_t const * xid,
44 0 : fd_pubkey_t const * addr ) {
45 0 : fd_accdb_ro_t ro[1];
46 0 : if( FD_LIKELY( !fd_accdb_open_ro( accdb, ro, xid, addr ) ) ) return NULL;
47 0 : tmp_account_new( acc, fd_accdb_ref_data_sz( ro ) );
48 0 : acc->meta = *ro->meta;
49 0 : acc->addr = *addr;
50 0 : fd_memcpy( acc->data, fd_accdb_ref_data_const( ro ), fd_accdb_ref_data_sz( ro ) );
51 0 : acc->data_sz = fd_accdb_ref_data_sz( ro );
52 0 : fd_accdb_close_ro( accdb, ro );
53 0 : return acc;
54 0 : }
55 :
56 : void
57 : tmp_account_store( fd_tmp_account_t * acc,
58 : fd_accdb_user_t * accdb,
59 : fd_funk_txn_xid_t const * xid,
60 : fd_bank_t * bank,
61 0 : fd_capture_ctx_t * capture_ctx ) {
62 0 : if( FD_UNLIKELY( fd_pubkey_eq( &acc->addr, &fd_solana_system_program_id ) ) ) {
63 0 : FD_LOG_ERR(( "Attempted to write to the system program account" ));
64 0 : }
65 :
66 0 : fd_accdb_rw_t rw[1]; fd_accdb_svm_update_t update[1];
67 0 : FD_TEST( fd_accdb_svm_open_rw( accdb, bank, xid, rw, update, &acc->addr, acc->data_sz, FD_ACCDB_FLAG_CREATE ) );
68 :
69 0 : fd_accdb_ref_exec_bit_set( rw, acc->meta.executable );
70 0 : fd_accdb_ref_owner_set ( rw, acc->meta.owner );
71 0 : fd_accdb_ref_lamports_set( rw, acc->meta.lamports );
72 0 : fd_accdb_ref_data_set ( accdb, rw, acc->data, acc->data_sz );
73 :
74 0 : fd_accdb_svm_close_rw( accdb, bank, capture_ctx, rw, update );
75 0 : }
76 :
77 : /* https://github.com/anza-xyz/agave/blob/v3.0.2/runtime/src/bank/builtins/core_bpf_migration/target_core_bpf.rs#L12 */
78 :
79 : struct target_core_bpf {
80 : fd_pubkey_t program_address;
81 : fd_tmp_account_t * program_data_account;
82 : fd_pubkey_t upgrade_authority_address;
83 : uint has_upgrade_authority_address : 1;
84 : };
85 :
86 : typedef struct target_core_bpf target_core_bpf_t;
87 :
88 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L19 */
89 :
90 : struct target_builtin {
91 : fd_tmp_account_t * program_account;
92 : fd_pubkey_t program_data_address;
93 : ulong program_data_account_lamports;
94 : };
95 :
96 : typedef struct target_builtin target_builtin_t;
97 :
98 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L25-L91 */
99 :
100 : target_builtin_t *
101 : target_builtin_new_checked( target_builtin_t * target_builtin,
102 : fd_pubkey_t const * program_address,
103 : int migration_target,
104 : int relax_programdata_account_check_migration,
105 : fd_accdb_user_t * accdb,
106 : fd_funk_txn_xid_t const * xid,
107 0 : fd_runtime_stack_t * runtime_stack ) {
108 :
109 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L31-L53 */
110 :
111 0 : fd_tmp_account_t * program_account = &runtime_stack->bpf_migration.program_account;
112 0 : switch( migration_target ) {
113 0 : case FD_CORE_BPF_MIGRATION_TARGET_BUILTIN:
114 0 : if( FD_UNLIKELY( !tmp_account_read( program_account, accdb, xid, program_address ) ) ) {
115 : /* CoreBpfMigrationError::AccountNotFound(*program_address) */
116 0 : return NULL;
117 0 : }
118 0 : if( FD_UNLIKELY( 0!=memcmp( program_account->meta.owner, &fd_solana_native_loader_id, 32 ) ) ) {
119 : /* CoreBpfMigrationError::IncorrectOwner(*program_address) */
120 0 : return NULL;
121 0 : }
122 0 : break;
123 0 : case FD_CORE_BPF_MIGRATION_TARGET_STATELESS: {
124 : /* Program account should not exist */
125 0 : fd_accdb_ro_t ro[1];
126 0 : int progdata_exists = !!fd_accdb_open_ro( accdb, ro, xid, program_address );
127 0 : if( progdata_exists ) {
128 : /* CoreBpfMigrationError::AccountAlreadyExists(*program_address) */
129 0 : fd_accdb_close_ro( accdb, ro );
130 0 : return NULL;
131 0 : }
132 0 : break;
133 0 : }
134 0 : default:
135 0 : FD_LOG_ERR(( "invalid migration_target %d", migration_target ));
136 0 : }
137 :
138 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L55 */
139 :
140 0 : fd_pubkey_t program_data_address = get_program_data_address( program_address );
141 :
142 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L57-L82 */
143 :
144 0 : ulong program_data_account_lamports = 0UL;
145 0 : do {
146 : /* Program data account should not exist */
147 0 : fd_accdb_ro_t ro[1];
148 0 : int progdata_exists = !!fd_accdb_open_ro( accdb, ro, xid, &program_data_address );
149 :
150 : /* SIMD-0444: relax_programdata_account_check_migration
151 : https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L57-L70 */
152 0 : if( relax_programdata_account_check_migration ) {
153 : /* The program data account should not exist, but a system
154 : account with funded lamports is acceptable. */
155 0 : if( FD_UNLIKELY( progdata_exists ) ) {
156 0 : if( FD_UNLIKELY( !fd_pubkey_eq( fd_accdb_ref_owner( ro ), &fd_solana_system_program_id ) ) ) {
157 : /* CoreBpfMigrationError::ProgramHasDataAccount(*program_address) */
158 0 : fd_accdb_close_ro( accdb, ro );
159 0 : return NULL;
160 0 : } else {
161 0 : program_data_account_lamports = fd_accdb_ref_lamports( ro );
162 0 : fd_accdb_close_ro( accdb, ro );
163 0 : }
164 0 : }
165 0 : } else {
166 : /* If relax_programdata_account_check_migration is not enabled,
167 : we do not allow the program data account to exist at all. */
168 0 : if( FD_UNLIKELY( progdata_exists ) ) {
169 : /* CoreBpfMigrationError::AccountAlreadyExists(*program_address) */
170 0 : fd_accdb_close_ro( accdb, ro );
171 0 : return NULL;
172 0 : }
173 0 : }
174 0 : } while(0);
175 :
176 : /* https://github.com/anza-xyz/agave/blob/v3.0.2/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L63-L67 */
177 :
178 0 : *target_builtin = (target_builtin_t) {
179 0 : .program_account = program_account,
180 0 : .program_data_address = program_data_address,
181 0 : .program_data_account_lamports = program_data_account_lamports
182 0 : };
183 0 : return target_builtin;
184 0 : }
185 :
186 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/target_core_bpf.rs#L26-L93 */
187 : static target_core_bpf_t *
188 : target_core_bpf_new_checked( target_core_bpf_t * target_core_bpf,
189 : fd_pubkey_t const * program_address,
190 : fd_accdb_user_t * accdb,
191 : fd_funk_txn_xid_t const * xid,
192 0 : fd_runtime_stack_t * runtime_stack ) {
193 0 : fd_pubkey_t program_data_address = get_program_data_address( program_address );
194 :
195 : /* The program account should exist */
196 0 : fd_tmp_account_t * program_account = &runtime_stack->bpf_migration.program_account;
197 0 : if( FD_UNLIKELY( !tmp_account_read( program_account, accdb, xid, program_address ) ) ) {
198 0 : return NULL;
199 0 : }
200 :
201 : /* The program account should be owned by the upgradeable loader */
202 0 : if( FD_UNLIKELY( 0!=memcmp( program_account->meta.owner, &fd_solana_bpf_loader_upgradeable_program_id, sizeof(fd_pubkey_t) ) ) ) {
203 0 : return NULL;
204 0 : }
205 :
206 : /* The program account should be executable */
207 0 : if( FD_UNLIKELY( !program_account->meta.executable ) ) {
208 0 : return NULL;
209 0 : }
210 :
211 : /* Decode and validate program account state */
212 0 : fd_bpf_state_t program_state[1];
213 0 : if( FD_UNLIKELY( FD_EXECUTOR_INSTR_SUCCESS!=fd_bpf_loader_program_get_state( &program_account->meta, program_state ) ) ) {
214 0 : return NULL;
215 0 : }
216 0 : if( FD_UNLIKELY( program_state->discriminant!=FD_BPF_STATE_PROGRAM ) ) {
217 0 : return NULL;
218 0 : }
219 0 : if( FD_UNLIKELY( 0!=memcmp( &program_state->inner.program.programdata_address, &program_data_address, sizeof(fd_pubkey_t) ) ) ) {
220 0 : return NULL;
221 0 : }
222 :
223 : /* The program data account should exist */
224 0 : fd_tmp_account_t * program_data_account = &runtime_stack->bpf_migration.new_target_program;
225 0 : if( FD_UNLIKELY( !tmp_account_read( program_data_account, accdb, xid, &program_data_address ) ) ) {
226 0 : return NULL;
227 0 : }
228 :
229 : /* The program data account should be owned by the upgradeable loader */
230 0 : if( FD_UNLIKELY( 0!=memcmp( program_data_account->meta.owner, &fd_solana_bpf_loader_upgradeable_program_id, sizeof(fd_pubkey_t) ) ) ) {
231 0 : return NULL;
232 0 : }
233 :
234 : /* Decode and validate program data account state */
235 0 : fd_bpf_state_t programdata_state[1];
236 0 : if( FD_UNLIKELY( FD_EXECUTOR_INSTR_SUCCESS!=fd_bpf_loader_program_get_state( &program_data_account->meta, programdata_state ) ) ) {
237 0 : return NULL;
238 0 : }
239 0 : if( FD_UNLIKELY( programdata_state->discriminant!=FD_BPF_STATE_PROGRAM_DATA ) ) {
240 0 : return NULL;
241 0 : }
242 :
243 : /* Extract upgrade authority from program data state */
244 0 : fd_pubkey_t upgrade_authority_address;
245 0 : if( programdata_state->inner.program_data.has_upgrade_authority_address ) {
246 0 : upgrade_authority_address = programdata_state->inner.program_data.upgrade_authority_address;
247 0 : } else {
248 0 : fd_memset( &upgrade_authority_address, 0, sizeof(fd_pubkey_t) );
249 0 : }
250 :
251 0 : *target_core_bpf = (target_core_bpf_t) {
252 0 : .program_address = *program_address,
253 0 : .program_data_account = program_data_account,
254 0 : .upgrade_authority_address = upgrade_authority_address,
255 0 : .has_upgrade_authority_address = (uint)!!programdata_state->inner.program_data.has_upgrade_authority_address
256 0 : };
257 0 : return target_core_bpf;
258 0 : }
259 :
260 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L25-L82
261 :
262 : Agave uses a separate TargetBpfV2 struct, but it has the
263 : same layout as target_builtin_t so we reuse that. */
264 : static target_builtin_t *
265 : target_bpf_v2_new_checked( target_builtin_t * target_bpf_v2,
266 : fd_pubkey_t const * program_address,
267 : int allow_prefunded,
268 : fd_accdb_user_t * accdb,
269 : fd_funk_txn_xid_t const * xid,
270 0 : fd_runtime_stack_t * runtime_stack ) {
271 :
272 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L30-L33 */
273 0 : fd_tmp_account_t * program_account = &runtime_stack->bpf_migration.program_account;
274 0 : if( FD_UNLIKELY( !tmp_account_read( program_account, accdb, xid, program_address ) ) ) {
275 : /* CoreBpfMigrationError::AccountNotFound(*program_address) */
276 0 : return NULL;
277 0 : }
278 :
279 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L35-L38 */
280 0 : if( FD_UNLIKELY( 0!=memcmp( program_account->meta.owner, &fd_solana_bpf_loader_program_id, FD_PUBKEY_FOOTPRINT ) ) ) {
281 : /* CoreBpfMigrationError::IncorrectOwner(*program_address) */
282 0 : return NULL;
283 0 : }
284 :
285 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L40-L45 */
286 0 : if( FD_UNLIKELY( !program_account->meta.executable ) ) {
287 : /* CoreBpfMigrationError::ProgramAccountNotExecutable(*program_address) */
288 0 : return NULL;
289 0 : }
290 :
291 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L47 */
292 0 : fd_pubkey_t program_data_address = get_program_data_address( program_address );
293 :
294 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L49-L74 */
295 0 : ulong program_data_account_lamports = 0UL;
296 0 : do {
297 0 : fd_accdb_ro_t ro[1];
298 0 : int progdata_exists = !!fd_accdb_open_ro( accdb, ro, xid, &program_data_address );
299 :
300 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L49-L74 */
301 0 : if( FD_LIKELY( allow_prefunded ) ) {
302 : /* The program data account should not exist, but a system
303 : account with funded lamports is acceptable.
304 :
305 : https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L50-L61 */
306 0 : if( FD_UNLIKELY( progdata_exists ) ) {
307 0 : if( FD_UNLIKELY( !fd_pubkey_eq( fd_accdb_ref_owner( ro ), &fd_solana_system_program_id ) ) ) {
308 : /* CoreBpfMigrationError::ProgramHasDataAccount(*program_address) */
309 0 : fd_accdb_close_ro( accdb, ro );
310 0 : return NULL;
311 0 : } else {
312 0 : program_data_account_lamports = fd_accdb_ref_lamports( ro );
313 0 : fd_accdb_close_ro( accdb, ro );
314 0 : }
315 0 : }
316 0 : } else {
317 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L62-L74 */
318 0 : if( FD_UNLIKELY( progdata_exists ) ) {
319 : /* CoreBpfMigrationError::ProgramHasDataAccount(*program_address) */
320 0 : fd_accdb_close_ro( accdb, ro );
321 0 : return NULL;
322 0 : }
323 0 : }
324 0 : } while(0);
325 :
326 0 : *target_bpf_v2 = (target_builtin_t) {
327 0 : .program_account = program_account,
328 0 : .program_data_address = program_data_address,
329 0 : .program_data_account_lamports = program_data_account_lamports
330 0 : };
331 0 : return target_bpf_v2;
332 0 : }
333 :
334 : /* This function contains the deployment checks that are equivalent to
335 : Agave's directly_invoke_loader_v3_deploy.
336 :
337 : There is no direct equivalent in Agave to this function, because
338 : we are not updating the program cache here. However, we do the same
339 : checks that our program cache does upon deployment.
340 :
341 : This is safe because the bpf migration code runs at the epoch
342 : boundary, before any transaction execution. The program cache
343 : automatically invalidates all programs at the start of an epoch
344 : boundary, so we do not need to explicitly update the cache during the
345 : migration.
346 :
347 : https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L120-L218 */
348 : static int
349 : fd_directly_invoke_loader_v3_deploy_checks( fd_bank_t const * bank,
350 : fd_runtime_stack_t * runtime_stack,
351 : uchar const * elf,
352 0 : ulong elf_sz ) {
353 0 : fd_features_t const * features = &bank->f.features;
354 0 : ulong slot = bank->f.slot;
355 :
356 : /* ELF verification with deploy checks enabled */
357 0 : fd_prog_versions_t versions = fd_prog_versions( features, slot );
358 0 : fd_sbpf_loader_config_t loader_config = {
359 0 : .elf_deploy_checks = 1,
360 0 : .sbpf_min_version = versions.min_sbpf_version,
361 0 : .sbpf_max_version = versions.max_sbpf_version,
362 0 : };
363 0 : fd_sbpf_elf_info_t elf_info[1];
364 0 : if( FD_UNLIKELY( fd_sbpf_elf_peek( elf_info, elf, elf_sz, &loader_config )!=FD_SBPF_ELF_SUCCESS ) ) return 1;
365 :
366 : /* Setup program (includes calldests) */
367 0 : fd_sbpf_program_t * prog = fd_sbpf_program_new(
368 0 : runtime_stack->bpf_migration.progcache_validate.sbpf_footprint,
369 0 : elf_info,
370 0 : runtime_stack->bpf_migration.progcache_validate.rodata );
371 0 : if( FD_UNLIKELY( !prog ) ) return 1;
372 :
373 0 : fd_sbpf_syscalls_t _syscalls[ FD_SBPF_SYSCALLS_SLOT_CNT ];
374 0 : fd_sbpf_syscalls_t * syscalls = fd_sbpf_syscalls_join( fd_sbpf_syscalls_new( _syscalls ) );
375 0 : if( FD_UNLIKELY( !syscalls ) ) return 1;
376 0 : if( FD_UNLIKELY( fd_vm_syscall_register_slot( syscalls, slot, features, /* is_deploy */ 1 )!=FD_VM_SUCCESS ) ) return 1;
377 :
378 : /* fd_sbpf_program_load checks */
379 0 : if( FD_UNLIKELY( fd_sbpf_program_load(
380 0 : prog,
381 0 : elf,
382 0 : elf_sz,
383 0 : syscalls,
384 0 : &loader_config,
385 0 : runtime_stack->bpf_migration.progcache_validate.programdata,
386 0 : sizeof(runtime_stack->bpf_migration.progcache_validate.programdata) ) ) ) return 1;
387 :
388 : /* fd_vm_validate checks */
389 0 : fd_vm_t _vm[1];
390 0 : fd_vm_t * vm = fd_vm_join( fd_vm_new( _vm ) );
391 0 : if( FD_UNLIKELY( !vm ) ) return 1;
392 0 : vm = fd_vm_init( vm,
393 0 : NULL,
394 0 : 0UL,
395 0 : 0UL,
396 0 : prog->rodata,
397 0 : prog->rodata_sz,
398 0 : prog->text,
399 0 : prog->info.text_cnt,
400 0 : prog->info.text_off,
401 0 : prog->info.text_sz,
402 0 : prog->entry_pc,
403 0 : prog->calldests,
404 0 : elf_info->sbpf_version,
405 0 : syscalls,
406 0 : NULL,
407 0 : NULL,
408 0 : NULL,
409 0 : 0U,
410 0 : NULL,
411 0 : 0,
412 0 : FD_FEATURE_ACTIVE( slot, features, account_data_direct_mapping ),
413 0 : FD_FEATURE_ACTIVE( slot, features, syscall_parameter_address_restrictions ),
414 0 : FD_FEATURE_ACTIVE( slot, features, virtual_address_space_adjustments ),
415 0 : 0,
416 0 : 0UL );
417 0 : if( FD_UNLIKELY( !vm ) ) return 1;
418 0 : if( FD_UNLIKELY( fd_vm_validate( vm )!=FD_VM_SUCCESS ) ) return 1;
419 :
420 0 : return FD_EXECUTOR_INSTR_SUCCESS;
421 0 : }
422 :
423 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L51-L75 */
424 :
425 : static fd_tmp_account_t *
426 : source_buffer_new_checked( fd_tmp_account_t * acc,
427 : fd_accdb_user_t * accdb,
428 : fd_funk_txn_xid_t const * xid,
429 : fd_pubkey_t const * pubkey,
430 0 : fd_hash_t const * verified_build_hash ) {
431 :
432 0 : if( FD_UNLIKELY( !tmp_account_read( acc, accdb, xid, pubkey ) ) ) {
433 : /* CoreBpfMigrationError::AccountNotFound(*buffer_address) */
434 0 : return NULL;
435 0 : }
436 :
437 0 : if( FD_UNLIKELY( 0!=memcmp( acc->meta.owner, &fd_solana_bpf_loader_upgradeable_program_id, 32 ) ) ) {
438 : /* CoreBpfMigrationError::IncorrectOwner(*buffer_address) */
439 0 : return NULL;
440 0 : }
441 :
442 0 : if( acc->data_sz < BUFFER_METADATA_SIZE ) {
443 : /* CoreBpfMigrationError::InvalidBufferAccount(*buffer_address) */
444 0 : return NULL;
445 0 : }
446 :
447 0 : fd_bpf_state_t state[1];
448 0 : if( FD_UNLIKELY( fd_bpf_state_decode( state, acc->data, BUFFER_METADATA_SIZE ) ) ) {
449 0 : return NULL;
450 0 : }
451 :
452 0 : if( FD_UNLIKELY( state->discriminant!=FD_BPF_STATE_BUFFER ) ) {
453 : /* CoreBpfMigrationError::InvalidBufferAccount(*buffer_address) */
454 0 : return NULL;
455 0 : }
456 :
457 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L61-L71 */
458 0 : if( verified_build_hash ) {
459 : /* Strip trailing zero-padding before hashing
460 : https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L61-L63 */
461 0 : uchar const * data = (uchar const *)acc->data;
462 0 : ulong offset = BUFFER_METADATA_SIZE;
463 0 : ulong end_offset = acc->data_sz;
464 0 : while( end_offset>offset && data[end_offset-1]==0 ) end_offset--;
465 0 : uchar const * buffer_program_data = data + offset;
466 0 : ulong buffer_program_data_sz = end_offset - offset;
467 :
468 0 : fd_hash_t hash;
469 0 : fd_sha256_hash( buffer_program_data, buffer_program_data_sz, hash.uc );
470 0 : if( FD_UNLIKELY( 0!=memcmp( hash.uc, verified_build_hash->uc, FD_HASH_FOOTPRINT ) ) ) {
471 : /* CoreBpfMigrationError::BuildHashMismatch */
472 0 : return NULL;
473 0 : }
474 0 : }
475 :
476 0 : return acc;
477 0 : }
478 :
479 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L82-L95 */
480 :
481 : static fd_tmp_account_t *
482 : new_target_program_account( fd_tmp_account_t * acc,
483 : target_builtin_t const * target,
484 0 : fd_rent_t const * rent ) {
485 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L86-L88 */
486 0 : fd_bpf_state_t state = {
487 0 : .discriminant = FD_BPF_STATE_PROGRAM,
488 0 : .inner = {
489 0 : .program = {
490 0 : .programdata_address = target->program_data_address,
491 0 : }
492 0 : }
493 0 : };
494 :
495 0 : ulong state_sz = fd_bpf_state_size( &state );
496 0 : tmp_account_new( acc, state_sz );
497 0 : acc->meta.lamports = fd_rent_exempt_minimum_balance( rent, SIZE_OF_PROGRAM );
498 0 : acc->meta.executable = 1;
499 0 : memcpy( acc->meta.owner, fd_solana_bpf_loader_upgradeable_program_id.uc, sizeof(fd_pubkey_t) );
500 :
501 0 : ulong out_sz = 0UL;
502 0 : if( FD_UNLIKELY( fd_bpf_state_encode( &state, acc->data, state_sz, &out_sz ) ) ) {
503 0 : FD_LOG_ERR(( "fd_bpf_state_encode failed" ));
504 0 : }
505 :
506 0 : return acc;
507 0 : }
508 :
509 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L108-L153 */
510 : static fd_tmp_account_t *
511 : new_target_program_data_account( fd_tmp_account_t * acc,
512 : fd_tmp_account_t const * source,
513 : fd_pubkey_t const * upgrade_authority_address,
514 : fd_rent_t const * rent,
515 0 : ulong slot ) {
516 0 : ulong const buffer_metadata_sz = BUFFER_METADATA_SIZE;
517 :
518 0 : if( FD_UNLIKELY( source->data_sz < buffer_metadata_sz ) )
519 0 : return NULL; /* CoreBpfMigrationError::InvalidBufferAccount */
520 :
521 0 : fd_bpf_state_t state;
522 0 : if( FD_UNLIKELY( fd_bpf_state_decode( &state, source->data, buffer_metadata_sz ) ) ) {
523 0 : return NULL;
524 0 : }
525 :
526 0 : if( FD_UNLIKELY( state.discriminant!=FD_BPF_STATE_BUFFER ) )
527 0 : return NULL; /* CoreBpfMigrationError::InvalidBufferAccount */
528 :
529 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L118-L125 */
530 0 : if( upgrade_authority_address ) {
531 0 : if( FD_UNLIKELY( !state.inner.buffer.has_authority_address ||
532 0 : !fd_pubkey_eq( upgrade_authority_address, &state.inner.buffer.authority_address ) ) ) {
533 0 : return NULL; /* CoreBpfMigrationError::UpgradeAuthorityMismatch */
534 0 : }
535 0 : }
536 :
537 0 : void const * elf = (uchar const *)source->data + buffer_metadata_sz;
538 0 : ulong elf_sz = /* */source->data_sz - buffer_metadata_sz;
539 :
540 0 : ulong space = PROGRAMDATA_METADATA_SIZE + elf_sz;
541 0 : ulong lamports = fd_rent_exempt_minimum_balance( rent, space );
542 0 : fd_pubkey_t owner = fd_solana_bpf_loader_upgradeable_program_id;
543 :
544 0 : fd_bpf_state_t programdata_meta = {
545 0 : .discriminant = FD_BPF_STATE_PROGRAM_DATA,
546 0 : .inner = {
547 0 : .program_data = {
548 0 : .slot = slot,
549 0 : .has_upgrade_authority_address = !!upgrade_authority_address,
550 0 : .upgrade_authority_address = upgrade_authority_address ? *upgrade_authority_address : (fd_pubkey_t){{0}}
551 0 : }
552 0 : }
553 0 : };
554 :
555 0 : tmp_account_new( acc, space );
556 0 : acc->meta.lamports = lamports;
557 0 : memcpy( acc->meta.owner, owner.uc, sizeof(fd_pubkey_t) );
558 0 : ulong out_sz = 0UL;
559 0 : if( FD_UNLIKELY( fd_bpf_state_encode( &programdata_meta, acc->data, PROGRAMDATA_METADATA_SIZE, &out_sz ) ) ) {
560 0 : FD_LOG_ERR(( "fd_bpf_state_encode failed" ));
561 0 : }
562 0 : fd_memcpy( (uchar *)acc->data+PROGRAMDATA_METADATA_SIZE, elf, elf_sz );
563 :
564 0 : return acc;
565 0 : }
566 :
567 : void
568 : migrate_builtin_to_core_bpf1( fd_core_bpf_migration_config_t const * config,
569 : fd_accdb_user_t * accdb,
570 : fd_funk_txn_xid_t const * xid,
571 : fd_bank_t * bank,
572 : fd_runtime_stack_t * runtime_stack,
573 : fd_pubkey_t const * builtin_program_id,
574 0 : fd_capture_ctx_t * capture_ctx ) {
575 0 : fd_memset( &runtime_stack->bpf_migration, 0, sizeof(runtime_stack->bpf_migration) );
576 :
577 0 : target_builtin_t target[1];
578 0 : if( FD_UNLIKELY( !target_builtin_new_checked(
579 0 : target,
580 0 : builtin_program_id,
581 0 : config->migration_target,
582 0 : FD_FEATURE_ACTIVE_BANK( bank, relax_programdata_account_check_migration ),
583 0 : accdb,
584 0 : xid,
585 0 : runtime_stack ) ) )
586 0 : return;
587 :
588 0 : fd_tmp_account_t * source = &runtime_stack->bpf_migration.source;
589 0 : if( FD_UNLIKELY( !source_buffer_new_checked(
590 0 : source,
591 0 : accdb,
592 0 : xid,
593 0 : config->source_buffer_address,
594 0 : config->verified_build_hash ) ) )
595 0 : return;
596 :
597 0 : fd_rent_t const * rent = &bank->f.rent;
598 0 : ulong const slot = bank->f.slot;
599 :
600 0 : fd_tmp_account_t * new_target_program = &runtime_stack->bpf_migration.new_target_program;
601 0 : if( FD_UNLIKELY( !new_target_program_account(
602 0 : new_target_program,
603 0 : target,
604 0 : rent ) ) )
605 0 : return;
606 0 : new_target_program->addr = *builtin_program_id;
607 :
608 0 : fd_tmp_account_t * new_target_program_data = &runtime_stack->bpf_migration.new_target_program_data;
609 0 : if( FD_UNLIKELY( !new_target_program_data_account(
610 0 : new_target_program_data,
611 0 : source,
612 0 : config->upgrade_authority_address,
613 0 : rent,
614 0 : slot ) ) )
615 0 : return;
616 0 : new_target_program_data->addr = target->program_data_address;
617 :
618 0 : ulong old_data_sz;
619 0 : if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->data_sz, source->data_sz, &old_data_sz ) ) ) return;
620 :
621 0 : ulong new_data_sz;
622 0 : if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->data_sz, new_target_program_data->data_sz, &new_data_sz ) ) ) return;
623 :
624 0 : assert( new_target_program_data->data_sz>=PROGRAMDATA_METADATA_SIZE );
625 : /* FIXME call fd_directly_invoke_loader_v3_deploy */
626 :
627 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L267-L281 */
628 0 : ulong lamports_to_burn;
629 0 : if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->meta.lamports, source->meta.lamports, &lamports_to_burn ) ) ) return;
630 0 : if( FD_UNLIKELY( fd_ulong_checked_add( lamports_to_burn, target->program_data_account_lamports, &lamports_to_burn ) ) ) return;
631 :
632 0 : ulong lamports_to_fund;
633 0 : if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->meta.lamports, new_target_program_data->meta.lamports, &lamports_to_fund ) ) ) return;
634 :
635 : /* Write back accounts */
636 0 : tmp_account_store( new_target_program, accdb, xid, bank, capture_ctx );
637 0 : tmp_account_store( new_target_program_data, accdb, xid, bank, capture_ctx );
638 0 : fd_tmp_account_t * empty = &runtime_stack->bpf_migration.empty;
639 0 : tmp_account_new( empty, 0UL );
640 0 : empty->addr = source->addr;
641 0 : tmp_account_store( empty, accdb, xid, bank, capture_ctx );
642 :
643 : /* FIXME "remove the built-in program from the bank's list of builtins" */
644 : /* FIXME "update account data size delta" */
645 0 : }
646 :
647 : /* Mimics migrate_builtin_to_core_bpf().
648 : https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#215-303 */
649 : void
650 : fd_migrate_builtin_to_core_bpf( fd_bank_t * bank,
651 : fd_accdb_user_t * accdb,
652 : fd_funk_txn_xid_t const * xid,
653 : fd_runtime_stack_t * runtime_stack,
654 : fd_core_bpf_migration_config_t const * config,
655 0 : fd_capture_ctx_t * capture_ctx ) {
656 0 : migrate_builtin_to_core_bpf1( config, accdb, xid, bank, runtime_stack, config->builtin_program_id, capture_ctx );
657 0 : }
658 :
659 : /* Mimics upgrade_core_bpf_program().
660 : https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L319-L377 */
661 : void
662 : fd_upgrade_core_bpf_program( fd_bank_t * bank,
663 : fd_accdb_user_t * accdb,
664 : fd_funk_txn_xid_t const * xid,
665 : fd_runtime_stack_t * runtime_stack,
666 : fd_pubkey_t const * builtin_program_id,
667 : fd_pubkey_t const * source_buffer_address,
668 0 : fd_capture_ctx_t * capture_ctx ) {
669 0 : fd_memset( &runtime_stack->bpf_migration, 0, sizeof(runtime_stack->bpf_migration) );
670 :
671 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L327 */
672 0 : target_core_bpf_t target[1];
673 0 : if( FD_UNLIKELY( !target_core_bpf_new_checked( target, builtin_program_id, accdb, xid, runtime_stack ) ) ) {
674 0 : return;
675 0 : }
676 :
677 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L328 */
678 0 : fd_tmp_account_t * source = &runtime_stack->bpf_migration.source;
679 0 : if( FD_UNLIKELY( !source_buffer_new_checked( source, accdb, xid, source_buffer_address, NULL ) ) ) {
680 0 : return;
681 0 : }
682 :
683 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L331-L332 */
684 0 : fd_tmp_account_t * new_target_program_data = &runtime_stack->bpf_migration.new_target_program_data;
685 0 : fd_pubkey_t program_data_address = get_program_data_address( builtin_program_id );
686 :
687 0 : ulong program_data_len = source->data_sz - BUFFER_METADATA_SIZE;
688 0 : ulong new_account_size = PROGRAMDATA_METADATA_SIZE + program_data_len;
689 :
690 0 : tmp_account_new( new_target_program_data, new_account_size );
691 0 : new_target_program_data->addr = program_data_address;
692 :
693 0 : fd_rent_t const * rent = &bank->f.rent;
694 0 : new_target_program_data->meta.lamports = fd_rent_exempt_minimum_balance( rent, new_account_size );
695 0 : new_target_program_data->meta.executable = 0;
696 0 : fd_memcpy( new_target_program_data->meta.owner, &fd_solana_bpf_loader_upgradeable_program_id, sizeof(fd_pubkey_t) );
697 :
698 0 : fd_bpf_state_t programdata_state[1] = {{
699 0 : .discriminant = FD_BPF_STATE_PROGRAM_DATA,
700 0 : .inner = { .program_data = {
701 0 : .slot = bank->f.slot,
702 0 : .upgrade_authority_address = target->upgrade_authority_address,
703 0 : .has_upgrade_authority_address = target->has_upgrade_authority_address
704 0 : }}
705 0 : }};
706 :
707 0 : ulong out_sz = 0UL;
708 0 : if( FD_UNLIKELY( fd_bpf_state_encode( programdata_state, new_target_program_data->data, PROGRAMDATA_METADATA_SIZE, &out_sz ) ) ) {
709 0 : return;
710 0 : }
711 :
712 0 : fd_memcpy( new_target_program_data->data + PROGRAMDATA_METADATA_SIZE,
713 0 : source->data + BUFFER_METADATA_SIZE,
714 0 : program_data_len );
715 :
716 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.4/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L339-L346 */
717 0 : ulong old_data_sz;
718 0 : if( FD_UNLIKELY( fd_ulong_checked_add( target->program_data_account->data_sz, source->data_sz, &old_data_sz ) ) ) return;
719 0 : ulong new_data_sz = new_target_program_data->data_sz;
720 :
721 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.4/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L349-L355 */
722 0 : uchar const * elf = new_target_program_data->data + PROGRAMDATA_METADATA_SIZE;
723 0 : ulong elf_sz = program_data_len;
724 0 : if( FD_UNLIKELY( fd_directly_invoke_loader_v3_deploy_checks( bank, runtime_stack, elf, elf_sz ) ) ) return;
725 :
726 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L359-L364 */
727 0 : ulong lamports_to_burn;
728 0 : if( FD_UNLIKELY( fd_ulong_checked_add( target->program_data_account->meta.lamports, source->meta.lamports, &lamports_to_burn ) ) ) return;
729 :
730 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L366-L371 */
731 0 : fd_pubkey_t source_addr = source->addr;
732 0 : tmp_account_store( new_target_program_data, accdb, xid, bank, capture_ctx );
733 :
734 0 : fd_tmp_account_t * empty = &runtime_stack->bpf_migration.empty;
735 0 : tmp_account_new( empty, 0UL );
736 0 : empty->addr = source_addr;
737 0 : tmp_account_store( empty, accdb, xid, bank, capture_ctx );
738 :
739 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L374 */
740 : /* FIXME "update account data size delta" */
741 0 : (void)old_data_sz;
742 0 : (void)new_data_sz;
743 :
744 0 : fd_memset( &runtime_stack->bpf_migration, 0, sizeof(runtime_stack->bpf_migration) );
745 0 : }
746 :
747 : /* Mimics upgrade_loader_v2_program_with_loader_v3_program().
748 : https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L402-L474 */
749 : void
750 : fd_upgrade_loader_v2_program_with_loader_v3_program( fd_bank_t * bank,
751 : fd_accdb_user_t * accdb,
752 : fd_funk_txn_xid_t const * xid,
753 : fd_runtime_stack_t * runtime_stack,
754 : fd_pubkey_t const * loader_v2_program_address,
755 : fd_pubkey_t const * source_buffer_address,
756 : int allow_prefunded,
757 0 : fd_capture_ctx_t * capture_ctx ) {
758 0 : fd_memset( &runtime_stack->bpf_migration, 0, sizeof(runtime_stack->bpf_migration) );
759 :
760 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L411-L412 */
761 0 : target_builtin_t target[1];
762 0 : if( FD_UNLIKELY( !target_bpf_v2_new_checked(
763 0 : target,
764 0 : loader_v2_program_address,
765 0 : allow_prefunded,
766 0 : accdb,
767 0 : xid,
768 0 : runtime_stack ) ) )
769 0 : return;
770 :
771 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L413 */
772 0 : fd_tmp_account_t * source = &runtime_stack->bpf_migration.source;
773 0 : if( FD_UNLIKELY( !source_buffer_new_checked( source, accdb, xid, source_buffer_address, NULL ) ) )
774 0 : return;
775 :
776 0 : fd_rent_t const * rent = &bank->f.rent;
777 0 : ulong slot = bank->f.slot;
778 :
779 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L416-L417 */
780 0 : fd_tmp_account_t * new_target_program = &runtime_stack->bpf_migration.new_target_program;
781 0 : if( FD_UNLIKELY( !new_target_program_account( new_target_program, target, rent ) ) )
782 0 : return;
783 0 : new_target_program->addr = *loader_v2_program_address;
784 :
785 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L419-L421 */
786 0 : fd_tmp_account_t * new_target_program_data = &runtime_stack->bpf_migration.new_target_program_data;
787 0 : if( FD_UNLIKELY( !new_target_program_data_account( new_target_program_data, source, NULL, rent, slot ) ) ) {
788 0 : return;
789 0 : }
790 0 : new_target_program_data->addr = target->program_data_address;
791 :
792 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L427-L435 */
793 0 : ulong old_data_sz;
794 0 : if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->data_sz, source->data_sz, &old_data_sz ) ) ) return;
795 :
796 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L432-L435 */
797 0 : ulong new_data_sz;
798 0 : if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->data_sz, new_target_program_data->data_sz, &new_data_sz ) ) ) return;
799 :
800 0 : if( FD_UNLIKELY( new_target_program_data->data_sz<PROGRAMDATA_METADATA_SIZE ) ) {
801 0 : FD_LOG_CRIT(( "invariant violation: new target programdata too small" ));
802 0 : }
803 :
804 : /* Agave calls directly_invoke_loader_v3_deploy to deploy the new
805 : program to the program cache. We don't do that, but instead we
806 : perform the same checks as directly_invoke_loader_v3_deploy
807 : without modifying the program cache. We need to do the checks
808 : at this point so that we can fail the upgrade if the ELF is
809 : invalid.
810 :
811 : This is safe because the bpf migration code runs at the epoch
812 : boundary, before any transaction execution. The program cache
813 : automatically invalidates all programs at the start of an epoch
814 : boundary, so we do not need to explicitly update the cache during the
815 : migration.
816 :
817 : https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L437-L443*/
818 0 : uchar const * elf = (uchar const *)new_target_program_data->data + PROGRAMDATA_METADATA_SIZE;
819 0 : ulong elf_sz = new_target_program_data->data_sz - PROGRAMDATA_METADATA_SIZE;
820 0 : if( FD_UNLIKELY( fd_directly_invoke_loader_v3_deploy_checks( bank, runtime_stack, elf, elf_sz ) ) ) return;
821 :
822 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L451-L459 */
823 0 : ulong lamports_to_burn;
824 0 : if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->meta.lamports, source->meta.lamports, &lamports_to_burn ) ) ) return;
825 0 : if( FD_UNLIKELY( fd_ulong_checked_add( lamports_to_burn, target->program_data_account_lamports, &lamports_to_burn ) ) ) return;
826 :
827 0 : ulong lamports_to_fund;
828 0 : if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->meta.lamports, new_target_program_data->meta.lamports, &lamports_to_fund ) ) ) return;
829 :
830 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L462-L468 */
831 0 : tmp_account_store( new_target_program, accdb, xid, bank, capture_ctx );
832 0 : tmp_account_store( new_target_program_data, accdb, xid, bank, capture_ctx );
833 :
834 0 : fd_tmp_account_t * empty = &runtime_stack->bpf_migration.empty;
835 0 : tmp_account_new( empty, 0UL );
836 0 : empty->addr = source->addr;
837 0 : tmp_account_store( empty, accdb, xid, bank, capture_ctx );
838 :
839 : /* NB: Agave updates "delta_off_chain", using these two fields,
840 : which is not consensus-critical (only used for Agave stats)
841 : so we don't update this in our migration code or store this in
842 : our bank. */
843 0 : (void)old_data_sz;
844 0 : (void)new_data_sz;
845 :
846 0 : fd_memset( &runtime_stack->bpf_migration, 0, sizeof(runtime_stack->bpf_migration) );
847 0 : }
|