Exemplo n.º 1
0
static void ValidateJmpz(const NCDecoderInst *dinst) {
  NCInstBytesPtr opcode;
  uint8_t opcode0;
  int32_t offset;
  NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
  NCInstBytesPtrInitInc(&opcode, &dinst->inst_bytes,
                        dinst->inst.prefixbytes);
  opcode0 = NCInstBytesByteInline(&opcode, 0);
  NCStatsCheckTarget(vstate);
  if (opcode0 == 0x0f) {
    /* Multbyte opcode. Intruction is of form:
     *    0F80 .. 0F8F: jCC $Jz
     */
    NCInstBytesPtr opcode_2;
    NCInstBytesPtrInitInc(&opcode_2, &opcode, 2);
    offset = NCInstBytesInt32(&opcode_2, dinst->inst.immbytes);
  } else {
    /* Single byte opcode. Must be one of:
     *    E8: call $Jz
     *    E9: jmp $Jx
     */
    NCInstBytesPtr opcode_1;
    NCInstBytesPtrInitInc(&opcode_1, &opcode, 1);
    offset = NCInstBytesInt32(&opcode_1, dinst->inst.immbytes);
    /* as a courtesy, check call alignment correctness */
    if (opcode0 == 0xe8) ValidateCallAlignment(dinst);
  }
  RememberJumpTarget(dinst, offset, vstate);
}
Exemplo n.º 2
0
int64_t NCInstBytesInt64(const NCInstBytesPtr* ptr, int num_bytes) {
  switch (num_bytes) {
    case 1:
    case 2:
    case 3: /* Handle special case of Iw, Ib in 32 bit validator. */
    case 4:
      return (int64_t) NCInstBytesInt32(ptr, num_bytes);
    case 6: {
      /* Handle special case of 48-bit pointers in 32 bit validator. */
      NCInstBytesPtr ptr_plus_2;
      NCInstBytesPtrInitInc(&ptr_plus_2, ptr, 2);
      return ((int64_t) (NCInstBytesInt32(&ptr_plus_2, 2)) << 32) |
          ((int64_t) (NCInstBytesInt32(ptr, 4)));
    }
    case 8: {
      NCInstBytesPtr ptr_plus_4;
      NCInstBytesPtrInitInc(&ptr_plus_4, ptr, 4);
      return ((int64_t) (NCInstBytesInt32(&ptr_plus_4, 4)) << 32) |
          ((int64_t) (NCInstBytesInt32(ptr, 4)));
    }
    default:
      CHECK(0); /* Fail -- should not happen. */
      return -1;
  }
}
Exemplo n.º 3
0
/*
 * The NaCl five-byte safe indirect calling sequence looks like this:
 *   83 e0 e0                 and  $0xe0,%eax
 *   ff d0                    call *%eax
 * The call may be replaced with a ff e0 jmp. Any register may
 * be used, not just eax. The validator requires exactly this
 * sequence.
 * Note: The code above assumes 32-bit alignment. Change e0 as appropriate
 * if a different alignment is used.
 */
static void ValidateIndirect5(const NCDecoderInst *dinst) {
  NCInstBytesPtr jmpopcode;
  NCInstBytesPtr andopcode;
  uint8_t               mrm;
  uint8_t               targetreg;
  const uint8_t         kReg_ESP = 4;
  NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);

  struct NCDecoderInst *andinst = PreviousInst(dinst, 1);
  if ((andinst == NULL) || (andinst->inst.bytes.length != 3)) {
    NCBadInstructionError(dinst, "Unsafe indirect jump");
    NCStatsUnsafeIndirect(vstate);
    return;
  }
  /* note: no prefixbytes allowed */
  NCInstBytesPtrInitInc(&jmpopcode, &dinst->inst_bytes, 0);
  /* note: no prefixbytes allowed */
  NCInstBytesPtrInitInc(&andopcode, &andinst->inst_bytes, 0);
  mrm = NCInstBytesByteInline(&jmpopcode, 1);
  /* Note that the modrm_rm field holds the
   * target addr the modrm_reg is the opcode.
   */
  targetreg = modrm_rmInline(mrm);
  NCStatsCheckTarget(vstate);
  NCStatsTargetIndirect(vstate);
  do {
    /* no prefix bytes allowed */
    if (dinst->inst.prefixbytes != 0) break;
    if (dinst->inst.prefixbytes != 0) break;
    /* Check all the opcodes. */
    /* In GROUP5, 2 => call, 4 => jmp */
    if (NCInstBytesByteInline(&jmpopcode, 0) != 0xff) break;
    if ((modrm_regInline(mrm) != 2) && (modrm_regInline(mrm) != 4)) break;
    /* Issue 32: disallow unsafe call/jump indirection */
    /* example:    ff 12     call (*edx)               */
    /* Reported by defend.the.world on 11 Dec 2008     */
    if (modrm_modInline(mrm) != 3) break;
    if (targetreg == kReg_ESP) break;
    if (NCInstBytesByteInline(&andopcode, 0) != 0x83) break;
    /* check modrm bytes of or and and instructions */
    if (NCInstBytesByteInline(&andopcode, 1) != (0xe0 | targetreg)) break;
    /* check mask */
    if (NCInstBytesByteInline(&andopcode, 2) !=
        (0x0ff & ~vstate->bundle_mask)) break;
    /* All checks look good. Make the sequence 'atomic.' */
    ForgetInstructionBoundary(dinst, vstate);
    /* as a courtesy, check call alignment correctness */
    if (modrm_regInline(mrm) == 2) ValidateCallAlignment(dinst);
    return;
  } while (0);
  NCBadInstructionError(dinst, "Unsafe indirect jump");
  NCStatsUnsafeIndirect(vstate);
}
/* disassembler stuff */
static const char* DisFmt(const NCDecoderInst *dinst) {
  NCInstBytesPtr opbyte;
  uint8_t opbyte0;
  uint8_t opbyte1;
  uint8_t pm = dinst->inst.opcode_prefixmask;
  NCInstBytesPtrInitInc(&opbyte, &dinst->inst_bytes, NCOpcodeOffset(dinst));
  opbyte0 = NCInstBytesByte(&opbyte, 0);

  if (dinst->opinfo->insttype == NACLi_X87 ||
      dinst->opinfo->insttype == NACLi_X87_FSINCOS) {
    if (opbyte0 != kWAITOp) {
      return kDisasmX87Op[opbyte0 - kFirstX87Opcode][dinst->inst.mrm];
    }
  }
  if (dinst->opinfo->insttype == NACLi_FCMOV) {
    return kDisasmX87Op[opbyte0 - kFirstX87Opcode][dinst->inst.mrm];
  }
  if (dinst->opinfo->insttype == NACLi_NOP) return "nop";
  if (opbyte0 != kTwoByteOpcodeByte1) return kDisasm1ByteOp[opbyte0];
  opbyte1 = NCInstBytesByte(&opbyte, 1);
  if (opbyte1 == 0x0f) {
    return kDisasm0F0FOp[
        NCInstBytesByte(&opbyte, dinst->inst.bytes.length - 1)];
  }
  if (opbyte1 == 0x38) {
    return kDisasm0F38Op[NCInstBytesByte(&opbyte, 2)];
  }
  if (opbyte1 == 0x3A) {
    return kDisasm0F3AOp[NCInstBytesByte(&opbyte, 2)];
  }
  if (! (pm & (kPrefixDATA16 | kPrefixREPNE | kPrefixREP))) {
    return kDisasm0FXXOp[opbyte1];
  }
  if (pm & kPrefixDATA16) return kDisasm660FXXOp[opbyte1];
  if (pm & kPrefixREPNE)  return kDisasmF20FXXOp[opbyte1];
  if (pm & kPrefixREP)    return kDisasmF30FXXOp[opbyte1];

  /* no update; should be invalid */
  return "internal error";
}
/* Returns the (sign extended) 32-bit integer displacement value. */
static int32_t DispValue32(const NCDecoderInst* dinst) {
  NCInstBytesPtr addr;
  NCInstBytesPtrInitInc(&addr, &dinst->inst_bytes,
                        NCDispOffset(dinst));
  return NCInstBytesInt32(&addr, dinst->inst.dispbytes);
}
/* Returns the (sign extended) 64-bit integer immediate value. */
static int64_t ImmedValue64(const NCDecoderInst* dinst) {
  NCInstBytesPtr addr;
  NCInstBytesPtrInitInc(&addr, &dinst->inst_bytes,
                        NCImmedOffset(dinst));
  return NCInstBytesInt64(&addr, dinst->inst.immbytes);
}