Esempio n. 1
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);
}
Esempio n. 2
0
/* Returns the corresponding segment register for the given index (0..7) */
static NaClExp* NaClAppendModRmSegmentReg(NaClInstState* state) {
  static NaClOpKind seg[8] = {
    RegES,
    RegCS,
    RegSS,
    RegDS,
    RegFS,
    RegGS,
    /* These should not happen. */
    RegUnknown,
    RegUnknown
  };
  return NaClAppendReg(seg[modrm_regInline(state->modrm)], &state->nodes);
}
/* Returns the index into the general purpose registers based on the
 * value in the modrm.rm field of the instruction (taking into account
 * the REX prefix if it appears).
 */
static INLINE uint32_t state_modrm_reg(const NCDecoderInst* dinst) {
  /* TODO(karl) This is no where near close to being correct. Currently,
   * It only models r/m64 entry for instructions in the Intel documentation,
   * which requires the W bit to be set (r/m32 entries do not use REX.w,
   * and a different set of registers).
   */
  uint32_t index = modrm_regInline(dinst->inst.mrm);
#if NACL_TARGET_SUBARCH == 64
  if (GetRexPrefixW(dinst) && GetRexPrefixR(dinst)) {
    index += 8;
  }
#endif
  return index;
}
Esempio n. 4
0
/* Return the general purpose register associated with the modrm.reg
 * field.
 */
static INLINE int NaClGetGenRegRegister(NaClInstState* state) {
  DEBUG(NaClLog(LOG_INFO, "Get GenRegRegister\n"));
  return NaClGetRexRReg(state, modrm_regInline(state->modrm));
}
Esempio n. 5
0
uint8_t modrm_reg(uint8_t modrm) {
  return modrm_regInline(modrm);
}
static void InstFormat(const char* format,
                       const NCDecoderInst *dinst,
                       struct Gio* fp) {
  char token_buf[128];
  char* fmt = token_buf;
  int pos = 0;

  strncpy(token_buf, format, sizeof(token_buf));

  while (1) {
    char* token = strtok(fmt, " ,\n");
    DEBUG( printf("\ntoken = '%s'\n", token) );
    if (NULL == token) {
      break;
    }
    if (pos > 1) {
      gprintf(fp, ", ");
    } else if (pos > 0) {
      gprintf(fp, " ");
    }
    if ('$' == token[0]) {
      NaClMRMGroups group = ParseGroupName(token+1);
      if (NOGROUP != group) {
        int mrm = modrm_regInline(dinst->inst.mrm);
        const char* opname = kDisasmModRMOp[group][mrm];
        DEBUG( printf("case: group %d, opname = %s\n", group, opname) );
        gprintf(fp, "%s", opname);
      } else {
        /* Tokens starting with a $ but not $group need formatting */
        DEBUG( printf("case: $ and not group\n") );
        switch (token[1]) {
          case 'A':
            gprintf(fp, "$A");
            break;
          case 'C':
            gprintf(fp, "%%cr%d", modrm_regInline(dinst->inst.mrm));
            break;
          case 'D':
            gprintf(fp, "%%dr%d", modrm_regInline(dinst->inst.mrm));
            break;
          case 'E':
          case 'M': /* mod should never be 3 for 'M' */
            /* TODO(sehr): byte and word accesses */
            RegMemPrint(dinst, gp_regs, 1, fp);
            break;
          case 'F':
            gprintf(fp, "eflags");
            break;
          case 'G':
            gprintf(fp, "%s", gp_regs[modrm_regInline(dinst->inst.mrm)]);
            break;
          case 'I':
            gprintf(fp, "0x%"NACL_PRIx64, ImmedValue64(dinst));
            break;
          case 'J':
            gprintf(fp, "0x%"NACL_PRIxNaClPcAddress,
                    NCPrintableInstructionAddress(dinst)
                    + dinst->inst.bytes.length
                    + ImmedValue32(dinst));
            break;
          case 'O':
            gprintf(fp, "[0x%"NACL_PRIx64"]", ImmedValue64(dinst));
            break;
          case 'P':
            if ('R' == token[2]) {
              gprintf(fp, "%%mm%d", modrm_rmInline(dinst->inst.mrm));
            } else {
              gprintf(fp, "%%mm%d", modrm_regInline(dinst->inst.mrm));
            }
            break;
          case 'Q':
            RegMemPrint(dinst, mmx_regs, 0, fp);
            break;
          case 'R':
            gprintf(fp, "%s", gp_regs[modrm_rmInline(dinst->inst.mrm)]);
            break;
          case 'S':
            gprintf(fp, "%s", seg_regs[modrm_regInline(dinst->inst.mrm)]);
            break;
          case 'V':
            if ('R' == token[2]) {
              gprintf(fp, "%%xmm%d", modrm_rmInline(dinst->inst.mrm));
            } else {
              gprintf(fp, "%%xmm%d", modrm_regInline(dinst->inst.mrm));
            }
            break;
          case 'W':
            RegMemPrint(dinst, xmm_regs, 0, fp);
            break;
          case 'X':
            gprintf(fp, "ds:[esi]");
            break;
          case 'Y':
            gprintf(fp, "es:[edi]");
            break;
          default:
            gprintf(fp, "token('%s')", token);
            break;
        }
      }
    } else {
      /* Print the token as is */
      gprintf(fp, "%s", token);
    }
    fmt = NULL;
    ++pos;
  }
}