/* Print out the register (from the list of register names),
 * that is referenced by the decoded instruction in the
 * decoder state. If is_gp_regs is true, the register names
 * correspond to general purpose register names. Otherwise,
 * they are some other set, such as MMX or XMM.
 */
static void RegMemPrint(const NCDecoderInst *dinst,
                        const char* reg_names[],
                        const uint8_t is_gp_regs,
                        struct Gio* fp) {
  DEBUG( printf(
             "reg mem print: sib_offset = %d, "
             "disp_offset = %d, mrm.mod = %02x\n",
             NCSibOffset(dinst), (int) NCDispOffset(dinst),
             modrm_modInline(dinst->inst.mrm)) );
  switch (modrm_modInline(dinst->inst.mrm)) {
    case 0:
      SegPrefixPrint(dinst, fp);
      if (NaClHasBit(dinst->inst.prefixmask, kPrefixADDR16)) {
        NaClIllegalOp(fp);
      } else {
        if (4 == modrm_rmInline(dinst->inst.mrm)) {
          SibPrint(dinst, fp);
        } else if (5 == modrm_rmInline(dinst->inst.mrm)) {
          gprintf(fp, "[0x%x]", DispValue32(dinst));
        } else {
          gprintf(fp, "[%s]", gp_regs[modrm_rmInline(dinst->inst.mrm)]);
        }
      }
      break;
    case 1:
      SegPrefixPrint(dinst, fp);
      if (NaClHasBit(dinst->inst.prefixmask, kPrefixADDR16)) {
        NaClIllegalOp(fp);
      } else {
        gprintf(fp, "0x%x", DispValue32(dinst));
        if (4 == modrm_rmInline(dinst->inst.mrm)) {
          SibPrint(dinst, fp);
        } else {
          gprintf(fp, "[%s]", gp_regs[modrm_rmInline(dinst->inst.mrm)]);
        }
      }
      break;
    case 2:
      SegPrefixPrint(dinst, fp);
      if (NaClHasBit(dinst->inst.prefixmask, kPrefixADDR16)) {
        NaClIllegalOp(fp);
      } else {
        gprintf(fp, "0x%x", DispValue32(dinst));
        if (4 == modrm_rmInline(dinst->inst.mrm)) {
          SibPrint(dinst, fp);
        } else {
          gprintf(fp, "[%s]", gp_regs[modrm_rmInline(dinst->inst.mrm)]);
        }
      }
      break;
    case 3:
      if (is_gp_regs) {
        gprintf(fp, "%s", reg_names[state_modrm_reg(dinst)]);
      } else {
        gprintf(fp, "%s", reg_names[modrm_rmInline(dinst->inst.mrm)]);
      }
      break;
  }
}
Esempio n. 2
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. 3
0
/* Return the general purpose register associated with the modrm.rm
 * field.
 */
static INLINE int NaClGetGenRmRegister(NaClInstState* state) {
  DEBUG(NaClLog(LOG_INFO, "Get GenRmRegister\n"));
  return NaClGetRexBReg(state, modrm_rmInline(state->modrm));
}
Esempio n. 4
0
uint8_t modrm_rm(uint8_t modrm) {
  return modrm_rmInline(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;
  }
}