LCOV - code coverage report
Current view: top level - flamenco/vm - fd_vm.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 210 296 70.9 %
Date: 2024-11-13 11:58:15 Functions: 12 12 100.0 %

          Line data    Source code
       1             : #include "fd_vm_private.h"
       2             : #include "../runtime/context/fd_exec_epoch_ctx.h"
       3             : #include "../runtime/context/fd_exec_slot_ctx.h"
       4             : #include "../features/fd_features.h"
       5             : 
       6             : /* fd_vm_syscall_strerror() returns the error message corresponding to err,
       7             :    intended to be logged by log_collector, or an empty string if the error code
       8             :    should be omitted in logs for whatever reason.  Omitted examples are success,
       9             :    panic (logged in place)...
      10             :    See also fd_log_collector_program_failure(). */
      11             : char const *
      12         183 : fd_vm_syscall_strerror( int err ) {
      13             : 
      14         183 :   switch( err ) {
      15             : 
      16           6 :   case FD_VM_ERR_SYSCALL_INVALID_STRING:                         return "invalid utf-8 sequence"; // truncated
      17           9 :   case FD_VM_ERR_SYSCALL_ABORT:                                  return "SBF program panicked";
      18          24 :   case FD_VM_ERR_SYSCALL_PANIC:                                  return "SBF program Panicked in..."; // truncated
      19           0 :   case FD_VM_ERR_SYSCALL_INVOKE_CONTEXT_BORROW_FAILED:           return "Cannot borrow invoke context";
      20           0 :   case FD_VM_ERR_SYSCALL_MALFORMED_SIGNER_SEED:                  return "Malformed signer seed"; // truncated
      21           3 :   case FD_VM_ERR_SYSCALL_BAD_SEEDS:                              return "Could not create program address with signer seeds"; // truncated
      22           0 :   case FD_VM_ERR_SYSCALL_PROGRAM_NOT_SUPPORTED:                  return "Program not supported by inner instructions"; // truncated
      23          24 :   case FD_VM_ERR_SYSCALL_UNALIGNED_POINTER:                      return "Unaligned pointer";
      24           0 :   case FD_VM_ERR_SYSCALL_TOO_MANY_SIGNERS:                       return "Too many signers";
      25           0 :   case FD_VM_ERR_SYSCALL_INSTRUCTION_TOO_LARGE:                  return "Instruction passed to inner instruction is too large"; // truncated
      26           0 :   case FD_VM_ERR_SYSCALL_TOO_MANY_ACCOUNTS:                      return "Too many accounts passed to inner instruction";
      27          57 :   case FD_VM_ERR_SYSCALL_COPY_OVERLAPPING:                       return "Overlapping copy";
      28           0 :   case FD_VM_ERR_SYSCALL_RETURN_DATA_TOO_LARGE:                  return "Return data too large"; // truncated
      29           9 :   case FD_VM_ERR_SYSCALL_TOO_MANY_SLICES:                        return "Hashing too many sequences";
      30          21 :   case FD_VM_ERR_SYSCALL_INVALID_LENGTH:                         return "InvalidLength";
      31           0 :   case FD_VM_ERR_SYSCALL_MAX_INSTRUCTION_DATA_LEN_EXCEEDED:      return "Invoked an instruction with data that is too large"; // truncated
      32           0 :   case FD_VM_ERR_SYSCALL_MAX_INSTRUCTION_ACCOUNTS_EXCEEDED:      return "Invoked an instruction with too many accounts"; // truncated
      33           0 :   case FD_VM_ERR_SYSCALL_MAX_INSTRUCTION_ACCOUNT_INFOS_EXCEEDED: return "Invoked an instruction with too many account info's"; // truncated
      34          24 :   case FD_VM_ERR_SYSCALL_INVALID_ATTRIBUTE:                      return "InvalidAttribute";
      35           0 :   case FD_VM_ERR_SYSCALL_INVALID_POINTER:                        return "Invalid pointer";
      36           0 :   case FD_VM_ERR_SYSCALL_ARITHMETIC_OVERFLOW:                    return "Arithmetic overflow";
      37             : 
      38           3 :   case FD_VM_ERR_SYSCALL_POSEIDON_INVALID_PARAMS:                return "Syscall error: Invalid parameters.";
      39           3 :   case FD_VM_ERR_SYSCALL_POSEIDON_INVALID_ENDIANNESS:            return "Syscall error: Invalid endianness.";
      40             : 
      41           0 :   default: break;
      42         183 :   }
      43             : 
      44           0 :   return "";
      45         183 : }
      46             : 
      47             : /* fd_vm_ebpf_strerror() returns the error message corresponding to err,
      48             :    intended to be logged by log_collector, or an empty string if the error code
      49             :    should be omitted in logs for whatever reason.
      50             :    See also fd_log_collector_program_failure(). */
      51             : char const *
      52         774 : fd_vm_ebpf_strerror( int err ) {
      53             : 
      54         774 :   switch( err ) {
      55             : 
      56           0 :   case FD_VM_ERR_EBPF_ELF_ERROR:                   return "ELF error"; // truncated
      57           0 :   case FD_VM_ERR_EBPF_FUNCTION_ALREADY_REGISTERED: return "function was already registered"; // truncated
      58           0 :   case FD_VM_ERR_EBPF_CALL_DEPTH_EXCEEDED:         return "exceeded max BPF to BPF call depth";
      59           0 :   case FD_VM_ERR_EBPF_EXIT_ROOT_CALL_FRAME:        return "attempted to exit root call frame";
      60           0 :   case FD_VM_ERR_EBPF_DIVIDE_BY_ZERO:              return "divide by zero at BPF instruction";
      61           0 :   case FD_VM_ERR_EBPF_DIVIDE_OVERFLOW:             return "division overflow at BPF instruction";
      62           0 :   case FD_VM_ERR_EBPF_EXECUTION_OVERRUN:           return "attempted to execute past the end of the text segment at BPF instruction";
      63           0 :   case FD_VM_ERR_EBPF_CALL_OUTSIDE_TEXT_SEGMENT:   return "callx attempted to call outside of the text segment";
      64           0 :   case FD_VM_ERR_EBPF_EXCEEDED_MAX_INSTRUCTIONS:   return "exceeded CUs meter at BPF instruction";
      65           0 :   case FD_VM_ERR_EBPF_JIT_NOT_COMPILED:            return "program has not been JIT-compiled";
      66           0 :   case FD_VM_ERR_EBPF_INVALID_VIRTUAL_ADDRESS:     return "invalid virtual address"; // truncated
      67           0 :   case FD_VM_ERR_EBPF_INVALID_MEMORY_REGION:       return "Invalid memory region at index"; // truncated
      68         774 :   case FD_VM_ERR_EBPF_ACCESS_VIOLATION:            return "Access violation"; // truncated
      69           0 :   case FD_VM_ERR_EBPF_STACK_ACCESS_VIOLATION:      return "Access violation in stack frame"; // truncated
      70           0 :   case FD_VM_ERR_EBPF_INVALID_INSTRUCTION:         return "invalid BPF instruction";
      71           0 :   case FD_VM_ERR_EBPF_UNSUPPORTED_INSTRUCTION:     return "unsupported BPF instruction";
      72           0 :   case FD_VM_ERR_EBPF_EXHAUSTED_TEXT_SEGMENT:      return "Compilation exhausted text segment at BPF instruction"; // truncated
      73           0 :   case FD_VM_ERR_EBPF_LIBC_INVOCATION_FAILED:      return "Libc calling returned error code"; // truncated
      74           0 :   case FD_VM_ERR_EBPF_VERIFIER_ERROR:              return "Verifier error"; // truncated
      75           0 :   case FD_VM_ERR_EBPF_SYSCALL_ERROR:               return ""; // handled explicitly via fd_vm_syscall_strerror()
      76             : 
      77           0 :   default: break;
      78         774 :   }
      79             : 
      80           0 :   return "";
      81         774 : }
      82             : 
      83             : /* fd_vm_strerror() returns the error message corresponding to err, used internally
      84             :    for system logs, NOT for log_collector / transaction logs. */
      85             : char const *
      86          99 : fd_vm_strerror( int err ) {
      87             : 
      88          99 :   switch( err ) {
      89             : 
      90             :   /* "Standard" Firedancer error codes */
      91             : 
      92           3 :   case FD_VM_SUCCESS:   return "SUCCESS success";
      93           3 :   case FD_VM_ERR_INVAL: return "INVAL invalid request";
      94           3 :   case FD_VM_ERR_UNSUP: return "UNSUP unsupported request";
      95           3 :   case FD_VM_ERR_PERM:  return "PERM unauthorized request";
      96           3 :   case FD_VM_ERR_FULL:  return "FULL storage full";
      97           3 :   case FD_VM_ERR_EMPTY: return "EMPTY nothing to do";
      98           3 :   case FD_VM_ERR_IO:    return "IO input-output error";
      99           3 :   case FD_VM_ERR_AGAIN: return "AGAIN try again later";
     100             : 
     101             :   /* VM exec error codes */
     102             : 
     103           3 :   case FD_VM_ERR_SIGTEXT:   return "SIGTEXT illegal program counter";
     104           3 :   case FD_VM_ERR_SIGSPLIT:  return "SIGSPLIT split multiword instruction";
     105           3 :   case FD_VM_ERR_SIGCALL:   return "unsupported BPF instruction";
     106           3 :   case FD_VM_ERR_SIGSTACK:  return "SIGSTACK call depth limit exceeded";
     107           3 :   case FD_VM_ERR_SIGILL:    return "SIGILL illegal instruction";
     108           3 :   case FD_VM_ERR_SIGSEGV:   return "SIGSEGV illegal memory address";
     109           3 :   case FD_VM_ERR_SIGBUS:    return "SIGBUS misaligned memory address";
     110           3 :   case FD_VM_ERR_SIGRDONLY: return "SIGRDONLY illegal write";
     111           3 :   case FD_VM_ERR_SIGCOST:   return "SIGCOST compute unit limit exceeded";
     112           0 :   case FD_VM_ERR_SIGFPE:    return "SIGFPE division by zero";
     113             : 
     114             :   /* VM syscall error codes */
     115             :   /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/mod.rs#L81 */
     116             : 
     117           3 :   case FD_VM_ERR_ABORT:                        return "SBF program panicked";
     118           3 :   case FD_VM_ERR_PANIC:                        return "PANIC";                        /* FIXME: description */
     119           3 :   case FD_VM_ERR_MEM_OVERLAP:                  return "MEM_OVERLAP";                  /* FIXME: description */
     120           3 :   case FD_VM_ERR_INSTR_ERR:                    return "INSTR_ERR";                    /* FIXME: description */
     121           3 :   case FD_VM_ERR_RETURN_DATA_TOO_LARGE:        return "RETURN_DATA_TOO_LARGE";        /* FIXME: description */
     122           3 :   case FD_VM_ERR_INVOKE_CONTEXT_BORROW_FAILED: return "INVOKE_CONTEXT_BORROW_FAILED"; /* FIXME: description */
     123             : 
     124             :   /* VM validate error codes */
     125             : 
     126           3 :   case FD_VM_ERR_INVALID_OPCODE:    return "INVALID_OPCODE detected an invalid opcode";
     127           3 :   case FD_VM_ERR_INVALID_SRC_REG:   return "INVALID_SRC_REG detected an invalid source register";
     128           3 :   case FD_VM_ERR_INVALID_DST_REG:   return "INVALID_DST_REG detected an invalid destination register";
     129           3 :   case FD_VM_ERR_INF_LOOP:          return "INF_LOOP detected an infinite loop";
     130           3 :   case FD_VM_ERR_JMP_OUT_OF_BOUNDS: return "JMP_OUT_OF_BOUNDS detected an out of bounds jump";
     131           3 :   case FD_VM_ERR_JMP_TO_ADDL_IMM:   return "JMP_TO_ADDL_IMM detected a jump to an addl imm";
     132           3 :   case FD_VM_ERR_INVALID_END_IMM:   return "INVALID_END_IMM detected an invalid immediate for an endianness conversion instruction";
     133           3 :   case FD_VM_ERR_INCOMPLETE_LDQ:    return "INCOMPLETE_LDQ detected an incomplete ldq at program end";
     134           3 :   case FD_VM_ERR_LDQ_NO_ADDL_IMM:   return "LDQ_NO_ADDL_IMM detected a ldq without an addl imm following it";
     135           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";
     136           0 :   case FD_VM_ERR_INVALID_REG:       return "INVALID_REG detected an invalid register number in a callx instruction";
     137           0 :   case FD_VM_ERR_BAD_TEXT:          return "BAD_TEXT detected a bad text section";
     138           0 :   case FD_VM_SH_OVERFLOW:           return "SH_OVERFLOW detected a shift overflow in an instruction";
     139           0 :   case FD_VM_TEXT_SZ_UNALIGNED:     return "TEXT_SZ_UNALIGNED detected an unaligned text section size (not a multiple of 8)";
     140             : 
     141           0 :   default: break;
     142          99 :   }
     143             : 
     144           0 :   return "UNKNOWN probably not a FD_VM_ERR code";
     145          99 : }
     146             : 
     147             : /* FIXME: add a pedantic version of this validation that does things
     148             :    like:
     149             :   - only 0 imms when the instruction does not use an imm
     150             :   - same as above but for src/dst reg, offset */
     151             : /* FIXME: HANDLING OF LDQ ON NEWER SBPF VERSUS OLDER SBPF (AND WITH CALL
     152             :    REG) */
     153             : /* FIXME: LINK TO SOLANA CODE VALIDATE AND DOUBLE CHECK THIS BEHAVES
     154             :    IDENTICALLY! */
     155             : 
     156             : int
     157        6651 : fd_vm_validate( fd_vm_t const * vm ) {
     158             : 
     159             :   /* A mapping of all the possible 1-byte sBPF opcodes to their
     160             :      validation criteria. */
     161             : 
     162   673603557 : # define FD_VALID       ((uchar)0) /* Valid opcode */
     163     5251095 : # define FD_CHECK_JMP   ((uchar)1) /* Validation should check that the instruction is a valid jump */
     164       14805 : # define FD_CHECK_END   ((uchar)2) /* Validation should check that the instruction is a valid endianness conversion */
     165   856138323 : # define FD_CHECK_ST    ((uchar)3) /* Validation should check that the instruction is a valid store */
     166     1355256 : # define FD_CHECK_LDQ   ((uchar)4) /* Validation should check that the instruction is a valid load-quad */
     167    64473162 : # define FD_CHECK_DIV   ((uchar)5) /* Validation should check that the instruction is a valid division by immediate */
     168    48328023 : # define FD_CHECK_SH32  ((uchar)6) /* Validation should check that the immediate is a valid 32-bit shift exponent */
     169    49413999 : # define FD_CHECK_SH64  ((uchar)7) /* Validation should check that the immediate is a valid 64-bit shift exponent */
     170     1098279 : # define FD_INVALID     ((uchar)8) /* The opcode is invalid */
     171      123828 : # define FD_CHECK_CALLX ((uchar)9) /* Validation should check that callx has valid register number */
     172             : 
     173        6651 :   static uchar const validation_map[ 256 ] = {
     174             :     /* 0x00 */ FD_INVALID,    /* 0x01 */ FD_INVALID,    /* 0x02 */ FD_INVALID,    /* 0x03 */ FD_INVALID,
     175             :     /* 0x04 */ FD_VALID,      /* 0x05 */ FD_CHECK_JMP,  /* 0x06 */ FD_INVALID,    /* 0x07 */ FD_VALID,
     176             :     /* 0x08 */ FD_INVALID,    /* 0x09 */ FD_INVALID,    /* 0x0a */ FD_INVALID,    /* 0x0b */ FD_INVALID,
     177             :     /* 0x0c */ FD_VALID,      /* 0x0d */ FD_INVALID,    /* 0x0e */ FD_INVALID,    /* 0x0f */ FD_VALID,
     178             :     /* 0x10 */ FD_INVALID,    /* 0x11 */ FD_INVALID,    /* 0x12 */ FD_INVALID,    /* 0x13 */ FD_INVALID,
     179             :     /* 0x14 */ FD_VALID,      /* 0x15 */ FD_CHECK_JMP,  /* 0x16 */ FD_INVALID,    /* 0x17 */ FD_VALID,
     180             :     /* 0x18 */ FD_CHECK_LDQ,  /* 0x19 */ FD_INVALID,    /* 0x1a */ FD_INVALID,    /* 0x1b */ FD_INVALID,
     181             :     /* 0x1c */ FD_VALID,      /* 0x1d */ FD_CHECK_JMP,  /* 0x1e */ FD_INVALID,    /* 0x1f */ FD_VALID,
     182             :     /* 0x20 */ FD_INVALID,    /* 0x21 */ FD_INVALID,    /* 0x22 */ FD_INVALID,    /* 0x23 */ FD_INVALID,
     183             :     /* 0x24 */ FD_VALID,      /* 0x25 */ FD_CHECK_JMP,  /* 0x26 */ FD_INVALID,    /* 0x27 */ FD_VALID,
     184             :     /* 0x28 */ FD_INVALID,    /* 0x29 */ FD_INVALID,    /* 0x2a */ FD_INVALID,    /* 0x2b */ FD_INVALID,
     185             :     /* 0x2c */ FD_VALID,      /* 0x2d */ FD_CHECK_JMP,  /* 0x2e */ FD_INVALID,    /* 0x2f */ FD_VALID,
     186             :     /* 0x30 */ FD_INVALID,    /* 0x31 */ FD_INVALID,    /* 0x32 */ FD_INVALID,    /* 0x33 */ FD_INVALID,
     187             :     /* 0x34 */ FD_CHECK_DIV,  /* 0x35 */ FD_CHECK_JMP,  /* 0x36 */ FD_INVALID,    /* 0x37 */ FD_CHECK_DIV,
     188             :     /* 0x38 */ FD_INVALID,    /* 0x39 */ FD_INVALID,    /* 0x3a */ FD_INVALID,    /* 0x3b */ FD_INVALID,
     189             :     /* 0x3c */ FD_VALID,      /* 0x3d */ FD_CHECK_JMP,  /* 0x3e */ FD_INVALID,    /* 0x3f */ FD_VALID,
     190             :     /* 0x40 */ FD_INVALID,    /* 0x41 */ FD_INVALID,    /* 0x42 */ FD_INVALID,    /* 0x43 */ FD_INVALID,
     191             :     /* 0x44 */ FD_VALID,      /* 0x45 */ FD_CHECK_JMP,  /* 0x46 */ FD_INVALID,    /* 0x47 */ FD_VALID,
     192             :     /* 0x48 */ FD_INVALID,    /* 0x49 */ FD_INVALID,    /* 0x4a */ FD_INVALID,    /* 0x4b */ FD_INVALID,
     193             :     /* 0x4c */ FD_VALID,      /* 0x4d */ FD_CHECK_JMP,  /* 0x4e */ FD_INVALID,    /* 0x4f */ FD_VALID,
     194             :     /* 0x50 */ FD_INVALID,    /* 0x51 */ FD_INVALID,    /* 0x52 */ FD_INVALID,    /* 0x53 */ FD_INVALID,
     195             :     /* 0x54 */ FD_VALID,      /* 0x55 */ FD_CHECK_JMP,  /* 0x56 */ FD_INVALID,    /* 0x57 */ FD_VALID,
     196             :     /* 0x58 */ FD_INVALID,    /* 0x59 */ FD_INVALID,    /* 0x5a */ FD_INVALID,    /* 0x5b */ FD_INVALID,
     197             :     /* 0x5c */ FD_VALID,      /* 0x5d */ FD_CHECK_JMP,  /* 0x5e */ FD_INVALID,    /* 0x5f */ FD_VALID,
     198             :     /* 0x60 */ FD_INVALID,    /* 0x61 */ FD_VALID,      /* 0x62 */ FD_CHECK_ST,   /* 0x63 */ FD_CHECK_ST,
     199             :     /* 0x64 */ FD_CHECK_SH32, /* 0x65 */ FD_CHECK_JMP,  /* 0x66 */ FD_INVALID,    /* 0x67 */ FD_CHECK_SH64,
     200             :     /* 0x68 */ FD_INVALID,    /* 0x69 */ FD_VALID,      /* 0x6a */ FD_CHECK_ST,   /* 0x6b */ FD_CHECK_ST,
     201             :     /* 0x6c */ FD_VALID,      /* 0x6d */ FD_CHECK_JMP,  /* 0x6e */ FD_INVALID,    /* 0x6f */ FD_VALID,
     202             :     /* 0x70 */ FD_INVALID,    /* 0x71 */ FD_VALID,      /* 0x72 */ FD_CHECK_ST,   /* 0x73 */ FD_CHECK_ST,
     203             :     /* 0x74 */ FD_CHECK_SH32, /* 0x75 */ FD_CHECK_JMP,  /* 0x76 */ FD_INVALID,    /* 0x77 */ FD_CHECK_SH64,
     204             :     /* 0x78 */ FD_INVALID,    /* 0x79 */ FD_VALID,      /* 0x7a */ FD_CHECK_ST,   /* 0x7b */ FD_CHECK_ST,
     205             :     /* 0x7c */ FD_VALID,      /* 0x7d */ FD_CHECK_JMP,  /* 0x7e */ FD_INVALID,    /* 0x7f */ FD_VALID,
     206             :     /* 0x80 */ FD_INVALID,    /* 0x81 */ FD_INVALID,    /* 0x82 */ FD_INVALID,    /* 0x83 */ FD_INVALID,
     207             :     /* 0x84 */ FD_VALID,      /* 0x85 */ FD_VALID,      /* 0x86 */ FD_INVALID,    /* 0x87 */ FD_VALID,
     208             :     /* 0x88 */ FD_INVALID,    /* 0x89 */ FD_INVALID,    /* 0x8a */ FD_INVALID,    /* 0x8b */ FD_INVALID,
     209             :     /* 0x8c */ FD_INVALID,    /* 0x8d */ FD_CHECK_CALLX,/* 0x8e */ FD_INVALID,    /* 0x8f */ FD_INVALID,
     210             :     /* 0x90 */ FD_INVALID,    /* 0x91 */ FD_INVALID,    /* 0x92 */ FD_INVALID,    /* 0x93 */ FD_INVALID,
     211             :     /* 0x94 */ FD_CHECK_DIV,  /* 0x95 */ FD_VALID,      /* 0x96 */ FD_INVALID,    /* 0x97 */ FD_CHECK_DIV,
     212             :     /* 0x98 */ FD_INVALID,    /* 0x99 */ FD_INVALID,    /* 0x9a */ FD_INVALID,    /* 0x9b */ FD_INVALID,
     213             :     /* 0x9c */ FD_VALID,      /* 0x9d */ FD_INVALID,    /* 0x9e */ FD_INVALID,    /* 0x9f */ FD_VALID,
     214             :     /* 0xa0 */ FD_INVALID,    /* 0xa1 */ FD_INVALID,    /* 0xa2 */ FD_INVALID,    /* 0xa3 */ FD_INVALID,
     215             :     /* 0xa4 */ FD_VALID,      /* 0xa5 */ FD_CHECK_JMP,  /* 0xa6 */ FD_INVALID,    /* 0xa7 */ FD_VALID,
     216             :     /* 0xa8 */ FD_INVALID,    /* 0xa9 */ FD_INVALID,    /* 0xaa */ FD_INVALID,    /* 0xab */ FD_INVALID,
     217             :     /* 0xac */ FD_VALID,      /* 0xad */ FD_CHECK_JMP,  /* 0xae */ FD_INVALID,    /* 0xaf */ FD_VALID,
     218             :     /* 0xb0 */ FD_INVALID,    /* 0xb1 */ FD_INVALID,    /* 0xb2 */ FD_INVALID,    /* 0xb3 */ FD_INVALID,
     219             :     /* 0xb4 */ FD_VALID,      /* 0xb5 */ FD_CHECK_JMP,  /* 0xb6 */ FD_INVALID,    /* 0xb7 */ FD_VALID,
     220             :     /* 0xb8 */ FD_INVALID,    /* 0xb9 */ FD_INVALID,    /* 0xba */ FD_INVALID,    /* 0xbb */ FD_INVALID,
     221             :     /* 0xbc */ FD_VALID,      /* 0xbd */ FD_CHECK_JMP,  /* 0xbe */ FD_INVALID,    /* 0xbf */ FD_VALID,
     222             :     /* 0xc0 */ FD_INVALID,    /* 0xc1 */ FD_INVALID,    /* 0xc2 */ FD_INVALID,    /* 0xc3 */ FD_INVALID,
     223             :     /* 0xc4 */ FD_CHECK_SH32, /* 0xc5 */ FD_CHECK_JMP,  /* 0xc6 */ FD_INVALID,    /* 0xc7 */ FD_CHECK_SH64,
     224             :     /* 0xc8 */ FD_INVALID,    /* 0xc9 */ FD_INVALID,    /* 0xca */ FD_INVALID,    /* 0xcb */ FD_INVALID,
     225             :     /* 0xcc */ FD_VALID,      /* 0xcd */ FD_CHECK_JMP,  /* 0xce */ FD_INVALID,    /* 0xcf */ FD_VALID,
     226             :     /* 0xd0 */ FD_INVALID,    /* 0xd1 */ FD_INVALID,    /* 0xd2 */ FD_INVALID,    /* 0xd3 */ FD_INVALID,
     227             :     /* 0xd4 */ FD_CHECK_END,  /* 0xd5 */ FD_CHECK_JMP,  /* 0xd6 */ FD_INVALID,    /* 0xd7 */ FD_INVALID,
     228             :     /* 0xd8 */ FD_INVALID,    /* 0xd9 */ FD_INVALID,    /* 0xda */ FD_INVALID,    /* 0xdb */ FD_INVALID,
     229             :     /* 0xdc */ FD_CHECK_END,  /* 0xdd */ FD_CHECK_JMP,  /* 0xde */ FD_INVALID,    /* 0xdf */ FD_INVALID,
     230             :     /* 0xe0 */ FD_INVALID,    /* 0xe1 */ FD_INVALID,    /* 0xe2 */ FD_INVALID,    /* 0xe3 */ FD_INVALID,
     231             :     /* 0xe4 */ FD_INVALID,    /* 0xe5 */ FD_INVALID,    /* 0xe6 */ FD_INVALID,    /* 0xe7 */ FD_INVALID,
     232             :     /* 0xe8 */ FD_INVALID,    /* 0xe9 */ FD_INVALID,    /* 0xea */ FD_INVALID,    /* 0xeb */ FD_INVALID,
     233             :     /* 0xec */ FD_INVALID,    /* 0xed */ FD_INVALID,    /* 0xee */ FD_INVALID,    /* 0xef */ FD_INVALID,
     234             :     /* 0xf0 */ FD_INVALID,    /* 0xf1 */ FD_INVALID,    /* 0xf2 */ FD_INVALID,    /* 0xf3 */ FD_INVALID,
     235             :     /* 0xf4 */ FD_INVALID,    /* 0xf5 */ FD_INVALID,    /* 0xf6 */ FD_INVALID,    /* 0xf7 */ FD_INVALID,
     236             :     /* 0xf8 */ FD_INVALID,    /* 0xf9 */ FD_INVALID,    /* 0xfa */ FD_INVALID,    /* 0xfb */ FD_INVALID,
     237             :     /* 0xfc */ FD_INVALID,    /* 0xfd */ FD_INVALID,    /* 0xfe */ FD_INVALID,    /* 0xff */ FD_INVALID,
     238        6651 :   };
     239             : 
     240             :   /* FIXME: These checks are not necessary assuming fd_vm_t is populated by metadata
     241             :      generated in fd_sbpf_elf_peek (which performs these checks). But there is no guarantee, and
     242             :      this non-guarantee is (rightfully) exploited by the fuzz harnesses.
     243             :      Agave doesn't perform these checks explicitly due to Rust's guarantees  */
     244        6651 :   if( FD_UNLIKELY( vm->text_sz / 8UL != vm->text_cnt ||
     245        6651 :                    (const uchar *)vm->text < vm->rodata ||
     246        6651 :                    (ulong)vm->text > (ulong)vm->text + vm->text_sz || /* Overflow chk */
     247        6651 :                    (const uchar *)vm->text + vm->text_sz > vm->rodata + vm->rodata_sz ) )
     248         162 :     return FD_VM_ERR_BAD_TEXT;
     249             : 
     250        6489 :   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 */
     251           3 :     return FD_VM_TEXT_SZ_UNALIGNED;
     252             : 
     253        6486 :   if ( FD_UNLIKELY( vm->text_cnt == 0UL ) ) /* https://github.com/solana-labs/rbpf/blob/v0.8.0/src/verifier.rs#L112 */
     254          45 :     return FD_VM_ERR_EMPTY;
     255             : 
     256             :   /* FIXME: CLEAN UP LONG / ULONG TYPE CONVERSION */
     257        6441 :   ulong const * text     = vm->text;
     258        6441 :   ulong         text_cnt = vm->text_cnt;
     259   849054258 :   for( ulong i=0UL; i<text_cnt; i++ ) {
     260   849049566 :     fd_sbpf_instr_t instr = fd_sbpf_instr( text[i] );
     261             : 
     262   849049566 :     uchar validation_code = validation_map[ instr.opcode.raw ];
     263   849049566 :     switch( validation_code ) {
     264             : 
     265   673297611 :     case FD_VALID: break;
     266             : 
     267     5098122 :     case FD_CHECK_JMP: {
     268     5098122 :       long jmp_dst = (long)i + (long)instr.offset + 1L;
     269     5098122 :       if( FD_UNLIKELY( (jmp_dst<0) | (jmp_dst>=(long)text_cnt)                          ) ) return FD_VM_ERR_JMP_OUT_OF_BOUNDS;
     270     5097969 :       if( FD_UNLIKELY( fd_sbpf_instr( text[ jmp_dst ] ).opcode.raw==FD_SBPF_OP_ADDL_IMM ) ) return FD_VM_ERR_JMP_TO_ADDL_IMM;
     271     5097846 :       break;
     272     5097969 :     }
     273             : 
     274     5097846 :     case FD_CHECK_END: {
     275        1503 :       if( FD_UNLIKELY( !((instr.imm==16) | (instr.imm==32) | (instr.imm==64)) ) ) return FD_VM_ERR_INVALID_END_IMM;
     276        1479 :       break;
     277        1503 :     }
     278             : 
     279     7037010 :     case FD_CHECK_ST: break; /* FIXME: HMMM ... */
     280             : 
     281             :     /* https://github.com/solana-labs/rbpf/blob/b503a1867a9cfa13f93b4d99679a17fe219831de/src/verifier.rs#L244 */
     282     1348605 :     case FD_CHECK_LDQ: {
     283             :       /* https://github.com/solana-labs/rbpf/blob/b503a1867a9cfa13f93b4d99679a17fe219831de/src/verifier.rs#L131 */
     284     1348605 :       if( FD_UNLIKELY( (i+1UL)>=text_cnt ) ) return FD_VM_ERR_INCOMPLETE_LDQ;
     285             : 
     286             :       /* https://github.com/solana-labs/rbpf/blob/b503a1867a9cfa13f93b4d99679a17fe219831de/src/verifier.rs#L137-L139 */
     287     1348602 :       fd_sbpf_instr_t addl_imm = fd_sbpf_instr( text[ i+1UL ] );
     288     1348602 :       if( FD_UNLIKELY( addl_imm.opcode.raw!=FD_SBPF_OP_ADDL_IMM ) ) return FD_VM_ERR_LDQ_NO_ADDL_IMM;
     289             : 
     290             :       /* FIXME: SET A BIT MAP HERE OF ADDL_IMM TO DENOTE * AS FORBIDDEN
     291             :          BRANCH TARGETS OF CALL_REG?? */
     292             : 
     293     1348599 :       i++; /* Skip the addl imm */
     294     1348599 :       break;
     295     1348602 :     }
     296             : 
     297    64446558 :     case FD_CHECK_DIV: {
     298    64446558 :       if( FD_UNLIKELY( instr.imm==0 ) ) return FD_VM_ERR_SIGFPE;  /* FIXME: SIGILL? */
     299    64446537 :       break;
     300    64446558 :     }
     301             : 
     302    64446537 :     case FD_CHECK_SH32: {
     303    48308070 :       if( FD_UNLIKELY( instr.imm>=32 ) ) return FD_VM_SH_OVERFLOW;
     304    48308046 :       break;
     305    48308070 :     }
     306             : 
     307    49394046 :     case FD_CHECK_SH64: {
     308    49394046 :       if( FD_UNLIKELY( instr.imm>=64 ) ) return FD_VM_SH_OVERFLOW;
     309    49394010 :       break;
     310    49394046 :     }
     311             : 
     312    49394010 :     case FD_CHECK_CALLX: {
     313             :       /* The register number to read is stored in the immediate.
     314             :          https://github.com/solana-labs/rbpf/blob/v0.8.1/src/verifier.rs#L218 */
     315      117177 :       if( FD_UNLIKELY( instr.imm > 9 ) ) {
     316          12 :         return FD_VM_ERR_INVALID_REG;
     317          12 :       }
     318      117165 :       break;
     319      117177 :     }
     320             : 
     321      117165 :     case FD_INVALID: default: return FD_VM_ERR_INVALID_OPCODE;
     322   849049566 :     }
     323             : 
     324   849048303 :     if( FD_UNLIKELY( instr.src_reg>10 ) ) return FD_VM_ERR_INVALID_SRC_REG; /* FIXME: MAGIC NUMBER */
     325             : 
     326   849048105 :     int is_invalid_dst_reg = instr.dst_reg > ((validation_code == FD_CHECK_ST) ? 10 : 9); /* FIXME: MAGIC NUMBER */
     327   849048105 :     if( FD_UNLIKELY( is_invalid_dst_reg ) ) return FD_VM_ERR_INVALID_DST_REG;
     328   849048105 :   }
     329             : 
     330        4692 :   return FD_VM_SUCCESS;
     331        6441 : }
     332             : 
     333             : FD_FN_CONST ulong
     334       12075 : fd_vm_align( void ) {
     335       12075 :   return FD_VM_ALIGN;
     336       12075 : }
     337             : 
     338             : FD_FN_CONST ulong
     339       12075 : fd_vm_footprint( void ) {
     340       12075 :   return FD_VM_FOOTPRINT;
     341       12075 : }
     342             : 
     343             : void *
     344       15348 : fd_vm_new( void * shmem ) {
     345             : 
     346       15348 :   if( FD_UNLIKELY( !shmem ) ) {
     347           0 :     FD_LOG_WARNING(( "NULL shmem" ));
     348           0 :     return NULL;
     349           0 :   }
     350             : 
     351       15348 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_vm_align() ) ) ) {
     352           0 :     FD_LOG_WARNING(( "misaligned shmem" ));
     353           0 :     return NULL;
     354           0 :   }
     355             : 
     356       15348 :   fd_vm_t * vm = (fd_vm_t *)shmem;
     357       15348 :   fd_memset( vm, 0, fd_vm_footprint() );
     358             : 
     359       15348 :   FD_COMPILER_MFENCE();
     360       15348 :   FD_VOLATILE( vm->magic ) = FD_VM_MAGIC;
     361       15348 :   FD_COMPILER_MFENCE();
     362             : 
     363       15348 :   return shmem;
     364       15348 : }
     365             : 
     366             : fd_vm_t *
     367       15348 : fd_vm_join( void * shmem ) {
     368             : 
     369       15348 :   if( FD_UNLIKELY( !shmem ) ) {
     370           0 :     FD_LOG_WARNING(( "NULL shmem" ));
     371           0 :     return NULL;
     372           0 :   }
     373             : 
     374       15348 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_vm_align() ) ) ) {
     375           0 :     FD_LOG_WARNING(( "misaligned shmem" ));
     376           0 :     return NULL;
     377           0 :   }
     378             : 
     379       15348 :   fd_vm_t * vm = (fd_vm_t *)shmem;
     380             : 
     381       15348 :   if( FD_UNLIKELY( vm->magic!=FD_VM_MAGIC ) ) {
     382           0 :     FD_LOG_WARNING(( "bad magic" ));
     383           0 :     return NULL;
     384           0 :   }
     385             : 
     386       15348 :   return vm;
     387       15348 : }
     388             : 
     389             : void *
     390         867 : fd_vm_leave( fd_vm_t * vm ) {
     391             : 
     392         867 :   if( FD_UNLIKELY( !vm ) ) {
     393           0 :     FD_LOG_WARNING(( "NULL vm" ));
     394           0 :     return NULL;
     395           0 :   }
     396             : 
     397         867 :   return (void *)vm;
     398         867 : }
     399             : 
     400             : void *
     401         867 : fd_vm_delete( void * shmem ) {
     402             : 
     403         867 :   if( FD_UNLIKELY( !shmem ) ) {
     404           0 :     FD_LOG_WARNING(( "NULL shmem" ));
     405           0 :     return NULL;
     406           0 :   }
     407             : 
     408         867 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_vm_align() ) ) ) {
     409           0 :     FD_LOG_WARNING(( "misaligned shmem" ));
     410           0 :     return NULL;
     411           0 :   }
     412             : 
     413         867 :   fd_vm_t * vm = (fd_vm_t *)shmem;
     414             : 
     415         867 :   if( FD_UNLIKELY( vm->magic!=FD_VM_MAGIC ) ) {
     416           0 :     FD_LOG_WARNING(( "bad magic" ));
     417           0 :     return NULL;
     418           0 :   }
     419             : 
     420         867 :   FD_COMPILER_MFENCE();
     421         867 :   FD_VOLATILE( vm->magic ) = 0UL;
     422         867 :   FD_COMPILER_MFENCE();
     423             : 
     424         867 :   return (void *)vm;
     425         867 : }
     426             : 
     427             : fd_vm_t *
     428             : fd_vm_init(
     429             :    fd_vm_t * vm,
     430             :    fd_exec_instr_ctx_t *instr_ctx,
     431             :    ulong heap_max,
     432             :    ulong entry_cu,
     433             :    uchar const * rodata,
     434             :    ulong rodata_sz,
     435             :    ulong const * text,
     436             :    ulong text_cnt,
     437             :    ulong text_off,
     438             :    ulong text_sz,
     439             :    ulong entry_pc,
     440             :    ulong * calldests,
     441             :    fd_sbpf_syscalls_t * syscalls,
     442             :    fd_vm_trace_t * trace,
     443             :    fd_sha256_t * sha,
     444             :    fd_vm_input_region_t * mem_regions,
     445             :    uint mem_regions_cnt,
     446             :    fd_vm_acc_region_meta_t * acc_region_metas,
     447             :    uchar is_deprecated,
     448       18885 :    int direct_mapping ) {
     449             : 
     450       18885 :   if ( FD_UNLIKELY( vm == NULL ) ) {
     451           0 :     FD_LOG_WARNING(( "NULL vm" ));
     452           0 :     return NULL;
     453           0 :   }
     454             : 
     455       18885 :   if ( FD_UNLIKELY( vm->magic != FD_VM_MAGIC ) ) {
     456           0 :     FD_LOG_WARNING(( "bad magic" ));
     457           0 :     return NULL;
     458           0 :   }
     459             : 
     460       18885 :   if ( FD_UNLIKELY( instr_ctx == NULL ) ) {
     461           0 :     FD_LOG_WARNING(( "NULL instr_ctx" ));
     462           0 :     return NULL;
     463           0 :   }
     464             : 
     465       18885 :   if ( FD_UNLIKELY( heap_max > FD_VM_HEAP_MAX ) ) {
     466           0 :     FD_LOG_WARNING(( "heap_max > FD_VM_HEAP_MAX" ));
     467           0 :     return NULL;
     468           0 :   }
     469             : 
     470             :   // Set the vm fields
     471       18885 :   vm->instr_ctx = instr_ctx;
     472       18885 :   vm->heap_max = heap_max;
     473       18885 :   vm->entry_cu = entry_cu;
     474       18885 :   vm->rodata = rodata;
     475       18885 :   vm->rodata_sz = rodata_sz;
     476       18885 :   vm->text = text;
     477       18885 :   vm->text_cnt = text_cnt;
     478       18885 :   vm->text_off = text_off;
     479       18885 :   vm->text_sz = text_sz;
     480       18885 :   vm->entry_pc = entry_pc;
     481       18885 :   vm->calldests = calldests;
     482       18885 :   vm->syscalls = syscalls;
     483       18885 :   vm->trace = trace;
     484       18885 :   vm->sha = sha;
     485       18885 :   vm->input_mem_regions = mem_regions;
     486       18885 :   vm->input_mem_regions_cnt = mem_regions_cnt;
     487       18885 :   vm->acc_region_metas = acc_region_metas;
     488       18885 :   vm->is_deprecated = is_deprecated;
     489       18885 :   vm->direct_mapping = direct_mapping;
     490       18885 :   vm->stack_frame_size = FD_VM_STACK_FRAME_SZ + ( direct_mapping ? 0UL : FD_VM_STACK_GUARD_SZ );
     491       18885 :   vm->segv_store_vaddr = ULONG_MAX;
     492             : 
     493             :   /* Unpack the configuration */
     494       18885 :   int err = fd_vm_setup_state_for_execution( vm );
     495       18885 :   if( FD_UNLIKELY( err != FD_VM_SUCCESS ) ) {
     496           0 :     return NULL;
     497           0 :   }
     498             : 
     499       18885 :   return vm;
     500       18885 : }
     501             : 
     502             : int
     503       30096 : fd_vm_setup_state_for_execution( fd_vm_t * vm ) {
     504             : 
     505       30096 :   if ( FD_UNLIKELY( !vm ) ) {
     506           0 :     FD_LOG_WARNING(( "NULL vm" ));
     507           0 :     return FD_VM_ERR_INVAL;
     508           0 :   }
     509             : 
     510             :   /* Unpack input and rodata */
     511       30096 :   fd_vm_mem_cfg( vm );
     512             : 
     513             :   /* Initialize registers */
     514             :   /* FIXME: Zero out shadow, stack and heap here? */
     515       30096 :   fd_memset( vm->reg, 0, FD_VM_REG_MAX * sizeof(ulong) );
     516       30096 :   vm->reg[ 1] = FD_VM_MEM_MAP_INPUT_REGION_START;
     517       30096 :   vm->reg[10] = FD_VM_MEM_MAP_STACK_REGION_START + 0x1000;
     518             : 
     519             :   /* Set execution state */
     520       30096 :   vm->pc        = vm->entry_pc;
     521       30096 :   vm->ic        = 0UL;
     522       30096 :   vm->cu        = vm->entry_cu;
     523       30096 :   vm->frame_cnt = 0UL;
     524             : 
     525       30096 :   vm->heap_sz = 0UL;
     526             : 
     527             :   /* Do NOT reset logs */
     528             : 
     529       30096 :   return FD_VM_SUCCESS;
     530       30096 : }

Generated by: LCOV version 1.14