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); }