Line data Source code
1 : #include "fd_vm_private.h"
2 : #include "../../ballet/sbpf/fd_sbpf_instr.h"
3 : #include "../../ballet/sbpf/fd_sbpf_opcodes.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 "Invalid parameters.";
45 0 : case FD_VM_SYSCALL_ERR_POSEIDON_INVALID_ENDIANNESS: return "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 6 : fd_vm_ebpf_strerror( int err ) {
59 :
60 6 : 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 6 : 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_MEMORY_REGION: return "Invalid memory region at index"; // truncated
73 0 : case FD_VM_ERR_EBPF_ACCESS_VIOLATION: return "Access violation"; // truncated
74 0 : case FD_VM_ERR_EBPF_STACK_ACCESS_VIOLATION: return "Access violation in stack frame"; // truncated
75 0 : case FD_VM_ERR_EBPF_INVALID_INSTRUCTION: return "invalid BPF instruction";
76 0 : case FD_VM_ERR_EBPF_UNSUPPORTED_INSTRUCTION: return "unsupported BPF instruction";
77 0 : case FD_VM_ERR_EBPF_EXHAUSTED_TEXT_SEGMENT: return "Compilation exhausted text segment at BPF instruction"; // truncated
78 0 : case FD_VM_ERR_EBPF_LIBC_INVOCATION_FAILED: return "Libc calling returned error code"; // truncated
79 0 : case FD_VM_ERR_EBPF_VERIFIER_ERROR: return "Verifier error"; // truncated
80 0 : case FD_VM_ERR_EBPF_SYSCALL_ERROR: return ""; // handled explicitly via fd_vm_syscall_strerror()
81 :
82 0 : default: break;
83 6 : }
84 :
85 0 : return "";
86 6 : }
87 :
88 : /* fd_vm_strerror() returns the error message corresponding to err, used internally
89 : for system logs, NOT for log_collector / transaction logs. */
90 : char const *
91 42 : fd_vm_strerror( int err ) {
92 :
93 42 : switch( err ) {
94 :
95 : /* "Standard" Firedancer error codes */
96 :
97 3 : case FD_VM_SUCCESS: return "SUCCESS success";
98 3 : case FD_VM_ERR_INVAL: return "INVAL invalid request";
99 3 : case FD_VM_ERR_UNSUP: return "UNSUP unsupported request";
100 3 : case FD_VM_ERR_FULL: return "FULL storage full";
101 3 : case FD_VM_ERR_EMPTY: return "EMPTY nothing to do";
102 3 : case FD_VM_ERR_IO: return "IO input-output error";
103 :
104 : /* VM exec error codes */
105 :
106 0 : case FD_VM_ERR_SIGFPE: return "SIGFPE division by zero";
107 :
108 : /* VM validate error codes */
109 :
110 3 : case FD_VM_ERR_INVALID_OPCODE: return "INVALID_OPCODE detected an invalid opcode";
111 3 : case FD_VM_ERR_INVALID_SRC_REG: return "INVALID_SRC_REG detected an invalid source register";
112 3 : case FD_VM_ERR_INVALID_DST_REG: return "INVALID_DST_REG detected an invalid destination register";
113 3 : case FD_VM_ERR_JMP_OUT_OF_BOUNDS: return "JMP_OUT_OF_BOUNDS detected an out of bounds jump";
114 3 : case FD_VM_ERR_JMP_TO_ADDL_IMM: return "JMP_TO_ADDL_IMM detected a jump to an addl imm";
115 3 : case FD_VM_ERR_INVALID_END_IMM: return "INVALID_END_IMM detected an invalid immediate for an endianness conversion instruction";
116 3 : case FD_VM_ERR_INCOMPLETE_LDQ: return "INCOMPLETE_LDQ detected an incomplete ldq at program end";
117 3 : case FD_VM_ERR_LDQ_NO_ADDL_IMM: return "LDQ_NO_ADDL_IMM detected a ldq without an addl imm following it";
118 0 : case FD_VM_ERR_INVALID_REG: return "INVALID_REG detected an invalid register number in a callx instruction";
119 0 : case FD_VM_ERR_BAD_TEXT: return "BAD_TEXT detected a bad text section";
120 0 : case FD_VM_SH_OVERFLOW: return "SH_OVERFLOW detected a shift overflow in an instruction";
121 0 : case FD_VM_TEXT_SZ_UNALIGNED: return "TEXT_SZ_UNALIGNED detected an unaligned text section size (not a multiple of 8)";
122 :
123 0 : default: break;
124 42 : }
125 :
126 0 : return "UNKNOWN probably not a FD_VM_ERR code";
127 42 : }
128 :
129 : /* FIXME: add a pedantic version of this validation that does things
130 : like:
131 : - only 0 imms when the instruction does not use an imm
132 : - same as above but for src/dst reg, offset */
133 : /* FIXME: HANDLING OF LDQ ON NEWER SBPF VERSUS OLDER SBPF (AND WITH CALL
134 : REG) */
135 : /* FIXME: LINK TO SOLANA CODE VALIDATE AND DOUBLE CHECK THIS BEHAVES
136 : IDENTICALLY! */
137 :
138 : int
139 11529 : fd_vm_validate( fd_vm_t const * vm ) {
140 :
141 11529 : ulong sbpf_version = vm->sbpf_version;
142 :
143 : /* A mapping of all the possible 1-byte sBPF opcodes to their
144 : validation criteria. */
145 :
146 645785994 : # define FD_VALID ((uchar)0) /* Valid opcode */
147 356628 : # define FD_CHECK_JMP ((uchar)1) /* Validation should check that the instruction is a valid jump */
148 18852 : # define FD_CHECK_END ((uchar)2) /* Validation should check that the instruction is a valid endianness conversion */
149 334350 : # define FD_CHECK_ST ((uchar)3) /* Validation should check that the instruction is a valid store */
150 51114 : # define FD_CHECK_LDQ ((uchar)4) /* Validation should check that the instruction is a valid load-quad */
151 64609248 : # define FD_CHECK_DIV ((uchar)5) /* Validation should check that the instruction is a valid division by immediate */
152 48343005 : # define FD_CHECK_SH32 ((uchar)6) /* Validation should check that the immediate is a valid 32-bit shift exponent */
153 48382416 : # define FD_CHECK_SH64 ((uchar)7) /* Validation should check that the immediate is a valid 64-bit shift exponent */
154 2417844 : # define FD_INVALID ((uchar)8) /* The opcode is invalid */
155 15885 : # define FD_CHECK_CALL_REG_SRC ((uchar)9) /* Validation should check that callx has valid register number in src */
156 11529 : # define FD_CHECK_CALL_REG_DST ((uchar)13) /* Validation should check that callx has a valid register number in dst */
157 25227 : # define FD_CHECK_CALL_REG_IMM ((uchar)10) /* Validation should check that callx has a valid register number in imm */
158 :
159 11529 : uchar validation_map[ 256 ] = {
160 11529 : /* 0x00 */ FD_INVALID, /* 0x01 */ FD_INVALID, /* 0x02 */ FD_INVALID, /* 0x03 */ FD_INVALID,
161 11529 : /* 0x04 */ FD_VALID, /* 0x05 */ FD_CHECK_JMP, /* 0x06 */ FD_INVALID, /* 0x07 */ FD_VALID,
162 11529 : /* 0x08 */ FD_INVALID, /* 0x09 */ FD_INVALID, /* 0x0a */ FD_INVALID, /* 0x0b */ FD_INVALID,
163 11529 : /* 0x0c */ FD_VALID, /* 0x0d */ FD_INVALID, /* 0x0e */ FD_INVALID, /* 0x0f */ FD_VALID,
164 11529 : /* 0x10 */ FD_INVALID, /* 0x11 */ FD_INVALID, /* 0x12 */ FD_INVALID, /* 0x13 */ FD_INVALID,
165 11529 : /* 0x14 */ FD_VALID, /* 0x15 */ FD_CHECK_JMP, /* 0x16 */ FD_INVALID, /* 0x17 */ FD_VALID,
166 11529 : /* 0x18 */ FD_INVALID, /* 0x19 */ FD_INVALID, /* 0x1a */ FD_INVALID, /* 0x1b */ FD_INVALID,
167 11529 : /* 0x1c */ FD_VALID, /* 0x1d */ FD_CHECK_JMP, /* 0x1e */ FD_INVALID, /* 0x1f */ FD_VALID,
168 11529 : /* 0x20 */ FD_INVALID, /* 0x21 */ FD_INVALID, /* 0x22 */ FD_INVALID, /* 0x23 */ FD_INVALID,
169 11529 : /* 0x24 */ FD_INVALID, /* 0x25 */ FD_CHECK_JMP, /* 0x26 */ FD_INVALID, /* 0x27 */ FD_CHECK_ST,
170 11529 : /* 0x28 */ FD_INVALID, /* 0x29 */ FD_INVALID, /* 0x2a */ FD_INVALID, /* 0x2b */ FD_INVALID,
171 11529 : /* 0x2c */ FD_VALID, /* 0x2d */ FD_CHECK_JMP, /* 0x2e */ FD_INVALID, /* 0x2f */ FD_CHECK_ST,
172 11529 : /* 0x30 */ FD_INVALID, /* 0x31 */ FD_INVALID, /* 0x32 */ FD_INVALID, /* 0x33 */ FD_INVALID,
173 11529 : /* 0x34 */ FD_INVALID, /* 0x35 */ FD_CHECK_JMP, /* 0x36 */ FD_VALID, /* 0x37 */ FD_CHECK_ST,
174 11529 : /* 0x38 */ FD_INVALID, /* 0x39 */ FD_INVALID, /* 0x3a */ FD_INVALID, /* 0x3b */ FD_INVALID,
175 11529 : /* 0x3c */ FD_VALID, /* 0x3d */ FD_CHECK_JMP, /* 0x3e */ FD_VALID, /* 0x3f */ FD_CHECK_ST,
176 11529 : /* 0x40 */ FD_INVALID, /* 0x41 */ FD_INVALID, /* 0x42 */ FD_INVALID, /* 0x43 */ FD_INVALID,
177 11529 : /* 0x44 */ FD_VALID, /* 0x45 */ FD_CHECK_JMP, /* 0x46 */ FD_CHECK_DIV, /* 0x47 */ FD_VALID,
178 11529 : /* 0x48 */ FD_INVALID, /* 0x49 */ FD_INVALID, /* 0x4a */ FD_INVALID, /* 0x4b */ FD_INVALID,
179 11529 : /* 0x4c */ FD_VALID, /* 0x4d */ FD_CHECK_JMP, /* 0x4e */ FD_VALID, /* 0x4f */ FD_VALID,
180 11529 : /* 0x50 */ FD_INVALID, /* 0x51 */ FD_INVALID, /* 0x52 */ FD_INVALID, /* 0x53 */ FD_INVALID,
181 11529 : /* 0x54 */ FD_VALID, /* 0x55 */ FD_CHECK_JMP, /* 0x56 */ FD_CHECK_DIV, /* 0x57 */ FD_VALID,
182 11529 : /* 0x58 */ FD_INVALID, /* 0x59 */ FD_INVALID, /* 0x5a */ FD_INVALID, /* 0x5b */ FD_INVALID,
183 11529 : /* 0x5c */ FD_VALID, /* 0x5d */ FD_CHECK_JMP, /* 0x5e */ FD_VALID, /* 0x5f */ FD_VALID,
184 11529 : /* 0x60 */ FD_INVALID, /* 0x61 */ FD_INVALID, /* 0x62 */ FD_INVALID, /* 0x63 */ FD_INVALID,
185 11529 : /* 0x64 */ FD_CHECK_SH32, /* 0x65 */ FD_CHECK_JMP, /* 0x66 */ FD_CHECK_DIV, /* 0x67 */ FD_CHECK_SH64,
186 11529 : /* 0x68 */ FD_INVALID, /* 0x69 */ FD_INVALID, /* 0x6a */ FD_INVALID, /* 0x6b */ FD_INVALID,
187 11529 : /* 0x6c */ FD_VALID, /* 0x6d */ FD_CHECK_JMP, /* 0x6e */ FD_VALID, /* 0x6f */ FD_VALID,
188 11529 : /* 0x70 */ FD_INVALID, /* 0x71 */ FD_INVALID, /* 0x72 */ FD_INVALID, /* 0x73 */ FD_INVALID,
189 11529 : /* 0x74 */ FD_CHECK_SH32, /* 0x75 */ FD_CHECK_JMP, /* 0x76 */ FD_CHECK_DIV, /* 0x77 */ FD_CHECK_SH64,
190 11529 : /* 0x78 */ FD_INVALID, /* 0x79 */ FD_INVALID, /* 0x7a */ FD_INVALID, /* 0x7b */ FD_INVALID,
191 11529 : /* 0x7c */ FD_VALID, /* 0x7d */ FD_CHECK_JMP, /* 0x7e */ FD_VALID, /* 0x7f */ FD_VALID,
192 11529 : /* 0x80 */ FD_INVALID, /* 0x81 */ FD_INVALID, /* 0x82 */ FD_INVALID, /* 0x83 */ FD_INVALID,
193 11529 : /* 0x84 */ FD_INVALID, /* 0x85 */ FD_VALID, /* 0x86 */ FD_VALID, /* 0x87 */ FD_CHECK_ST,
194 11529 : /* 0x88 */ FD_INVALID, /* 0x89 */ FD_INVALID, /* 0x8a */ FD_INVALID, /* 0x8b */ FD_INVALID,
195 11529 : /* 0x8c */ FD_VALID, /* 0x8d */ FD_CHECK_CALL_REG_SRC,/*0x8e*/FD_VALID, /* 0x8f */ FD_CHECK_ST,
196 11529 : /* 0x90 */ FD_INVALID, /* 0x91 */ FD_INVALID, /* 0x92 */ FD_INVALID, /* 0x93 */ FD_INVALID,
197 11529 : /* 0x94 */ FD_INVALID, /* 0x95 */ FD_VALID, /* 0x96 */ FD_VALID, /* 0x97 */ FD_CHECK_ST,
198 11529 : /* 0x98 */ FD_INVALID, /* 0x99 */ FD_INVALID, /* 0x9a */ FD_INVALID, /* 0x9b */ FD_INVALID,
199 11529 : /* 0x9c */ FD_VALID, /* 0x9d */ FD_INVALID, /* 0x9e */ FD_VALID, /* 0x9f */ FD_CHECK_ST,
200 11529 : /* 0xa0 */ FD_INVALID, /* 0xa1 */ FD_INVALID, /* 0xa2 */ FD_INVALID, /* 0xa3 */ FD_INVALID,
201 11529 : /* 0xa4 */ FD_VALID, /* 0xa5 */ FD_CHECK_JMP, /* 0xa6 */ FD_INVALID, /* 0xa7 */ FD_VALID,
202 11529 : /* 0xa8 */ FD_INVALID, /* 0xa9 */ FD_INVALID, /* 0xaa */ FD_INVALID, /* 0xab */ FD_INVALID,
203 11529 : /* 0xac */ FD_VALID, /* 0xad */ FD_CHECK_JMP, /* 0xae */ FD_INVALID, /* 0xaf */ FD_VALID,
204 11529 : /* 0xb0 */ FD_INVALID, /* 0xb1 */ FD_INVALID, /* 0xb2 */ FD_INVALID, /* 0xb3 */ FD_INVALID,
205 11529 : /* 0xb4 */ FD_VALID, /* 0xb5 */ FD_CHECK_JMP, /* 0xb6 */ FD_VALID, /* 0xb7 */ FD_VALID,
206 11529 : /* 0xb8 */ FD_INVALID, /* 0xb9 */ FD_INVALID, /* 0xba */ FD_INVALID, /* 0xbb */ FD_INVALID,
207 11529 : /* 0xbc */ FD_VALID, /* 0xbd */ FD_CHECK_JMP, /* 0xbe */ FD_VALID, /* 0xbf */ FD_VALID,
208 11529 : /* 0xc0 */ FD_INVALID, /* 0xc1 */ FD_INVALID, /* 0xc2 */ FD_INVALID, /* 0xc3 */ FD_INVALID,
209 11529 : /* 0xc4 */ FD_CHECK_SH32, /* 0xc5 */ FD_CHECK_JMP, /* 0xc6 */ FD_CHECK_DIV, /* 0xc7 */ FD_CHECK_SH64,
210 11529 : /* 0xc8 */ FD_INVALID, /* 0xc9 */ FD_INVALID, /* 0xca */ FD_INVALID, /* 0xcb */ FD_INVALID,
211 11529 : /* 0xcc */ FD_VALID, /* 0xcd */ FD_CHECK_JMP, /* 0xce */ FD_VALID, /* 0xcf */ FD_VALID,
212 11529 : /* 0xd0 */ FD_INVALID, /* 0xd1 */ FD_INVALID, /* 0xd2 */ FD_INVALID, /* 0xd3 */ FD_INVALID,
213 11529 : /* 0xd4 */ FD_INVALID, /* 0xd5 */ FD_CHECK_JMP, /* 0xd6 */ FD_CHECK_DIV, /* 0xd7 */ FD_INVALID,
214 11529 : /* 0xd8 */ FD_INVALID, /* 0xd9 */ FD_INVALID, /* 0xda */ FD_INVALID, /* 0xdb */ FD_INVALID,
215 11529 : /* 0xdc */ FD_CHECK_END, /* 0xdd */ FD_CHECK_JMP, /* 0xde */ FD_VALID, /* 0xdf */ FD_INVALID,
216 11529 : /* 0xe0 */ FD_INVALID, /* 0xe1 */ FD_INVALID, /* 0xe2 */ FD_INVALID, /* 0xe3 */ FD_INVALID,
217 11529 : /* 0xe4 */ FD_INVALID, /* 0xe5 */ FD_INVALID, /* 0xe6 */ FD_CHECK_DIV, /* 0xe7 */ FD_INVALID,
218 11529 : /* 0xe8 */ FD_INVALID, /* 0xe9 */ FD_INVALID, /* 0xea */ FD_INVALID, /* 0xeb */ FD_INVALID,
219 11529 : /* 0xec */ FD_INVALID, /* 0xed */ FD_INVALID, /* 0xee */ FD_VALID, /* 0xef */ FD_INVALID,
220 11529 : /* 0xf0 */ FD_INVALID, /* 0xf1 */ FD_INVALID, /* 0xf2 */ FD_INVALID, /* 0xf3 */ FD_INVALID,
221 11529 : /* 0xf4 */ FD_INVALID, /* 0xf5 */ FD_INVALID, /* 0xf6 */ FD_CHECK_DIV, /* 0xf7 */ FD_VALID,
222 11529 : /* 0xf8 */ FD_INVALID, /* 0xf9 */ FD_INVALID, /* 0xfa */ FD_INVALID, /* 0xfb */ FD_INVALID,
223 11529 : /* 0xfc */ FD_INVALID, /* 0xfd */ FD_INVALID, /* 0xfe */ FD_VALID, /* 0xff */ FD_INVALID,
224 11529 : };
225 :
226 : /* SIMD-0173: LDDW
227 : https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/verifier.rs#L232-L235 */
228 11529 : validation_map[ 0x18 ] = !FD_VM_SBPF_DISABLE_LDDW(sbpf_version) ? FD_CHECK_LDQ : FD_INVALID;
229 : /* HOR64 https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/verifier.rs#L325 */
230 11529 : validation_map[ 0xf7 ] = FD_VM_SBPF_DISABLE_LDDW(sbpf_version) ? FD_VALID : FD_INVALID;
231 :
232 : /* SIMD-0173: LE
233 : https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/verifier.rs#L285 */
234 11529 : validation_map[ 0xd4 ] = !FD_VM_SBPF_DISABLE_LE(sbpf_version) ? FD_CHECK_END : FD_INVALID;
235 :
236 : /* SIMD-0173: LDXW, STW, STXW */
237 11529 : validation_map[ 0x61 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_VALID;
238 11529 : validation_map[ 0x62 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_CHECK_ST;
239 11529 : validation_map[ 0x63 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_CHECK_ST;
240 11529 : validation_map[ 0x8c ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_VALID : FD_INVALID;
241 11529 : validation_map[ 0x87 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST : FD_VALID; /* VALID because it's NEG64 */
242 11529 : validation_map[ 0x8f ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST : FD_INVALID;
243 :
244 : /* SIMD-0173: LDXH, STH, STXH */
245 11529 : validation_map[ 0x69 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_VALID;
246 11529 : validation_map[ 0x6a ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_CHECK_ST;
247 11529 : validation_map[ 0x6b ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_CHECK_ST;
248 11529 : validation_map[ 0x3c ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_VALID : FD_VALID;
249 11529 : validation_map[ 0x37 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST : FD_CHECK_DIV;
250 11529 : validation_map[ 0x3f ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST : FD_VALID;
251 :
252 : /* SIMD-0173: LDXB, STB, STXB */
253 11529 : validation_map[ 0x71 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_VALID;
254 11529 : validation_map[ 0x72 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_CHECK_ST;
255 11529 : validation_map[ 0x73 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_CHECK_ST;
256 11529 : validation_map[ 0x2c ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_VALID : FD_VALID;
257 11529 : validation_map[ 0x27 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST : FD_VALID;
258 11529 : validation_map[ 0x2f ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST : FD_VALID;
259 :
260 : /* SIMD-0173: LDXDW, STDW, STXDW */
261 11529 : validation_map[ 0x79 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_VALID;
262 11529 : validation_map[ 0x7a ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_CHECK_ST;
263 11529 : validation_map[ 0x7b ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID : FD_CHECK_ST;
264 11529 : validation_map[ 0x9c ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_VALID : FD_VALID;
265 11529 : validation_map[ 0x97 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST : FD_CHECK_DIV;
266 11529 : validation_map[ 0x9f ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST : FD_VALID;
267 :
268 : /* SIMD-0173 / SIMD-0377: CALLX references valid register numbers
269 : https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/verifier.rs#L198-L214 */
270 11529 : validation_map[ 0x8d ] = FD_VM_SBPF_CALLX_USES_SRC_REG(sbpf_version) ? FD_CHECK_CALL_REG_SRC
271 11529 : : FD_VM_SBPF_CALLX_USES_DST_REG(sbpf_version) ? FD_CHECK_CALL_REG_DST
272 7194 : : FD_CHECK_CALL_REG_IMM;
273 :
274 : /* SIMD-0174: MUL, DIV, MOD */
275 11529 : validation_map[ 0x24 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_INVALID : FD_VALID;
276 11529 : validation_map[ 0x34 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_INVALID : FD_CHECK_DIV;
277 11529 : validation_map[ 0x94 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_INVALID : FD_CHECK_DIV;
278 : /* note: 0x?c, 0x?7, 0x?f should not be overwritten because they're now load/store ix */
279 :
280 : /* SIMD-0174: NEG
281 : https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/verifier.rs#L274 */
282 11529 : validation_map[ 0x84 ] = !FD_VM_SBPF_DISABLE_NEG(sbpf_version) ? FD_VALID : FD_INVALID;
283 : /* note: 0x87 should not be overwritten because it was NEG64 and it becomes STW */
284 :
285 : /* SIMD-0174: MUL, DIV, MOD */
286 11529 : validation_map[ 0x36 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID; /* UHMUL64 */
287 11529 : validation_map[ 0x3e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
288 11529 : validation_map[ 0x46 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* UDIV32 */
289 11529 : validation_map[ 0x4e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
290 11529 : validation_map[ 0x56 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* UDIV64 */
291 11529 : validation_map[ 0x5e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
292 11529 : validation_map[ 0x66 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* UREM32 */
293 11529 : validation_map[ 0x6e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
294 11529 : validation_map[ 0x76 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* UREM64 */
295 11529 : validation_map[ 0x7e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
296 11529 : validation_map[ 0x86 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID; /* LMUL32 */
297 11529 : validation_map[ 0x8e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
298 11529 : validation_map[ 0x96 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID; /* LMUL64 */
299 11529 : validation_map[ 0x9e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
300 11529 : validation_map[ 0xb6 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID; /* SHMUL64 */
301 11529 : validation_map[ 0xbe ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
302 11529 : validation_map[ 0xc6 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* SDIV32 */
303 11529 : validation_map[ 0xce ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
304 11529 : validation_map[ 0xd6 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* SDIV64 */
305 11529 : validation_map[ 0xde ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
306 11529 : validation_map[ 0xe6 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* SREM32 */
307 11529 : validation_map[ 0xee ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
308 11529 : validation_map[ 0xf6 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* SREM64 */
309 11529 : validation_map[ 0xfe ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID : FD_INVALID;
310 :
311 : /* SIMD-0377: JMP32
312 : https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/verifier.rs#L354-L375
313 :
314 : Note that these override some opcodes that conflict with PQR, so
315 : these must come AFTER PQR. */
316 11529 : if( FD_VM_SBPF_ENABLE_JMP32( sbpf_version ) ) {
317 639 : validation_map[ 0x16 ] = FD_CHECK_JMP; /* JEQ32_IMM */
318 639 : validation_map[ 0x1e ] = FD_CHECK_JMP; /* JEQ32_REG */
319 639 : validation_map[ 0x26 ] = FD_CHECK_JMP; /* JGT32_IMM */
320 639 : validation_map[ 0x2e ] = FD_CHECK_JMP; /* JGT32_REG */
321 639 : validation_map[ 0x36 ] = FD_CHECK_JMP; /* JGE32_IMM */
322 639 : validation_map[ 0x3e ] = FD_CHECK_JMP; /* JGE32_REG */
323 639 : validation_map[ 0x46 ] = FD_CHECK_JMP; /* JSET32_IMM */
324 639 : validation_map[ 0x4e ] = FD_CHECK_JMP; /* JSET32_REG */
325 639 : validation_map[ 0x56 ] = FD_CHECK_JMP; /* JNE32_IMM */
326 639 : validation_map[ 0x5e ] = FD_CHECK_JMP; /* JNE32_REG */
327 639 : validation_map[ 0x66 ] = FD_CHECK_JMP; /* JSGT32_IMM */
328 639 : validation_map[ 0x6e ] = FD_CHECK_JMP; /* JSGT32_REG */
329 639 : validation_map[ 0x76 ] = FD_CHECK_JMP; /* JSGE32_IMM */
330 639 : validation_map[ 0x7e ] = FD_CHECK_JMP; /* JSGE32_REG */
331 639 : validation_map[ 0xa6 ] = FD_CHECK_JMP; /* JLT32_IMM */
332 639 : validation_map[ 0xae ] = FD_CHECK_JMP; /* JLT32_REG */
333 639 : validation_map[ 0xb6 ] = FD_CHECK_JMP; /* JLE32_IMM */
334 639 : validation_map[ 0xbe ] = FD_CHECK_JMP; /* JLE32_REG */
335 639 : validation_map[ 0xc6 ] = FD_CHECK_JMP; /* JSLT32_IMM */
336 639 : validation_map[ 0xce ] = FD_CHECK_JMP; /* JSLT32_REG */
337 639 : validation_map[ 0xd6 ] = FD_CHECK_JMP; /* JSLE32_IMM */
338 639 : validation_map[ 0xde ] = FD_CHECK_JMP; /* JSLE32_REG */
339 639 : }
340 :
341 : /* FIXME: These checks are not necessary assuming fd_vm_t is populated by metadata
342 : generated in fd_sbpf_elf_peek (which performs these checks). But there is no guarantee, and
343 : this non-guarantee is (rightfully) exploited by the fuzz harnesses.
344 : Agave doesn't perform these checks explicitly due to Rust's guarantees */
345 11529 : if( FD_UNLIKELY( vm->text_sz / 8UL != vm->text_cnt ||
346 11529 : (const uchar *)vm->text < vm->rodata ||
347 11529 : (ulong)vm->text > (ulong)vm->text + vm->text_sz || /* Overflow chk */
348 11529 : (const uchar *)vm->text + vm->text_sz > vm->rodata + vm->rodata_sz +
349 11529 : ( FD_VM_SBPF_ENABLE_STRICTER_ELF_HEADERS( sbpf_version ) ? vm->text_sz : 0UL ) ) )
350 0 : return FD_VM_ERR_BAD_TEXT;
351 :
352 11529 : 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 */
353 0 : return FD_VM_TEXT_SZ_UNALIGNED;
354 :
355 11529 : if ( FD_UNLIKELY( vm->text_cnt == 0UL ) ) /* https://github.com/solana-labs/rbpf/blob/v0.8.0/src/verifier.rs#L112 */
356 0 : return FD_VM_ERR_EMPTY;
357 :
358 11529 : ulong const * text = vm->text;
359 11529 : ulong text_cnt = vm->text_cnt;
360 :
361 806093244 : for( ulong i=0UL; i<text_cnt; i++ ) {
362 806084481 : fd_sbpf_instr_t instr = fd_sbpf_instr( text[i] );
363 :
364 806084481 : uchar validation_code = validation_map[ instr.opcode.raw ];
365 806084481 : switch( validation_code ) {
366 :
367 644833329 : case FD_VALID: break;
368 :
369 : /* Store ops are special because they allow dreg==r10.
370 : We use a special validation_code, used later in the
371 : "Check registers" section.
372 : But there's nothing to do at this time. */
373 57654 : case FD_CHECK_ST: break;
374 :
375 77403 : case FD_CHECK_JMP: {
376 77403 : long jmp_dst = (long)i + (long)instr.offset + 1L;
377 77403 : if( FD_UNLIKELY( (jmp_dst<0) | (jmp_dst>=(long)text_cnt) ) ) return FD_VM_ERR_JMP_OUT_OF_BOUNDS;
378 : //FIXME: this shouldn't be here?
379 77256 : if( FD_UNLIKELY( fd_sbpf_instr( text[ jmp_dst ] ).opcode.raw==FD_SBPF_OP_ADDL_IMM ) ) return FD_VM_ERR_JMP_TO_ADDL_IMM;
380 77256 : break;
381 77256 : }
382 :
383 77256 : case FD_CHECK_END: {
384 129 : if( FD_UNLIKELY( !((instr.imm==16) | (instr.imm==32) | (instr.imm==64)) ) ) return FD_VM_ERR_INVALID_END_IMM;
385 111 : break;
386 129 : }
387 :
388 : /* https://github.com/solana-labs/rbpf/blob/b503a1867a9cfa13f93b4d99679a17fe219831de/src/verifier.rs#L244 */
389 43920 : case FD_CHECK_LDQ: {
390 : /* https://github.com/solana-labs/rbpf/blob/b503a1867a9cfa13f93b4d99679a17fe219831de/src/verifier.rs#L131 */
391 43920 : if( FD_UNLIKELY( (i+1UL)>=text_cnt ) ) return FD_VM_ERR_INCOMPLETE_LDQ;
392 :
393 : /* https://github.com/solana-labs/rbpf/blob/b503a1867a9cfa13f93b4d99679a17fe219831de/src/verifier.rs#L137-L139 */
394 43920 : fd_sbpf_instr_t addl_imm = fd_sbpf_instr( text[ i+1UL ] );
395 43920 : if( FD_UNLIKELY( addl_imm.opcode.raw!=FD_SBPF_OP_ADDL_IMM ) ) return FD_VM_ERR_LDQ_NO_ADDL_IMM;
396 :
397 : /* FIXME: SET A BIT MAP HERE OF ADDL_IMM TO DENOTE * AS FORBIDDEN
398 : BRANCH TARGETS OF CALL_REG?? */
399 :
400 43920 : i++; /* Skip the addl imm */
401 43920 : break;
402 43920 : }
403 :
404 64407444 : case FD_CHECK_DIV: {
405 64407444 : if( FD_UNLIKELY( instr.imm==0 ) ) return FD_VM_ERR_SIGFPE;
406 64407384 : break;
407 64407444 : }
408 :
409 64407384 : case FD_CHECK_SH32: {
410 48308418 : if( FD_UNLIKELY( instr.imm>=32 ) ) return FD_VM_SH_OVERFLOW;
411 48308328 : break;
412 48308418 : }
413 :
414 48347829 : case FD_CHECK_SH64: {
415 48347829 : if( FD_UNLIKELY( instr.imm>=64 ) ) return FD_VM_SH_OVERFLOW;
416 48347721 : break;
417 48347829 : }
418 :
419 : /* https://github.com/anza-xyz/sbpf/blob/v0.11.1/src/verifier.rs#L220 */
420 48347721 : case FD_CHECK_CALL_REG_SRC: {
421 21 : if( FD_UNLIKELY( instr.src_reg > 9 ) ) {
422 9 : return FD_VM_ERR_INVALID_REG;
423 9 : }
424 12 : break;
425 21 : }
426 7143 : case FD_CHECK_CALL_REG_IMM: {
427 7143 : if( FD_UNLIKELY( instr.imm > 9 ) ) {
428 9 : return FD_VM_ERR_INVALID_REG;
429 9 : }
430 7134 : break;
431 7143 : }
432 : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/verifier.rs#L205-L206 */
433 7134 : case FD_CHECK_CALL_REG_DST: {
434 9 : if( FD_UNLIKELY( instr.dst_reg > 9 ) ) {
435 3 : return FD_VM_ERR_INVALID_REG;
436 3 : }
437 6 : break;
438 9 : }
439 :
440 1182 : case FD_INVALID: default: return FD_VM_ERR_INVALID_OPCODE;
441 806084481 : }
442 :
443 : /* Check registers
444 : https://github.com/solana-labs/rbpf/blob/v0.8.5/src/verifier.rs#L177 */
445 :
446 : /* Source register */
447 806082855 : if( FD_UNLIKELY( instr.src_reg>10 ) ) return FD_VM_ERR_INVALID_SRC_REG;
448 :
449 : /* Special R10 register allowed for ADD64_IMM */
450 806082387 : if( instr.dst_reg==10U
451 806082387 : && FD_VM_SBPF_MANUAL_STACK_FRAME_BUMP( sbpf_version )
452 806082387 : && instr.opcode.raw == 0x07
453 806082387 : && ( instr.imm % FD_VM_SBPF_DYNAMIC_STACK_FRAMES_ALIGN )==0 )
454 9 : continue;
455 :
456 : /* Destination register. */
457 806082378 : if( FD_UNLIKELY( instr.dst_reg==10U && validation_code != FD_CHECK_ST ) ) return FD_VM_ERR_INVALID_DST_REG;
458 806081919 : if( FD_UNLIKELY( instr.dst_reg > 10U ) ) return FD_VM_ERR_INVALID_DST_REG;
459 806081919 : }
460 :
461 8763 : return FD_VM_SUCCESS;
462 11529 : }
463 :
464 : FD_FN_CONST ulong
465 11364 : fd_vm_align( void ) {
466 11364 : return FD_VM_ALIGN;
467 11364 : }
468 :
469 : FD_FN_CONST ulong
470 5703 : fd_vm_footprint( void ) {
471 5703 : return FD_VM_FOOTPRINT;
472 5703 : }
473 :
474 : void *
475 5595 : fd_vm_new( void * shmem ) {
476 :
477 5595 : if( FD_UNLIKELY( !shmem ) ) {
478 0 : FD_LOG_WARNING(( "NULL shmem" ));
479 0 : return NULL;
480 0 : }
481 :
482 5595 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_vm_align() ) ) ) {
483 0 : FD_LOG_WARNING(( "misaligned shmem" ));
484 0 : return NULL;
485 0 : }
486 :
487 5595 : fd_vm_t * vm = (fd_vm_t *)shmem;
488 5595 : fd_memset( vm, 0, fd_vm_footprint() );
489 :
490 5595 : FD_COMPILER_MFENCE();
491 5595 : FD_VOLATILE( vm->magic ) = FD_VM_MAGIC;
492 5595 : FD_COMPILER_MFENCE();
493 :
494 5595 : return shmem;
495 5595 : }
496 :
497 : fd_vm_t *
498 5595 : fd_vm_join( void * shmem ) {
499 :
500 5595 : if( FD_UNLIKELY( !shmem ) ) {
501 0 : FD_LOG_WARNING(( "NULL shmem" ));
502 0 : return NULL;
503 0 : }
504 :
505 5595 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_vm_align() ) ) ) {
506 0 : FD_LOG_WARNING(( "misaligned shmem" ));
507 0 : return NULL;
508 0 : }
509 :
510 5595 : fd_vm_t * vm = (fd_vm_t *)shmem;
511 :
512 5595 : if( FD_UNLIKELY( vm->magic!=FD_VM_MAGIC ) ) {
513 0 : FD_LOG_WARNING(( "bad magic" ));
514 0 : return NULL;
515 0 : }
516 :
517 5595 : return vm;
518 5595 : }
519 :
520 : void *
521 66 : fd_vm_leave( fd_vm_t * vm ) {
522 :
523 66 : if( FD_UNLIKELY( !vm ) ) {
524 0 : FD_LOG_WARNING(( "NULL vm" ));
525 0 : return NULL;
526 0 : }
527 :
528 66 : return (void *)vm;
529 66 : }
530 :
531 : void *
532 66 : fd_vm_delete( void * shmem ) {
533 :
534 66 : if( FD_UNLIKELY( !shmem ) ) {
535 0 : FD_LOG_WARNING(( "NULL shmem" ));
536 0 : return NULL;
537 0 : }
538 :
539 66 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_vm_align() ) ) ) {
540 0 : FD_LOG_WARNING(( "misaligned shmem" ));
541 0 : return NULL;
542 0 : }
543 :
544 66 : fd_vm_t * vm = (fd_vm_t *)shmem;
545 :
546 66 : if( FD_UNLIKELY( vm->magic!=FD_VM_MAGIC ) ) {
547 0 : FD_LOG_WARNING(( "bad magic" ));
548 0 : return NULL;
549 0 : }
550 :
551 66 : FD_COMPILER_MFENCE();
552 66 : FD_VOLATILE( vm->magic ) = 0UL;
553 66 : FD_COMPILER_MFENCE();
554 :
555 66 : return (void *)vm;
556 66 : }
557 :
558 : fd_vm_t *
559 : fd_vm_init(
560 : fd_vm_t * vm,
561 : fd_exec_instr_ctx_t * instr_ctx,
562 : ulong heap_max,
563 : ulong entry_cu,
564 : uchar const * rodata,
565 : ulong rodata_sz,
566 : ulong const * text,
567 : ulong text_cnt,
568 : ulong text_off,
569 : ulong text_sz,
570 : ulong entry_pc,
571 : ulong const * calldests,
572 : ulong sbpf_version,
573 : fd_sbpf_syscalls_t * syscalls,
574 : fd_vm_trace_t * trace,
575 : fd_sha256_t * sha,
576 : fd_vm_input_region_t * mem_regions,
577 : uint mem_regions_cnt,
578 : fd_vm_acc_region_meta_t * acc_region_metas,
579 : uchar is_deprecated,
580 : int direct_mapping,
581 : int syscall_parameter_address_restrictions,
582 : int virtual_address_space_adjustments,
583 : int dump_syscall_to_pb,
584 17262 : ulong r2_initial_value ) {
585 :
586 17262 : if ( FD_UNLIKELY( vm == NULL ) ) {
587 0 : FD_LOG_WARNING(( "NULL vm" ));
588 0 : return NULL;
589 0 : }
590 :
591 17262 : if ( FD_UNLIKELY( vm->magic != FD_VM_MAGIC ) ) {
592 0 : FD_LOG_WARNING(( "bad magic" ));
593 0 : return NULL;
594 0 : }
595 :
596 17262 : if ( FD_UNLIKELY( heap_max > FD_VM_HEAP_MAX ) ) {
597 0 : FD_LOG_WARNING(( "heap_max > FD_VM_HEAP_MAX" ));
598 0 : return NULL;
599 0 : }
600 :
601 : /* We do support calldests==NULL for tests that do not require
602 : program execution, e.g. just testing some interpreter functionality
603 : or syscalls.
604 : SBPF v3+ no longer needs calldests, so we enforce it to be NULL. */
605 17262 : if( FD_UNLIKELY( calldests && FD_VM_SBPF_ENABLE_STRICTER_ELF_HEADERS( sbpf_version ) ) ) {
606 0 : return NULL;
607 0 : }
608 :
609 : // Set the vm fields
610 17262 : vm->instr_ctx = instr_ctx;
611 17262 : vm->heap_max = heap_max;
612 17262 : vm->entry_cu = entry_cu;
613 17262 : vm->rodata = rodata;
614 17262 : vm->rodata_sz = rodata_sz;
615 17262 : vm->text = text;
616 17262 : vm->text_cnt = text_cnt;
617 : /* In SBPF V3, bytecode starts at vaddr 0x100000000 exactly, so
618 : text_off from the POV of the VM is 0.
619 : https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/interpreter.rs#L539 */
620 17262 : vm->text_off = FD_VM_SBPF_ENABLE_LOWER_RODATA_VADDR( sbpf_version ) ? 0UL : text_off;
621 17262 : vm->text_sz = text_sz;
622 17262 : vm->entry_pc = entry_pc;
623 17262 : vm->calldests = calldests;
624 17262 : vm->sbpf_version = sbpf_version;
625 17262 : vm->syscalls = syscalls;
626 17262 : vm->trace = trace;
627 17262 : vm->sha = sha;
628 17262 : vm->input_mem_regions = mem_regions;
629 17262 : vm->input_mem_regions_cnt = mem_regions_cnt;
630 17262 : vm->acc_region_metas = acc_region_metas;
631 17262 : vm->is_deprecated = is_deprecated;
632 17262 : vm->direct_mapping = direct_mapping;
633 17262 : vm->syscall_parameter_address_restrictions = syscall_parameter_address_restrictions;
634 17262 : vm->virtual_address_space_adjustments = virtual_address_space_adjustments;
635 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/vm.rs#L99-L103 */
636 17262 : if( FD_UNLIKELY( FD_VM_SBPF_STACK_FRAME_GAPS( sbpf_version ) && !virtual_address_space_adjustments ) ) {
637 8274 : vm->stack_frame_sz = FD_VM_STACK_FRAME_SZ;
638 8274 : vm->stack_push_frame_count = 2UL;
639 8988 : } else if ( FD_VM_SBPF_MANUAL_STACK_FRAME_BUMP( sbpf_version ) ) {
640 4341 : vm->stack_frame_sz = 0UL;
641 4341 : vm->stack_push_frame_count = 0UL;
642 4647 : } else {
643 4647 : vm->stack_frame_sz = FD_VM_STACK_FRAME_SZ;
644 4647 : vm->stack_push_frame_count = 1UL;
645 4647 : }
646 :
647 17262 : vm->segv_vaddr = ULONG_MAX;
648 17262 : vm->segv_access_len = 0UL;
649 17262 : vm->segv_access_type = 0;
650 17262 : vm->dump_syscall_to_pb = dump_syscall_to_pb;
651 :
652 : /* Unpack input and rodata */
653 17262 : fd_vm_mem_cfg( vm );
654 :
655 : /* Initialize registers */
656 : /* FIXME: Zero out shadow, stack and heap here? */
657 17262 : fd_memset( vm->reg, 0, FD_VM_REG_MAX * sizeof(ulong) );
658 17262 : vm->reg[1] = FD_VM_MEM_MAP_INPUT_REGION_START;
659 17262 : vm->reg[2] = r2_initial_value;
660 : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/vm.rs#L325-L330 */
661 17262 : vm->reg[10] = FD_VM_MEM_MAP_STACK_REGION_START +
662 17262 : ( FD_VM_SBPF_MANUAL_STACK_FRAME_BUMP( vm->sbpf_version ) ? FD_VM_STACK_MAX : vm->stack_frame_sz );
663 : /* Note: Agave uses r11 as pc, we don't */
664 :
665 : /* Set execution state */
666 17262 : vm->pc = vm->entry_pc;
667 17262 : vm->ic = 0UL;
668 17262 : vm->cu = vm->entry_cu;
669 17262 : vm->frame_cnt = 0UL;
670 :
671 17262 : vm->heap_sz = 0UL;
672 :
673 : /* Do NOT reset logs */
674 :
675 17262 : return vm;
676 17262 : }
|