示例#1
0
static Bool ValidateInst(const NCDecoderInst *dinst) {
  NaClCPUFeaturesX86 *cpufeatures;
  int squashme = 0;
  NCValidatorState* vstate;
  if (dinst == NULL) return TRUE;
  vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);

  OpcodeHisto(NCInstBytesByteInline(&dinst->inst_bytes,
                                    dinst->inst.prefixbytes),
              vstate);
  /* For testing only, this mode disables inter-instruction checks. */
  if (!NACL_FLAG_unsafe_single_inst32_mode) {
    RememberInstructionBoundary(dinst, vstate);
  }

  cpufeatures = &(vstate->cpufeatures);

  if (!ValidatePrefixes(dinst)) {
    NCBadInstructionError(dinst, "Bad prefix usage");
    NCStatsBadPrefix(vstate);
  }

  if ((dinst->opinfo->insttype != NACLi_NOP) &&
      ((size_t) (dinst->inst.bytes.length - dinst->inst.prefixbytes)
       > kMaxValidInstLength)) {
    NCBadInstructionError(dinst, "Instruction too long");
    NCStatsBadInstLength(vstate);
  }

  switch (dinst->opinfo->insttype) {
    case NACLi_NOP:
    case NACLi_386:
    case NACLi_386L:
    case NACLi_386R:
    case NACLi_386RE:
      break;
    case NACLi_JMP8:
      ValidateJmp8(dinst);
      break;
    case NACLi_JMPZ:
      ValidateJmpz(dinst);
      break;
    case NACLi_INDIRECT:
      ValidateIndirect5(dinst);
      break;
    case NACLi_X87:
    case NACLi_X87_FSINCOS:
      squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_x87);
      break;
    case NACLi_SFENCE_CLFLUSH:
      squashme = ValidateSFenceClFlush(dinst);
      break;
    case NACLi_CMPXCHG8B:
      /* Only allow if the modrm mod field accesses memory.
       * This stops us from accepting f00f on multiple bytes.
       * http://en.wikipedia.org/wiki/Pentium_F00F_bug
       */
      if (modrm_modInline(dinst->inst.mrm)
          == kModRmModFieldDefinesRegisterRef) {
        NCBadInstructionError(dinst, "Illegal instruction");
        NCStatsIllegalInst(vstate);
      }
      squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_CX8);
      break;
    case NACLi_CMOV:
      squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_CMOV);
      break;
    case NACLi_FCMOV:
      squashme = !(NaClGetCPUFeature(cpufeatures, NaClCPUFeature_CMOV) &&
                   NaClGetCPUFeature(cpufeatures, NaClCPUFeature_x87));
      break;
    case NACLi_RDTSC:
      squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_TSC);
      break;
    case NACLi_MMX:
      squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_MMX);
      break;
    case NACLi_MMXSSE2:
      /* Note: We accept these instructions if either MMX or SSE2 bits */
      /* are set, in case MMX instructions go away someday...          */
      squashme = !(NaClGetCPUFeature(cpufeatures, NaClCPUFeature_MMX) ||
                   NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE2));
      break;
    case NACLi_SSE:
      squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE);
      break;
    case NACLi_SSE2:
      squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE2);
      break;
    case NACLi_SSE3:
      squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE3);
      break;
    case NACLi_SSE4A:
      squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE4A);
      break;
    case NACLi_SSE41:
      squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE41);
      break;
    case NACLi_SSE42:
      squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE42);
      break;
    case NACLi_MOVBE:
      squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_MOVBE);
      break;
    case NACLi_POPCNT:
      squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_POPCNT);
      break;
    case NACLi_LZCNT:
      squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_LZCNT);
      break;
    case NACLi_SSSE3:
      squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSSE3);
      break;
    case NACLi_3DNOW:
      squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_3DNOW);
      break;
    case NACLi_E3DNOW:
      squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_E3DNOW);
      break;
    case NACLi_SSE2x:
      /* This case requires CPUID checking code */
      /* Note: DATA16 prefix required. The generated table
       * for group 14 (which the only 2 SSE2x instructions are in),
       * allows instructions with and without a 66 prefix. However,
       * the SSE2x instructions psrldq and pslldq are only allowed
       * with the 66 prefix. Hence, this code has been added to
       * do this check.
       */
      if (!(dinst->inst.opcode_prefixmask & kPrefixDATA16)) {
        NCBadInstructionError(dinst, "Bad prefix usage");
        NCStatsBadPrefix(vstate);
      }
      squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE2);
      break;

    case NACLi_RETURN:
      NCBadInstructionError(dinst, "ret instruction (not allowed)");
      NCStatsReturn(vstate);
      /* ... and fall through to illegal instruction code */
    case NACLi_EMMX:
      /* EMMX needs to be supported someday but isn't ready yet. */
    case NACLi_INVALID:
    case NACLi_ILLEGAL:
    case NACLi_SYSTEM:
    case NACLi_RDMSR:
    case NACLi_RDTSCP:
    case NACLi_SYSCALL:
    case NACLi_SYSENTER:
    case NACLi_LONGMODE:
    case NACLi_SVM:
    case NACLi_OPINMRM:
    case NACLi_3BYTE:
    case NACLi_CMPXCHG16B: {
        NCBadInstructionError(dinst, "Illegal instruction");
        NCStatsIllegalInst(vstate);
        break;
      }
    case NACLi_UNDEFINED: {
        NCBadInstructionError(dinst, "Undefined instruction");
        NCStatsIllegalInst(vstate);
        NCStatsInternalError(vstate);
        break;
      }
    default:
      NCBadInstructionError(dinst, "Undefined instruction type");
      NCStatsInternalError(vstate);
      break;
  }
  if (squashme) {
    if (vstate->readonly_text) {
      NCBadInstructionError(dinst,
                            "Illegal instruction for fixed-feature CPU mode");
      NCStatsIllegalInst(vstate);
    } else {
      NCStubOutMem(vstate, dinst->dstate->memory.mpc,
                   dinst->dstate->memory.read_length);
    }
  }
  return TRUE;
}
void ValidateInst(const struct NCDecoderState *mstate) {
  CPUFeatures *cpufeatures;
  int squashme = 0;

  /*  dprint(("ValidateInst(%x, %x) at %x\n",
      (uint32_t)mstate, (uint32_t)mstate->vstate, mstate->inst.vaddr)); */
  if (mstate == NULL) return;
  if (mstate->vstate == NULL) return;
  OpcodeHisto(mstate->inst.maddr[mstate->inst.prefixbytes],
              mstate->vstate);
  RememberIP(mstate->inst.vaddr, mstate->vstate);
  cpufeatures = &(mstate->vstate->cpufeatures);
  do {
    if (mstate->inst.prefixbytes == 0) break;
    if (mstate->inst.prefixbytes <= kMaxValidPrefixBytes) {
      if (mstate->inst.hasopbyte2) {
        if (mstate->inst.prefixmask & kPrefixLOCK) {
          /* For two byte opcodes, check for use of the lock prefix.   */
          if (mstate->opinfo->insttype == NACLi_386L) break;
          if (mstate->opinfo->insttype == NACLi_CMPXCHG8B) break;
        } else {
          /* Other prefixes checks are encoded in the two-byte tables. */
          break;
        }
      } else {
        /* one byte opcode */
        if ((mstate->inst.prefixmask &
             BadPrefixMask[mstate->opinfo->insttype]) == 0) break;
      }
    } else if ((mstate->inst.prefixbytes == 2) &&
               (mstate->inst.prefixmask == (kPrefixLOCK | kPrefixDATA16))) {
      /* Special case of lock on short integer, if instruction allows lock. */
      if (mstate->opinfo->insttype == NACLi_386L) break;
    }
    BadInstructionError(mstate, "Bad prefix usage");
    Stats_BadPrefix(mstate->vstate);
  } while (0);
  if ((size_t) (mstate->inst.length - mstate->inst.prefixbytes)
      > kMaxValidInstLength) {
    BadInstructionError(mstate, "Instruction too long");
    Stats_BadInstLength(mstate->vstate);
  }
  switch (mstate->opinfo->insttype) {
    case NACLi_386:
    case NACLi_386L:
    case NACLi_386R:
    case NACLi_386RE:
      break;
    case NACLi_JMP8:
      ValidateJmp8(mstate);
      break;
    case NACLi_JMPZ:
      ValidateJmpz(mstate);
      break;
    case NACLi_INDIRECT:
      ValidateIndirect5(mstate);
      break;
    case NACLi_X87:
      squashme = (!cpufeatures->f_x87);
      break;
    case NACLi_SFENCE_CLFLUSH:
      squashme = ValidateSFenceClFlush(mstate);
      break;
    case NACLi_CMPXCHG8B:
      squashme = (!cpufeatures->f_CX8);
      break;
    case NACLi_CMOV:
      squashme = (!cpufeatures->f_CMOV);
      break;
    case NACLi_FCMOV:
      squashme = (!(cpufeatures->f_CMOV && cpufeatures->f_x87));
      break;
    case NACLi_RDTSC:
      squashme = (!cpufeatures->f_TSC);
      break;
    case NACLi_MMX:
      squashme = (!cpufeatures->f_MMX);
      break;
    case NACLi_MMXSSE2:
      /* Note: We accept these instructions if either MMX or SSE2 bits */
      /* are set, in case MMX instructions go away someday...          */
      squashme = (!(cpufeatures->f_MMX || cpufeatures->f_SSE2));
      break;
    case NACLi_SSE:
      squashme = (!cpufeatures->f_SSE);
      break;
    case NACLi_SSE2:
      squashme = (!cpufeatures->f_SSE2);
      break;
    case NACLi_SSE3:
      squashme = (!cpufeatures->f_SSE3);
      break;
    case NACLi_SSE4A:
      squashme = (!cpufeatures->f_SSE4A);
      break;
    case NACLi_SSE41:
      squashme = (!cpufeatures->f_SSE41);
      break;
    case NACLi_SSE42:
      squashme = (!cpufeatures->f_SSE42);
      break;
    case NACLi_MOVBE:
      squashme = (!cpufeatures->f_MOVBE);
      break;
    case NACLi_POPCNT:
      squashme = (!cpufeatures->f_POPCNT);
      break;
    case NACLi_LZCNT:
      squashme = (!cpufeatures->f_LZCNT);
      break;
    case NACLi_SSSE3:
      squashme = (!cpufeatures->f_SSSE3);
      break;
    case NACLi_3DNOW:
      squashme = (!cpufeatures->f_3DNOW);
      break;
    case NACLi_E3DNOW:
      squashme = (!cpufeatures->f_E3DNOW);
      break;
    case NACLi_SSE2x:
      /* This case requires CPUID checking code */
      /* DATA16 prefix required */
      if (!(mstate->inst.prefixmask & kPrefixDATA16)) {
        BadInstructionError(mstate, "Bad prefix usage");
        Stats_BadPrefix(mstate->vstate);
      }
      squashme = (!cpufeatures->f_SSE2);
      break;

    case NACLi_RETURN:
      BadInstructionError(mstate, "ret instruction (not allowed)");
      Stats_Return(mstate->vstate);
      /* ... and fall through to illegal instruction code */
    case NACLi_EMMX:
      /* EMMX needs to be supported someday but isn't ready yet. */
    case NACLi_INVALID:
    case NACLi_ILLEGAL:
    case NACLi_SYSTEM:
    case NACLi_RDMSR:
    case NACLi_RDTSCP:
    case NACLi_SYSCALL:
    case NACLi_SYSENTER:
    case NACLi_LONGMODE:
    case NACLi_SVM:
    case NACLi_OPINMRM:
    case NACLi_3BYTE:
    case NACLi_CMPXCHG16B: {
        /* uint8_t *opcode = mstate->inst.maddr + mstate->inst.prefixbytes; */
        BadInstructionError(mstate, "Illegal instruction");
        Stats_IllegalInst(mstate->vstate);
        break;
      }
    case NACLi_UNDEFINED: {
        /* uint8_t *opcode = mstate->inst.maddr + mstate->inst.prefixbytes; */
        BadInstructionError(mstate, "Undefined instruction");
        Stats_IllegalInst(mstate->vstate);
        Stats_InternalError(mstate->vstate);
        break;
      }
    default:
      BadInstructionError(mstate, "Undefined instruction type");
      Stats_InternalError(mstate->vstate);
      break;
  }
  if (squashme) memset(mstate->inst.maddr, kNaClFullStop, mstate->inst.length);
}