Line data Source code
1 : #include "fd_vm_private.h"
2 : #include "../runtime/context/fd_exec_slot_ctx.h"
3 : #include "../features/fd_features.h"
4 :
5 : /* fd_vm_syscall_strerror() returns the error message corresponding to err,
6 : intended to be logged by log_collector, or an empty string if the error code
7 : should be omitted in logs for whatever reason. Omitted examples are success,
8 : panic (logged in place)...
9 : See also fd_log_collector_program_failure(). */
10 : char const *
11 0 : fd_vm_syscall_strerror( int err ) {
12 :
13 0 : switch( err ) {
14 :
15 0 : case FD_VM_SYSCALL_ERR_INVALID_STRING: return "invalid utf-8 sequence"; // truncated
16 0 : case FD_VM_SYSCALL_ERR_ABORT: return "SBF program panicked";
17 0 : case FD_VM_SYSCALL_ERR_PANIC: return "SBF program Panicked in..."; // truncated
18 0 : case FD_VM_SYSCALL_ERR_INVOKE_CONTEXT_BORROW_FAILED: return "Cannot borrow invoke context";
19 0 : case FD_VM_SYSCALL_ERR_MALFORMED_SIGNER_SEED: return "Malformed signer seed"; // truncated
20 0 : case FD_VM_SYSCALL_ERR_BAD_SEEDS: return "Could not create program address with signer seeds"; // truncated
21 0 : case FD_VM_SYSCALL_ERR_PROGRAM_NOT_SUPPORTED: return "Program not supported by inner instructions"; // truncated
22 0 : case FD_VM_SYSCALL_ERR_UNALIGNED_POINTER: return "Unaligned pointer";
23 0 : case FD_VM_SYSCALL_ERR_TOO_MANY_SIGNERS: return "Too many signers";
24 0 : case FD_VM_SYSCALL_ERR_INSTRUCTION_TOO_LARGE: return "Instruction passed to inner instruction is too large"; // truncated
25 0 : case FD_VM_SYSCALL_ERR_TOO_MANY_ACCOUNTS: return "Too many accounts passed to inner instruction";
26 0 : case FD_VM_SYSCALL_ERR_COPY_OVERLAPPING: return "Overlapping copy";
27 0 : case FD_VM_SYSCALL_ERR_RETURN_DATA_TOO_LARGE: return "Return data too large"; // truncated
28 0 : case FD_VM_SYSCALL_ERR_TOO_MANY_SLICES: return "Hashing too many sequences";
29 0 : case FD_VM_SYSCALL_ERR_INVALID_LENGTH: return "InvalidLength";
30 0 : case FD_VM_SYSCALL_ERR_MAX_INSTRUCTION_DATA_LEN_EXCEEDED: return "Invoked an instruction with data that is too large"; // truncated
31 0 : case FD_VM_SYSCALL_ERR_MAX_INSTRUCTION_ACCOUNTS_EXCEEDED: return "Invoked an instruction with too many accounts"; // truncated
32 0 : case FD_VM_SYSCALL_ERR_MAX_INSTRUCTION_ACCOUNT_INFOS_EXCEEDED: return "Invoked an instruction with too many account info's"; // truncated
33 0 : case FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE: return "InvalidAttribute";
34 0 : case FD_VM_SYSCALL_ERR_INVALID_POINTER: return "Invalid pointer";
35 0 : case FD_VM_SYSCALL_ERR_ARITHMETIC_OVERFLOW: return "Arithmetic overflow";
36 :
37 0 : case FD_VM_SYSCALL_ERR_INSTR_ERR: return "Instruction error";
38 0 : case FD_VM_SYSCALL_ERR_INVALID_PDA: return "Invalid PDA";
39 0 : case FD_VM_SYSCALL_ERR_COMPUTE_BUDGET_EXCEEDED: return "Compute budget exceeded";
40 0 : case FD_VM_SYSCALL_ERR_SEGFAULT: return "Segmentation fault";
41 0 : case FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME: return "Syscall executed outside runtime";
42 :
43 :
44 0 : case FD_VM_SYSCALL_ERR_POSEIDON_INVALID_PARAMS: return "Syscall error: Invalid parameters.";
45 0 : case FD_VM_SYSCALL_ERR_POSEIDON_INVALID_ENDIANNESS: return "Syscall error: Invalid endianness.";
46 :
47 0 : default: break;
48 0 : }
49 :
50 0 : return "";
51 0 : }
52 :
53 : /* fd_vm_ebpf_strerror() returns the error message corresponding to err,
54 : intended to be logged by log_collector, or an empty string if the error code
55 : should be omitted in logs for whatever reason.
56 : See also fd_log_collector_program_failure(). */
57 : char const *
58 0 : fd_vm_ebpf_strerror( int err ) {
59 :
60 0 : switch( err ) {
61 :
62 0 : case FD_VM_ERR_EBPF_ELF_ERROR: return "ELF error"; // truncated
63 0 : case FD_VM_ERR_EBPF_FUNCTION_ALREADY_REGISTERED: return "function was already registered"; // truncated
64 0 : case FD_VM_ERR_EBPF_CALL_DEPTH_EXCEEDED: return "exceeded max BPF to BPF call depth";
65 0 : case FD_VM_ERR_EBPF_EXIT_ROOT_CALL_FRAME: return "attempted to exit root call frame";
66 0 : case FD_VM_ERR_EBPF_DIVIDE_BY_ZERO: return "divide by zero at BPF instruction";
67 0 : case FD_VM_ERR_EBPF_DIVIDE_OVERFLOW: return "division overflow at BPF instruction";
68 0 : case FD_VM_ERR_EBPF_EXECUTION_OVERRUN: return "attempted to execute past the end of the text segment at BPF instruction";
69 0 : case FD_VM_ERR_EBPF_CALL_OUTSIDE_TEXT_SEGMENT: return "callx attempted to call outside of the text segment";
70 0 : case FD_VM_ERR_EBPF_EXCEEDED_MAX_INSTRUCTIONS: return "exceeded CUs meter at BPF instruction";
71 0 : case FD_VM_ERR_EBPF_JIT_NOT_COMPILED: return "program has not been JIT-compiled";
72 0 : case FD_VM_ERR_EBPF_INVALID_VIRTUAL_ADDRESS: return "invalid virtual address"; // truncated
73 0 : case FD_VM_ERR_EBPF_INVALID_MEMORY_REGION: return "Invalid memory region at index"; // truncated
74 0 : case FD_VM_ERR_EBPF_ACCESS_VIOLATION: return "Access violation"; // truncated
75 0 : case FD_VM_ERR_EBPF_STACK_ACCESS_VIOLATION: return "Access violation in stack frame"; // truncated
76 0 : case FD_VM_ERR_EBPF_INVALID_INSTRUCTION: return "invalid BPF instruction";
77 0 : case FD_VM_ERR_EBPF_UNSUPPORTED_INSTRUCTION: return "unsupported BPF instruction";
78 0 : case FD_VM_ERR_EBPF_EXHAUSTED_TEXT_SEGMENT: return "Compilation exhausted text segment at BPF instruction"; // truncated
79 0 : case FD_VM_ERR_EBPF_LIBC_INVOCATION_FAILED: return "Libc calling returned error code"; // truncated
80 0 : case FD_VM_ERR_EBPF_VERIFIER_ERROR: return "Verifier error"; // truncated
81 0 : case FD_VM_ERR_EBPF_SYSCALL_ERROR: return ""; // handled explicitly via fd_vm_syscall_strerror()
82 :
83 0 : default: break;
84 0 : }
85 :
86 0 : return "";
87 0 : }
88 :
89 : /* fd_vm_strerror() returns the error message corresponding to err, used internally
90 : for system logs, NOT for log_collector / transaction logs. */
91 : char const *
92 81 : fd_vm_strerror( int err ) {
93 :
94 81 : switch( err ) {
95 :
96 : /* "Standard" Firedancer error codes */
97 :
98 3 : case FD_VM_SUCCESS: return "SUCCESS success";
99 3 : case FD_VM_ERR_INVAL: return "INVAL invalid request";
100 3 : case FD_VM_ERR_UNSUP: return "UNSUP unsupported request";
101 3 : case FD_VM_ERR_PERM: return "PERM unauthorized request";
102 3 : case FD_VM_ERR_FULL: return "FULL storage full";
103 3 : case FD_VM_ERR_EMPTY: return "EMPTY nothing to do";
104 3 : case FD_VM_ERR_IO: return "IO input-output error";
105 3 : case FD_VM_ERR_AGAIN: return "AGAIN try again later";
106 :
107 : /* VM exec error codes */
108 :
109 3 : case FD_VM_ERR_SIGTEXT: return "SIGTEXT illegal program counter";
110 3 : case FD_VM_ERR_SIGSPLIT: return "SIGSPLIT split multiword instruction";
111 3 : case FD_VM_ERR_SIGCALL: return "unsupported BPF instruction";
112 3 : case FD_VM_ERR_SIGSTACK: return "SIGSTACK call depth limit exceeded";
113 3 : case FD_VM_ERR_SIGILL: return "SIGILL illegal instruction";
114 3 : case FD_VM_ERR_SIGSEGV: return "SIGSEGV illegal memory address";
115 3 : case FD_VM_ERR_SIGBUS: return "SIGBUS misaligned memory address";
116 3 : case FD_VM_ERR_SIGRDONLY: return "SIGRDONLY illegal write";
117 3 : case FD_VM_ERR_SIGCOST: return "SIGCOST compute unit limit exceeded";
118 0 : case FD_VM_ERR_SIGFPE: return "SIGFPE division by zero";
119 0 : case FD_VM_ERR_SIGFPE_OF: return "SIGFPE division overflow";
120 0 : case FD_VM_ERR_SIGSYSCALL: return "SIGSYSCALL syscall error";
121 0 : case FD_VM_ERR_SIGABORT: return "SIGABORT abort error";
122 :
123 : /* VM validate error codes */
124 :
125 3 : case FD_VM_ERR_INVALID_OPCODE: return "INVALID_OPCODE detected an invalid opcode";
126 3 : case FD_VM_ERR_INVALID_SRC_REG: return "INVALID_SRC_REG detected an invalid source register";
127 3 : case FD_VM_ERR_INVALID_DST_REG: return "INVALID_DST_REG detected an invalid destination register";
128 3 : case FD_VM_ERR_INF_LOOP: return "INF_LOOP detected an infinite loop";
129 3 : case FD_VM_ERR_JMP_OUT_OF_BOUNDS: return "JMP_OUT_OF_BOUNDS detected an out of bounds jump";
130 3 : case FD_VM_ERR_JMP_TO_ADDL_IMM: return "JMP_TO_ADDL_IMM detected a jump to an addl imm";
131 3 : case FD_VM_ERR_INVALID_END_IMM: return "INVALID_END_IMM detected an invalid immediate for an endianness conversion instruction";
132 3 : case FD_VM_ERR_INCOMPLETE_LDQ: return "INCOMPLETE_LDQ detected an incomplete ldq at program end";
133 3 : case FD_VM_ERR_LDQ_NO_ADDL_IMM: return "LDQ_NO_ADDL_IMM detected a ldq without an addl imm following it";
134 3 : case FD_VM_ERR_NO_SUCH_EXT_CALL: return "NO_SUCH_EXT_CALL detected a call imm with no function was registered for that immediate";
135 0 : case FD_VM_ERR_INVALID_REG: return "INVALID_REG detected an invalid register number in a callx instruction";
136 0 : case FD_VM_ERR_BAD_TEXT: return "BAD_TEXT detected a bad text section";
137 0 : case FD_VM_SH_OVERFLOW: return "SH_OVERFLOW detected a shift overflow in an instruction";
138 0 : case FD_VM_TEXT_SZ_UNALIGNED: return "TEXT_SZ_UNALIGNED detected an unaligned text section size (not a multiple of 8)";
139 :
140 0 : default: break;
141 81 : }
142 :
143 0 : return "UNKNOWN probably not a FD_VM_ERR code";
144 81 : }
145 :
146 : /* FIXME: add a pedantic version of this validation that does things
147 : like:
148 : - only 0 imms when the instruction does not use an imm
149 : - same as above but for src/dst reg, offset */
150 : /* FIXME: HANDLING OF LDQ ON NEWER SBPF VERSUS OLDER SBPF (AND WITH CALL
151 : REG) */
152 : /* FIXME: LINK TO SOLANA CODE VALIDATE AND DOUBLE CHECK THIS BEHAVES
153 : IDENTICALLY! */
154 :
155 : int
156 7848 : fd_vm_validate( fd_vm_t const * vm ) {
157 :
158 7848 : ulong sbpf_version = vm->sbpf_version;
159 :
160 : /* A mapping of all the possible 1-byte sBPF opcodes to their
161 : validation criteria. */
162 :
163 644984100 : # define FD_VALID ((uchar)0) /* Valid opcode */
164 7848 : # define FD_CHECK_JMP_V3 ((uchar)1) /* Validation should check that the instruction is a valid jump (v3+) */
165 11676 : # define FD_CHECK_END ((uchar)2) /* Validation should check that the instruction is a valid endianness conversion */
166 192042 : # define FD_CHECK_ST ((uchar)3) /* Validation should check that the instruction is a valid store */
167 7848 : # define FD_CHECK_LDQ ((uchar)4) /* Validation should check that the instruction is a valid load-quad */
168 64548912 : # define FD_CHECK_DIV ((uchar)5) /* Validation should check that the instruction is a valid division by immediate */
169 48331824 : # define FD_CHECK_SH32 ((uchar)6) /* Validation should check that the immediate is a valid 32-bit shift exponent */
170 48356103 : # define FD_CHECK_SH64 ((uchar)7) /* Validation should check that the immediate is a valid 64-bit shift exponent */
171 1635756 : # define FD_INVALID ((uchar)8) /* The opcode is invalid */
172 11985 : # define FD_CHECK_CALL_REG ((uchar)9) /* Validation should check that callx has valid register number */
173 12087 : # define FD_CHECK_CALL_REG_DEPR ((uchar)10) /* Older / deprecated FD_CHECK_CALLX */
174 7848 : # define FD_CHECK_CALL_IMM ((uchar)11) /* Check call against functions registry */
175 7848 : # define FD_CHECK_SYSCALL ((uchar)12) /* Check call against syscalls registry */
176 22431 : # define FD_CHECK_JMP_V0 ((uchar)13) /* Validation should check that the instruction is a valid jump (v0..v2) */
177 :
178 7848 : uchar FD_CHECK_JMP = FD_VM_SBPF_STATIC_SYSCALLS (sbpf_version) ? FD_CHECK_JMP_V3 : FD_CHECK_JMP_V0;
179 :
180 7848 : uchar validation_map[ 256 ] = {
181 : /* 0x00 */ FD_INVALID, /* 0x01 */ FD_INVALID, /* 0x02 */ FD_INVALID, /* 0x03 */ FD_INVALID,
182 : /* 0x04 */ FD_VALID, /* 0x05 */ FD_CHECK_JMP, /* 0x06 */ FD_INVALID, /* 0x07 */ FD_VALID,
183 : /* 0x08 */ FD_INVALID, /* 0x09 */ FD_INVALID, /* 0x0a */ FD_INVALID, /* 0x0b */ FD_INVALID,
184 : /* 0x0c */ FD_VALID, /* 0x0d */ FD_INVALID, /* 0x0e */ FD_INVALID, /* 0x0f */ FD_VALID,
185 : /* 0x10 */ FD_INVALID, /* 0x11 */ FD_INVALID, /* 0x12 */ FD_INVALID, /* 0x13 */ FD_INVALID,
186 : /* 0x14 */ FD_VALID, /* 0x15 */ FD_CHECK_JMP, /* 0x16 */ FD_INVALID, /* 0x17 */ FD_VALID,
187 : /* 0x18 */ FD_INVALID, /* 0x19 */ FD_INVALID, /* 0x1a */ FD_INVALID, /* 0x1b */ FD_INVALID,
188 : /* 0x1c */ FD_VALID, /* 0x1d */ FD_CHECK_JMP, /* 0x1e */ FD_INVALID, /* 0x1f */ FD_VALID,
189 : /* 0x20 */ FD_INVALID, /* 0x21 */ FD_INVALID, /* 0x22 */ FD_INVALID, /* 0x23 */ FD_INVALID,
190 : /* 0x24 */ FD_INVALID, /* 0x25 */ FD_CHECK_JMP, /* 0x26 */ FD_INVALID, /* 0x27 */ FD_CHECK_ST,
191 : /* 0x28 */ FD_INVALID, /* 0x29 */ FD_INVALID, /* 0x2a */ FD_INVALID, /* 0x2b */ FD_INVALID,
192 : /* 0x2c */ FD_VALID, /* 0x2d */ FD_CHECK_JMP, /* 0x2e */ FD_INVALID, /* 0x2f */ FD_CHECK_ST,
193 : /* 0x30 */ FD_INVALID, /* 0x31 */ FD_INVALID, /* 0x32 */ FD_INVALID, /* 0x33 */ FD_INVALID,
194 : /* 0x34 */ FD_INVALID, /* 0x35 */ FD_CHECK_JMP, /* 0x36 */ FD_VALID, /* 0x37 */ FD_CHECK_ST,
195 : /* 0x38 */ FD_INVALID, /* 0x39 */ FD_INVALID, /* 0x3a */ FD_INVALID, /* 0x3b */ FD_INVALID,
196 : /* 0x3c */ FD_VALID, /* 0x3d */ FD_CHECK_JMP, /* 0x3e */ FD_VALID, /* 0x3f */ FD_CHECK_ST,
197 : /* 0x40 */ FD_INVALID, /* 0x41 */ FD_INVALID, /* 0x42 */ FD_INVALID, /* 0x43 */ FD_INVALID,
198 : /* 0x44 */ FD_VALID, /* 0x45 */ FD_CHECK_JMP, /* 0x46 */ FD_CHECK_DIV, /* 0x47 */ FD_VALID,
199 : /* 0x48 */ FD_INVALID, /* 0x49 */ FD_INVALID, /* 0x4a */ FD_INVALID, /* 0x4b */ FD_INVALID,
200 : /* 0x4c */ FD_VALID, /* 0x4d */ FD_CHECK_JMP, /* 0x4e */ FD_VALID, /* 0x4f */ FD_VALID,
201 : /* 0x50 */ FD_INVALID, /* 0x51 */ FD_INVALID, /* 0x52 */ FD_INVALID, /* 0x53 */ FD_INVALID,
202 : /* 0x54 */ FD_VALID, /* 0x55 */ FD_CHECK_JMP, /* 0x56 */ FD_CHECK_DIV, /* 0x57 */ FD_VALID,
203 : /* 0x58 */ FD_INVALID, /* 0x59 */ FD_INVALID, /* 0x5a */ FD_INVALID, /* 0x5b */ FD_INVALID,
204 : /* 0x5c */ FD_VALID, /* 0x5d */ FD_CHECK_JMP, /* 0x5e */ FD_VALID, /* 0x5f */ FD_VALID,
205 : /* 0x60 */ FD_INVALID, /* 0x61 */ FD_INVALID, /* 0x62 */ FD_INVALID, /* 0x63 */ FD_INVALID,
206 : /* 0x64 */ FD_CHECK_SH32, /* 0x65 */ FD_CHECK_JMP, /* 0x66 */ FD_CHECK_DIV, /* 0x67 */ FD_CHECK_SH64,
207 : /* 0x68 */ FD_INVALID, /* 0x69 */ FD_INVALID, /* 0x6a */ FD_INVALID, /* 0x6b */ FD_INVALID,
208 : /* 0x6c */ FD_VALID, /* 0x6d */ FD_CHECK_JMP, /* 0x6e */ FD_VALID, /* 0x6f */ FD_VALID,
209 : /* 0x70 */ FD_INVALID, /* 0x71 */ FD_INVALID, /* 0x72 */ FD_INVALID, /* 0x73 */ FD_INVALID,
210 : /* 0x74 */ FD_CHECK_SH32, /* 0x75 */ FD_CHECK_JMP, /* 0x76 */ FD_CHECK_DIV, /* 0x77 */ FD_CHECK_SH64,
211 : /* 0x78 */ FD_INVALID, /* 0x79 */ FD_INVALID, /* 0x7a */ FD_INVALID, /* 0x7b */ FD_INVALID,
212 : /* 0x7c */ FD_VALID, /* 0x7d */ FD_CHECK_JMP, /* 0x7e */ FD_VALID, /* 0x7f */ FD_VALID,
213 : /* 0x80 */ FD_INVALID, /* 0x81 */ FD_INVALID, /* 0x82 */ FD_INVALID, /* 0x83 */ FD_INVALID,
214 : /* 0x84 */ FD_INVALID, /* 0x85 */ FD_CHECK_CALL_IMM,/*0x86*/FD_VALID, /* 0x87 */ FD_CHECK_ST,
215 : /* 0x88 */ FD_INVALID, /* 0x89 */ FD_INVALID, /* 0x8a */ FD_INVALID, /* 0x8b */ FD_INVALID,
216 : /* 0x8c */ FD_VALID, /* 0x8d */ FD_CHECK_CALL_REG,/*0x8e*/FD_VALID, /* 0x8f */ FD_CHECK_ST,
217 : /* 0x90 */ FD_INVALID, /* 0x91 */ FD_INVALID, /* 0x92 */ FD_INVALID, /* 0x93 */ FD_INVALID,
218 : /* 0x94 */ FD_INVALID, /* 0x95 */ FD_CHECK_SYSCALL,/*0x96*/ FD_VALID, /* 0x97 */ FD_CHECK_ST,
219 : /* 0x98 */ FD_INVALID, /* 0x99 */ FD_INVALID, /* 0x9a */ FD_INVALID, /* 0x9b */ FD_INVALID,
220 : /* 0x9c */ FD_VALID, /* 0x9d */ FD_VALID, /* 0x9e */ FD_VALID, /* 0x9f */ FD_CHECK_ST,
221 : /* 0xa0 */ FD_INVALID, /* 0xa1 */ FD_INVALID, /* 0xa2 */ FD_INVALID, /* 0xa3 */ FD_INVALID,
222 : /* 0xa4 */ FD_VALID, /* 0xa5 */ FD_CHECK_JMP, /* 0xa6 */ FD_INVALID, /* 0xa7 */ FD_VALID,
223 : /* 0xa8 */ FD_INVALID, /* 0xa9 */ FD_INVALID, /* 0xaa */ FD_INVALID, /* 0xab */ FD_INVALID,
224 : /* 0xac */ FD_VALID, /* 0xad */ FD_CHECK_JMP, /* 0xae */ FD_INVALID, /* 0xaf */ FD_VALID,
225 : /* 0xb0 */ FD_INVALID, /* 0xb1 */ FD_INVALID, /* 0xb2 */ FD_INVALID, /* 0xb3 */ FD_INVALID,
226 : /* 0xb4 */ FD_VALID, /* 0xb5 */ FD_CHECK_JMP, /* 0xb6 */ FD_VALID, /* 0xb7 */ FD_VALID,
227 : /* 0xb8 */ FD_INVALID, /* 0xb9 */ FD_INVALID, /* 0xba */ FD_INVALID, /* 0xbb */ FD_INVALID,
228 : /* 0xbc */ FD_VALID, /* 0xbd */ FD_CHECK_JMP, /* 0xbe */ FD_VALID, /* 0xbf */ FD_VALID,
229 : /* 0xc0 */ FD_INVALID, /* 0xc1 */ FD_INVALID, /* 0xc2 */ FD_INVALID, /* 0xc3 */ FD_INVALID,
230 : /* 0xc4 */ FD_CHECK_SH32, /* 0xc5 */ FD_CHECK_JMP, /* 0xc6 */ FD_CHECK_DIV, /* 0xc7 */ FD_CHECK_SH64,
231 : /* 0xc8 */ FD_INVALID, /* 0xc9 */ FD_INVALID, /* 0xca */ FD_INVALID, /* 0xcb */ FD_INVALID,
232 : /* 0xcc */ FD_VALID, /* 0xcd */ FD_CHECK_JMP, /* 0xce */ FD_VALID, /* 0xcf */ FD_VALID,
233 : /* 0xd0 */ FD_INVALID, /* 0xd1 */ FD_INVALID, /* 0xd2 */ FD_INVALID, /* 0xd3 */ FD_INVALID,
234 : /* 0xd4 */ FD_INVALID, /* 0xd5 */ FD_CHECK_JMP, /* 0xd6 */ FD_CHECK_DIV, /* 0xd7 */ FD_INVALID,
235 : /* 0xd8 */ FD_INVALID, /* 0xd9 */ FD_INVALID, /* 0xda */ FD_INVALID, /* 0xdb */ FD_INVALID,
236 : /* 0xdc */ FD_CHECK_END, /* 0xdd */ FD_CHECK_JMP, /* 0xde */ FD_VALID, /* 0xdf */ FD_INVALID,
237 : /* 0xe0 */ FD_INVALID, /* 0xe1 */ FD_INVALID, /* 0xe2 */ FD_INVALID, /* 0xe3 */ FD_INVALID,
238 : /* 0xe4 */ FD_INVALID, /* 0xe5 */ FD_INVALID, /* 0xe6 */ FD_CHECK_DIV, /* 0xe7 */ FD_INVALID,
239 : /* 0xe8 */ FD_INVALID, /* 0xe9 */ FD_INVALID, /* 0xea */ FD_INVALID, /* 0xeb */ FD_INVALID,
240 : /* 0xec */ FD_INVALID, /* 0xed */ FD_INVALID, /* 0xee */ FD_VALID, /* 0xef */ FD_INVALID,
241 : /* 0xf0 */ FD_INVALID, /* 0xf1 */ FD_INVALID, /* 0xf2 */ FD_INVALID, /* 0xf3 */ FD_INVALID,
242 : /* 0xf4 */ FD_INVALID, /* 0xf5 */ FD_INVALID, /* 0xf6 */ FD_CHECK_DIV, /* 0xf7 */ FD_VALID,
243 : /* 0xf8 */ FD_INVALID, /* 0xf9 */ FD_INVALID, /* 0xfa */ FD_INVALID, /* 0xfb */ FD_INVALID,
244 : /* 0xfc */ FD_INVALID, /* 0xfd */ FD_INVALID, /* 0xfe */ FD_VALID, /* 0xff */ FD_INVALID,
245 7848 : };
246 :
247 : /* SIMD-0173: LDDW */
248 7848 : validation_map[ 0x18 ] = FD_VM_SBPF_ENABLE_LDDW(sbpf_version) ? FD_CHECK_LDQ : FD_INVALID;
249 7848 : validation_map[ 0xf7 ] = FD_VM_SBPF_ENABLE_LDDW(sbpf_version) ? FD_INVALID : FD_VALID; /* HOR64 */
250 :
251 : /* SIMD-0173: LE */
252 7848 : validation_map[ 0xd4 ] = FD_VM_SBPF_ENABLE_LE (sbpf_version) ? FD_CHECK_END : FD_INVALID;
253 :
254 : /* SIMD-0173: LDXW, STW, STXW */
255 7848 : validation_map[ 0x61 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_VALID;
256 7848 : validation_map[ 0x62 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_CHECK_ST;
257 7848 : validation_map[ 0x63 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_CHECK_ST;
258 7848 : validation_map[ 0x8c ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_VALID : FD_INVALID;
259 7848 : validation_map[ 0x87 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST : FD_VALID; /* VALID because it's NEG64 */
260 7848 : validation_map[ 0x8f ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST : FD_INVALID;
261 :
262 : /* SIMD-0173: LDXH, STH, STXH */
263 7848 : validation_map[ 0x69 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_VALID;
264 7848 : validation_map[ 0x6a ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_CHECK_ST;
265 7848 : validation_map[ 0x6b ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_CHECK_ST;
266 7848 : validation_map[ 0x3c ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_VALID : FD_VALID;
267 7848 : validation_map[ 0x37 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST : FD_CHECK_DIV;
268 7848 : validation_map[ 0x3f ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST : FD_VALID;
269 :
270 : /* SIMD-0173: LDXB, STB, STXB */
271 7848 : validation_map[ 0x71 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_VALID;
272 7848 : validation_map[ 0x72 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_CHECK_ST;
273 7848 : validation_map[ 0x73 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_CHECK_ST;
274 7848 : validation_map[ 0x2c ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_VALID : FD_VALID;
275 7848 : validation_map[ 0x27 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST : FD_VALID;
276 7848 : validation_map[ 0x2f ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST : FD_VALID;
277 :
278 : /* SIMD-0173: LDXDW, STDW, STXDW */
279 7848 : validation_map[ 0x79 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_VALID;
280 7848 : validation_map[ 0x7a ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_CHECK_ST;
281 7848 : validation_map[ 0x7b ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_CHECK_ST;
282 7848 : validation_map[ 0x9c ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_VALID : FD_VALID;
283 7848 : validation_map[ 0x97 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST : FD_CHECK_DIV;
284 7848 : validation_map[ 0x9f ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST : FD_VALID;
285 :
286 : /* SIMD-0173: CALLX */
287 7848 : validation_map[ 0x8d ] = FD_VM_SBPF_CALLX_USES_SRC_REG(sbpf_version) ? FD_CHECK_CALL_REG : FD_CHECK_CALL_REG_DEPR;
288 :
289 : /* SIMD-0174: MUL, DIV, MOD */
290 7848 : validation_map[ 0x24 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_INVALID : FD_VALID;
291 7848 : validation_map[ 0x34 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_INVALID : FD_CHECK_DIV;
292 7848 : validation_map[ 0x94 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_INVALID : FD_CHECK_DIV;
293 : /* note: 0x?c, 0x?7, 0x?f should not be overwritten because they're now load/store ix */
294 :
295 : /* SIMD-0174: NEG */
296 7848 : validation_map[ 0x84 ] = FD_VM_SBPF_ENABLE_NEG (sbpf_version) ? FD_VALID : FD_INVALID;
297 : /* note: 0x87 should not be overwritten because it was NEG64 and it becomes STW */
298 :
299 : /* SIMD-0174: MUL, DIV, MOD */
300 7848 : validation_map[ 0x36 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID; /* UHMUL64 */
301 7848 : validation_map[ 0x3e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
302 7848 : validation_map[ 0x46 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* UDIV32 */
303 7848 : validation_map[ 0x4e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
304 7848 : validation_map[ 0x56 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* UDIV64 */
305 7848 : validation_map[ 0x5e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
306 7848 : validation_map[ 0x66 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* UREM32 */
307 7848 : validation_map[ 0x6e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
308 7848 : validation_map[ 0x76 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* UREM64 */
309 7848 : validation_map[ 0x7e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
310 7848 : validation_map[ 0x86 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID; /* LMUL32 */
311 7848 : validation_map[ 0x8e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
312 7848 : validation_map[ 0x96 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID; /* LMUL64 */
313 7848 : validation_map[ 0x9e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
314 7848 : validation_map[ 0xb6 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID; /* SHMUL64 */
315 7848 : validation_map[ 0xbe ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
316 7848 : validation_map[ 0xc6 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* SDIV32 */
317 7848 : validation_map[ 0xce ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
318 7848 : validation_map[ 0xd6 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* SDIV64 */
319 7848 : validation_map[ 0xde ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
320 7848 : validation_map[ 0xe6 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* SREM32 */
321 7848 : validation_map[ 0xee ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
322 7848 : validation_map[ 0xf6 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* SREM64 */
323 7848 : validation_map[ 0xfe ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
324 :
325 : /* SIMD-0178: static syscalls */
326 7848 : validation_map[ 0x85 ] = FD_VM_SBPF_STATIC_SYSCALLS (sbpf_version) ? FD_CHECK_CALL_IMM : FD_VALID;
327 7848 : validation_map[ 0x95 ] = FD_VM_SBPF_STATIC_SYSCALLS (sbpf_version) ? FD_CHECK_SYSCALL : FD_VALID;
328 7848 : validation_map[ 0x9d ] = FD_VM_SBPF_STATIC_SYSCALLS (sbpf_version) ? FD_VALID : FD_INVALID;
329 :
330 : /* FIXME: These checks are not necessary assuming fd_vm_t is populated by metadata
331 : generated in fd_sbpf_elf_peek (which performs these checks). But there is no guarantee, and
332 : this non-guarantee is (rightfully) exploited by the fuzz harnesses.
333 : Agave doesn't perform these checks explicitly due to Rust's guarantees */
334 7848 : if( FD_UNLIKELY( vm->text_sz / 8UL != vm->text_cnt ||
335 7848 : (const uchar *)vm->text < vm->rodata ||
336 7848 : (ulong)vm->text > (ulong)vm->text + vm->text_sz || /* Overflow chk */
337 7848 : (const uchar *)vm->text + vm->text_sz > vm->rodata + vm->rodata_sz ) )
338 0 : return FD_VM_ERR_BAD_TEXT;
339 :
340 7848 : if( FD_UNLIKELY( !fd_ulong_is_aligned( vm->text_sz, 8UL ) ) ) /* https://github.com/solana-labs/rbpf/blob/v0.8.0/src/verifier.rs#L109 */
341 0 : return FD_VM_TEXT_SZ_UNALIGNED;
342 :
343 7848 : if ( FD_UNLIKELY( vm->text_cnt == 0UL ) ) /* https://github.com/solana-labs/rbpf/blob/v0.8.0/src/verifier.rs#L112 */
344 0 : return FD_VM_ERR_EMPTY;
345 :
346 7848 : ulong function_start = 0UL;
347 7848 : ulong function_next = 0UL;
348 7848 : if( FD_VM_SBPF_STATIC_SYSCALLS(sbpf_version) ) {
349 0 : function_next = fd_sbpf_calldests_const_iter_init( vm->calldests );
350 0 : FD_TEST( function_next==0UL ); /* assert that the first function always starts at 0. */
351 0 : }
352 :
353 7848 : ulong const * text = vm->text;
354 7848 : ulong text_cnt = vm->text_cnt;
355 805362735 : for( ulong i=0UL; i<text_cnt; i++ ) {
356 805357341 : fd_sbpf_instr_t instr = fd_sbpf_instr( text[i] );
357 :
358 : /* Validate functions, stored in vm->calldests.
359 : https://github.com/anza-xyz/sbpf/blob/v0.11.1/src/verifier.rs#L253-L263
360 : At the start of a function, we check that the function ends with JA(0x05) or RETURN(0x9D).
361 : As a side effect, the range of the function is [function_start, function_next-1],
362 : used to validate jumps.
363 : Note that the first function always starts at 0, and similarly the last function
364 : always ends at text_cnt-1. */
365 805357341 : if( FD_UNLIKELY( FD_VM_SBPF_STATIC_SYSCALLS(sbpf_version) && i==function_next ) ) {
366 0 : function_start = function_next;
367 0 : function_next = fd_sbpf_calldests_const_iter_next( vm->calldests, function_start );
368 0 : if( fd_sbpf_calldests_const_iter_done( function_next ) ) {
369 0 : function_next = text_cnt;
370 0 : }
371 0 : fd_sbpf_instr_t end_instr = fd_sbpf_instr( text[function_next-1] );
372 0 : if( FD_UNLIKELY( end_instr.opcode.raw!=0x05 && end_instr.opcode.raw!=0x9D ) ) {
373 0 : return FD_VM_INVALID_FUNCTION;
374 0 : }
375 0 : }
376 :
377 805357341 : uchar validation_code = validation_map[ instr.opcode.raw ];
378 805357341 : switch( validation_code ) {
379 :
380 644296056 : case FD_VALID: break;
381 :
382 : /* Store ops are special because they allow dreg==r10.
383 : We use a special validation_code, used later in the
384 : "Check registers" section.
385 : But there's nothing to do at this time. */
386 3690 : case FD_CHECK_ST: break;
387 :
388 6735 : case FD_CHECK_JMP_V0: {
389 6735 : long jmp_dst = (long)i + (long)instr.offset + 1L;
390 6735 : if( FD_UNLIKELY( (jmp_dst<0) | (jmp_dst>=(long)text_cnt) ) ) return FD_VM_ERR_JMP_OUT_OF_BOUNDS;
391 : //FIXME: this shouldn't be here?
392 6597 : if( FD_UNLIKELY( fd_sbpf_instr( text[ jmp_dst ] ).opcode.raw==FD_SBPF_OP_ADDL_IMM ) ) return FD_VM_ERR_JMP_TO_ADDL_IMM;
393 6597 : break;
394 6597 : }
395 :
396 6597 : case FD_CHECK_JMP_V3: {
397 0 : long jmp_dst = (long)i + (long)instr.offset + 1L;
398 0 : if( FD_UNLIKELY( (jmp_dst<(long)function_start) | (jmp_dst>=(long)function_next) ) ) return FD_VM_ERR_JMP_OUT_OF_BOUNDS;
399 0 : break;
400 0 : }
401 :
402 96 : case FD_CHECK_END: {
403 96 : if( FD_UNLIKELY( !((instr.imm==16) | (instr.imm==32) | (instr.imm==64)) ) ) return FD_VM_ERR_INVALID_END_IMM;
404 78 : break;
405 96 : }
406 :
407 : /* https://github.com/solana-labs/rbpf/blob/b503a1867a9cfa13f93b4d99679a17fe219831de/src/verifier.rs#L244 */
408 1341 : case FD_CHECK_LDQ: {
409 : /* https://github.com/solana-labs/rbpf/blob/b503a1867a9cfa13f93b4d99679a17fe219831de/src/verifier.rs#L131 */
410 1341 : if( FD_UNLIKELY( (i+1UL)>=text_cnt ) ) return FD_VM_ERR_INCOMPLETE_LDQ;
411 :
412 : /* https://github.com/solana-labs/rbpf/blob/b503a1867a9cfa13f93b4d99679a17fe219831de/src/verifier.rs#L137-L139 */
413 1341 : fd_sbpf_instr_t addl_imm = fd_sbpf_instr( text[ i+1UL ] );
414 1341 : if( FD_UNLIKELY( addl_imm.opcode.raw!=FD_SBPF_OP_ADDL_IMM ) ) return FD_VM_ERR_LDQ_NO_ADDL_IMM;
415 :
416 : /* FIXME: SET A BIT MAP HERE OF ADDL_IMM TO DENOTE * AS FORBIDDEN
417 : BRANCH TARGETS OF CALL_REG?? */
418 :
419 1341 : i++; /* Skip the addl imm */
420 1341 : break;
421 1341 : }
422 :
423 64406880 : case FD_CHECK_DIV: {
424 64406880 : if( FD_UNLIKELY( instr.imm==0 ) ) return FD_VM_ERR_SIGFPE;
425 64406820 : break;
426 64406880 : }
427 :
428 64406820 : case FD_CHECK_SH32: {
429 48308280 : if( FD_UNLIKELY( instr.imm>=32 ) ) return FD_VM_SH_OVERFLOW;
430 48308250 : break;
431 48308280 : }
432 :
433 48332559 : case FD_CHECK_SH64: {
434 48332559 : if( FD_UNLIKELY( instr.imm>=64 ) ) return FD_VM_SH_OVERFLOW;
435 48332517 : break;
436 48332559 : }
437 :
438 : /* https://github.com/anza-xyz/sbpf/blob/v0.11.1/src/verifier.rs#L220 */
439 48332517 : case FD_CHECK_CALL_REG: {
440 21 : if( FD_UNLIKELY( instr.src_reg > 9 ) ) {
441 9 : return FD_VM_ERR_INVALID_REG;
442 9 : }
443 12 : break;
444 21 : }
445 507 : case FD_CHECK_CALL_REG_DEPR: {
446 507 : if( FD_UNLIKELY( instr.imm > 9 ) ) {
447 9 : return FD_VM_ERR_INVALID_REG;
448 9 : }
449 498 : break;
450 507 : }
451 :
452 : /* https://github.com/anza-xyz/sbpf/blob/v0.11.1/src/verifier.rs#L411-L418 */
453 498 : case FD_CHECK_CALL_IMM: {
454 0 : ulong target_pc = (ulong)( fd_long_sat_add( (long)i, fd_long_sat_add( (long)(int)instr.imm, 1 ) ) );
455 0 : if( FD_UNLIKELY( target_pc>=text_cnt || !fd_sbpf_calldests_test( vm->calldests, target_pc ) ) ) {
456 0 : return FD_VM_INVALID_FUNCTION;
457 0 : }
458 0 : break;
459 0 : }
460 :
461 : /* https://github.com/anza-xyz/sbpf/blob/v0.11.1/src/verifier.rs#L423-L428 */
462 0 : case FD_CHECK_SYSCALL: {
463 : /* check active syscall */
464 0 : fd_sbpf_syscalls_t const * syscall = fd_sbpf_syscalls_query_const( vm->syscalls, (ulong)instr.imm, NULL );
465 0 : if( FD_UNLIKELY( !syscall ) ) {
466 0 : return FD_VM_INVALID_SYSCALL;
467 0 : }
468 0 : break;
469 0 : }
470 :
471 1176 : case FD_INVALID: default: return FD_VM_ERR_INVALID_OPCODE;
472 805357341 : }
473 :
474 : /* Check registers
475 : https://github.com/solana-labs/rbpf/blob/v0.8.5/src/verifier.rs#L177 */
476 :
477 : /* Source register */
478 805355859 : if( FD_UNLIKELY( instr.src_reg>10 ) ) return FD_VM_ERR_INVALID_SRC_REG;
479 :
480 : /* Special R10 register allowed for ADD64_IMM */
481 805355469 : if( instr.dst_reg==10U
482 805355469 : && FD_VM_SBPF_DYNAMIC_STACK_FRAMES( sbpf_version )
483 805355469 : && instr.opcode.raw == 0x07
484 805355469 : && ( instr.imm % FD_VM_SBPF_DYNAMIC_STACK_FRAMES_ALIGN )==0 )
485 9 : continue;
486 :
487 : /* Destination register. */
488 805355460 : if( FD_UNLIKELY( instr.dst_reg==10U && validation_code != FD_CHECK_ST ) ) return FD_VM_ERR_INVALID_DST_REG;
489 805355079 : if( FD_UNLIKELY( instr.dst_reg > 10U ) ) return FD_VM_ERR_INVALID_DST_REG;
490 805355079 : }
491 :
492 5394 : return FD_VM_SUCCESS;
493 7848 : }
494 :
495 : FD_FN_CONST ulong
496 411 : fd_vm_align( void ) {
497 411 : return FD_VM_ALIGN;
498 411 : }
499 :
500 : FD_FN_CONST ulong
501 201 : fd_vm_footprint( void ) {
502 201 : return FD_VM_FOOTPRINT;
503 201 : }
504 :
505 : void *
506 201 : fd_vm_new( void * shmem ) {
507 :
508 201 : if( FD_UNLIKELY( !shmem ) ) {
509 0 : FD_LOG_WARNING(( "NULL shmem" ));
510 0 : return NULL;
511 0 : }
512 :
513 201 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_vm_align() ) ) ) {
514 0 : FD_LOG_WARNING(( "misaligned shmem" ));
515 0 : return NULL;
516 0 : }
517 :
518 201 : fd_vm_t * vm = (fd_vm_t *)shmem;
519 201 : fd_memset( vm, 0, fd_vm_footprint() );
520 :
521 201 : FD_COMPILER_MFENCE();
522 201 : FD_VOLATILE( vm->magic ) = FD_VM_MAGIC;
523 201 : FD_COMPILER_MFENCE();
524 :
525 201 : return shmem;
526 201 : }
527 :
528 : fd_vm_t *
529 201 : fd_vm_join( void * shmem ) {
530 :
531 201 : if( FD_UNLIKELY( !shmem ) ) {
532 0 : FD_LOG_WARNING(( "NULL shmem" ));
533 0 : return NULL;
534 0 : }
535 :
536 201 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_vm_align() ) ) ) {
537 0 : FD_LOG_WARNING(( "misaligned shmem" ));
538 0 : return NULL;
539 0 : }
540 :
541 201 : fd_vm_t * vm = (fd_vm_t *)shmem;
542 :
543 201 : if( FD_UNLIKELY( vm->magic!=FD_VM_MAGIC ) ) {
544 0 : FD_LOG_WARNING(( "bad magic" ));
545 0 : return NULL;
546 0 : }
547 :
548 201 : return vm;
549 201 : }
550 :
551 : void *
552 9 : fd_vm_leave( fd_vm_t * vm ) {
553 :
554 9 : if( FD_UNLIKELY( !vm ) ) {
555 0 : FD_LOG_WARNING(( "NULL vm" ));
556 0 : return NULL;
557 0 : }
558 :
559 9 : return (void *)vm;
560 9 : }
561 :
562 : void *
563 9 : fd_vm_delete( void * shmem ) {
564 :
565 9 : if( FD_UNLIKELY( !shmem ) ) {
566 0 : FD_LOG_WARNING(( "NULL shmem" ));
567 0 : return NULL;
568 0 : }
569 :
570 9 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_vm_align() ) ) ) {
571 0 : FD_LOG_WARNING(( "misaligned shmem" ));
572 0 : return NULL;
573 0 : }
574 :
575 9 : fd_vm_t * vm = (fd_vm_t *)shmem;
576 :
577 9 : if( FD_UNLIKELY( vm->magic!=FD_VM_MAGIC ) ) {
578 0 : FD_LOG_WARNING(( "bad magic" ));
579 0 : return NULL;
580 0 : }
581 :
582 9 : FD_COMPILER_MFENCE();
583 9 : FD_VOLATILE( vm->magic ) = 0UL;
584 9 : FD_COMPILER_MFENCE();
585 :
586 9 : return (void *)vm;
587 9 : }
588 :
589 : fd_vm_t *
590 : fd_vm_init(
591 : fd_vm_t * vm,
592 : fd_exec_instr_ctx_t *instr_ctx,
593 : ulong heap_max,
594 : ulong entry_cu,
595 : uchar const * rodata,
596 : ulong rodata_sz,
597 : ulong const * text,
598 : ulong text_cnt,
599 : ulong text_off,
600 : ulong text_sz,
601 : ulong entry_pc,
602 : ulong * calldests,
603 : ulong sbpf_version,
604 : fd_sbpf_syscalls_t * syscalls,
605 : fd_vm_trace_t * trace,
606 : fd_sha256_t * sha,
607 : fd_vm_input_region_t * mem_regions,
608 : uint mem_regions_cnt,
609 : fd_vm_acc_region_meta_t * acc_region_metas,
610 : uchar is_deprecated,
611 : int direct_mapping,
612 7854 : int dump_syscall_to_pb ) {
613 :
614 7854 : if ( FD_UNLIKELY( vm == NULL ) ) {
615 0 : FD_LOG_WARNING(( "NULL vm" ));
616 0 : return NULL;
617 0 : }
618 :
619 7854 : if ( FD_UNLIKELY( vm->magic != FD_VM_MAGIC ) ) {
620 0 : FD_LOG_WARNING(( "bad magic" ));
621 0 : return NULL;
622 0 : }
623 :
624 7854 : if ( FD_UNLIKELY( heap_max > FD_VM_HEAP_MAX ) ) {
625 0 : FD_LOG_WARNING(( "heap_max > FD_VM_HEAP_MAX" ));
626 0 : return NULL;
627 0 : }
628 :
629 : /* We do support calldests==NULL for tests that do not require
630 : program execution, e.g. just testing some interpreter functionality
631 : or syscalls.
632 : However in v3, if calldests is specified, it must be a valid calldests.
633 : In particular, the bit 0 should be always set to 1.
634 : This property is derived from:
635 : https://github.com/anza-xyz/sbpf/blob/v0.11.1/src/elf.rs#L529
636 : and it's used by fd_vm_validate() */
637 7854 : if( FD_LIKELY( calldests && FD_VM_SBPF_STATIC_SYSCALLS(sbpf_version) ) ) {
638 0 : fd_sbpf_calldests_insert( calldests, 0 );
639 0 : }
640 :
641 : // Set the vm fields
642 7854 : vm->instr_ctx = instr_ctx;
643 7854 : vm->heap_max = heap_max;
644 7854 : vm->entry_cu = entry_cu;
645 7854 : vm->rodata = rodata;
646 7854 : vm->rodata_sz = rodata_sz;
647 7854 : vm->text = text;
648 7854 : vm->text_cnt = text_cnt;
649 7854 : vm->text_off = text_off;
650 7854 : vm->text_sz = text_sz;
651 7854 : vm->entry_pc = entry_pc;
652 7854 : vm->calldests = calldests;
653 7854 : vm->sbpf_version = sbpf_version;
654 7854 : vm->syscalls = syscalls;
655 7854 : vm->trace = trace;
656 7854 : vm->sha = sha;
657 7854 : vm->input_mem_regions = mem_regions;
658 7854 : vm->input_mem_regions_cnt = mem_regions_cnt;
659 7854 : vm->acc_region_metas = acc_region_metas;
660 7854 : vm->is_deprecated = is_deprecated;
661 7854 : vm->direct_mapping = direct_mapping;
662 7854 : vm->stack_frame_size = FD_VM_STACK_FRAME_SZ + ( direct_mapping ? 0UL : FD_VM_STACK_GUARD_SZ );
663 7854 : vm->segv_store_vaddr = ULONG_MAX;
664 7854 : vm->dump_syscall_to_pb = dump_syscall_to_pb;
665 :
666 : /* Unpack the configuration */
667 7854 : int err = fd_vm_setup_state_for_execution( vm );
668 7854 : if( FD_UNLIKELY( err != FD_VM_SUCCESS ) ) {
669 0 : return NULL;
670 0 : }
671 :
672 7854 : return vm;
673 7854 : }
674 :
675 : int
676 7854 : fd_vm_setup_state_for_execution( fd_vm_t * vm ) {
677 :
678 7854 : if ( FD_UNLIKELY( !vm ) ) {
679 0 : FD_LOG_WARNING(( "NULL vm" ));
680 0 : return FD_VM_ERR_INVAL;
681 0 : }
682 :
683 : /* Unpack input and rodata */
684 7854 : fd_vm_mem_cfg( vm );
685 :
686 : /* Initialize registers */
687 : /* FIXME: Zero out shadow, stack and heap here? */
688 7854 : fd_memset( vm->reg, 0, FD_VM_REG_MAX * sizeof(ulong) );
689 7854 : vm->reg[ 1] = FD_VM_MEM_MAP_INPUT_REGION_START;
690 : /* https://github.com/solana-labs/rbpf/blob/4ad935be45e5663be23b30cfc750b1ae1ad03c44/src/vm.rs#L326-L333 */
691 7854 : vm->reg[10] = FD_VM_MEM_MAP_STACK_REGION_START +
692 7854 : ( FD_VM_SBPF_DYNAMIC_STACK_FRAMES( vm->sbpf_version ) ? FD_VM_STACK_MAX : FD_VM_STACK_FRAME_SZ );
693 : /* Note: Agave uses r11 as pc, we don't */
694 :
695 : /* Set execution state */
696 7854 : vm->pc = vm->entry_pc;
697 7854 : vm->ic = 0UL;
698 7854 : vm->cu = vm->entry_cu;
699 7854 : vm->frame_cnt = 0UL;
700 :
701 7854 : vm->heap_sz = 0UL;
702 :
703 : /* Do NOT reset logs */
704 :
705 7854 : return FD_VM_SUCCESS;
706 7854 : }
|