void NCBadInstructionError(const struct NCDecoderInst *dinst, const char *msg) { NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate); ValidatePrintInstructionError(dinst, msg, vstate); if (vstate->do_stub_out) { NCStubOutMem(vstate, dinst->dstate->memory.mpc, dinst->dstate->memory.read_length); } }
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 NaClCpuCheck(struct NaClValidatorState* state, struct NaClInstIter* iter) { Bool squash_me = FALSE; switch (state->cur_inst->insttype) { case NACLi_X87: case NACLi_X87_FSINCOS: NaClCheckFeature(NaClCPUFeatureX86_x87, state, &squash_me); break; case NACLi_SFENCE_CLFLUSH: /* TODO(bradchen): distinguish between SFENCE and CLFLUSH */ NaClCheckFeature(NaClCPUFeatureX86_CLFLUSH, state, &squash_me); NaClCheckFeature(NaClCPUFeatureX86_FXSR, state, &squash_me); break; case NACLi_CMPXCHG8B: NaClCheckFeature(NaClCPUFeatureX86_CX8, state, &squash_me); break; case NACLi_CMPXCHG16B: NaClCheckFeature(NaClCPUFeatureX86_CX16, state, &squash_me); break; case NACLi_CMOV: NaClCheckFeature(NaClCPUFeatureX86_CMOV, state, &squash_me); break; case NACLi_FCMOV: if (!(NaClGetCPUFeatureX86(&state->cpu_features, NaClCPUFeatureX86_CMOV) && NaClGetCPUFeatureX86(&state->cpu_features, NaClCPUFeatureX86_x87))) { if (!state->cpu_checks.f_CMOV_and_x87) { NaClValidatorInstMessage( LOG_WARNING, state, state->cur_inst_state, "CPU model does not support CMOV and x87 instructions.\n"); state->cpu_checks.f_CMOV_and_x87 = TRUE; } squash_me = TRUE; } break; case NACLi_RDTSC: NaClCheckFeature(NaClCPUFeatureX86_TSC, state, &squash_me); break; case NACLi_MMX: NaClCheckFeature(NaClCPUFeatureX86_MMX, state, &squash_me); break; case NACLi_MMXSSE2: /* Note: We accept these instructions if either MMX or SSE2 bits */ /* are set, in case MMX instructions go away someday... */ if (!(NaClGetCPUFeatureX86(&state->cpu_features, NaClCPUFeatureX86_MMX) || NaClGetCPUFeatureX86(&state->cpu_features, NaClCPUFeatureX86_SSE2))) { if (!state->cpu_checks.f_MMX_or_SSE2) { NaClValidatorInstMessage( LOG_WARNING, state, state->cur_inst_state, "CPU model does not support MMX or SSE2 instructions.\n"); state->cpu_checks.f_MMX_or_SSE2 = TRUE; } } squash_me = TRUE; break; case NACLi_SSE: NaClCheckFeature(NaClCPUFeatureX86_SSE, state, &squash_me); break; case NACLi_SSE2: NaClCheckFeature(NaClCPUFeatureX86_SSE2, state, &squash_me); break; case NACLi_SSE3: NaClCheckFeature(NaClCPUFeatureX86_SSE3, state, &squash_me); break; case NACLi_SSE4A: NaClCheckFeature(NaClCPUFeatureX86_SSE4A, state, &squash_me); break; case NACLi_SSE41: NaClCheckFeature(NaClCPUFeatureX86_SSE41, state, &squash_me); break; case NACLi_SSE42: NaClCheckFeature(NaClCPUFeatureX86_SSE42, state, &squash_me); break; case NACLi_MOVBE: NaClCheckFeature(NaClCPUFeatureX86_MOVBE, state, &squash_me); break; case NACLi_POPCNT: NaClCheckFeature(NaClCPUFeatureX86_POPCNT, state, &squash_me); break; case NACLi_LZCNT: NaClCheckFeature(NaClCPUFeatureX86_LZCNT, state, &squash_me); break; case NACLi_SSSE3: NaClCheckFeature(NaClCPUFeatureX86_SSSE3, state, &squash_me); break; case NACLi_3DNOW: NaClCheckFeature(NaClCPUFeatureX86_3DNOW, state, &squash_me); break; case NACLi_E3DNOW: NaClCheckFeature(NaClCPUFeatureX86_E3DNOW, state, &squash_me); break; case NACLi_LONGMODE: /* TODO(karl): Remove this when NACLi_LONGMODE is no longer needed */ NaClCheckFeature(NaClCPUFeatureX86_LM, state, &squash_me); break; case NACLi_SSE2x: /* This case requires CPUID checking code */ /* DATA16 prefix required */ if (!(state->cur_inst_state->prefix_mask & kPrefixDATA16)) { NaClValidatorInstMessage( LOG_ERROR, state, state->cur_inst_state, "SSEx instruction must use prefix 0x66.\n"); } NaClCheckFeature(NaClCPUFeatureX86_SSE2, state, &squash_me); break; default: /* This instruction could be either legal or illegal, but if we * get here it is not CPU-dependent. */ break; } if (state->cur_inst->flags & NACL_IFLAG(LongMode)) { NaClCheckFeature(NaClCPUFeatureX86_LM, state, &squash_me); } if (squash_me) { if (state->readonly_text) { NaClValidatorInstMessage( LOG_ERROR, state, state->cur_inst_state, "Read-only text: cannot squash unsupported instruction.\n"); } else { /* Replace all bytes of the instruction with the HLT instruction. */ NCStubOutMem(state, NaClInstIterGetInstMemoryInline(iter), NaClInstStateLength(state->cur_inst_state)); } } }