[PATCH] x86emul/fuzz: sanitize CR4 values
Jan Beulich <[email protected]>
| Newsgroups | org.xenproject.lists.xen-devel |
|---|---|
| Message-ID | <[email protected]> |
While the CPU policy is obtained from hardware, the CRn values to start with are taken from fuzzed input. Since most CR4 bits can only be set when the respective feature is indicated as available by CPUID, the emulator often only checks the CR4 bit. Without sanitization, assertions like the one in emul_test_read_xcr() (checking XSAVE support) could therefore trigger. Omit most paging-only bits from sanitization, as the core emulator doesn't itself walk page tables. LA57 wants checking for the bit being used by CANONICALIZE_MAYBE(). Reported-by: Andrew Mbugua <[email protected]> Signed-off-by: Jan Beulich <[email protected]> --- For this to have the overall intended effect, the previously submitted https://lists.xen.org/archives/html/xen-devel/2026-08/msg01018.html also need including. UINTR is omitted, as the feature reportedly is about to be deprecated by Intel, and hence we may never add support for it to the emulator. (We also don't have X86_CR4_UINTR in x86-defns.h.) Checks like the one for VMXE, SMXE, CET, and FRED are forward-looking, as the emulator is yet to gain support for those. --- a/tools/fuzz/x86_instruction_emulator/fuzz-emul.c +++ b/tools/fuzz/x86_instruction_emulator/fuzz-emul.c @@ -825,6 +825,58 @@ static void sanitize_input(struct x86_em regs->entry_vector = 0; /* + * Most CR4 bits can only be set when corresponding CPUID bits are set. + * (In such cases the emulator may only check the CR4 bit.) + */ + if ( !cpu_policy.basic.vme ) + c->cr[4] &= ~(X86_CR4_VME | X86_CR4_PVI); + + if ( !cpu_policy.basic.tsc ) + c->cr[4] &= ~X86_CR4_TSD; + + if ( !cpu_policy.basic.de ) + c->cr[4] &= ~X86_CR4_DE; + + if ( !cpu_policy.basic.fxsr ) + c->cr[4] &= ~X86_CR4_OSFXSR; + + if ( !cpu_policy.basic.sse ) + c->cr[4] &= ~X86_CR4_OSXMMEXCPT; + + if ( !cpu_policy.feat.umip ) + c->cr[4] &= ~X86_CR4_UMIP; + + if ( !cpu_policy.feat.la57 ) + c->cr[4] &= ~X86_CR4_LA57; + + if ( !cpu_policy.basic.vmx ) + c->cr[4] &= ~X86_CR4_VMXE; + + if ( !cpu_policy.basic.smx ) + c->cr[4] &= ~X86_CR4_SMXE; + + if ( !cpu_policy.feat.fsgsbase ) + c->cr[4] &= ~X86_CR4_FSGSBASE; + + if ( !cpu_policy.basic.pcid ) + c->cr[4] &= ~X86_CR4_PCIDE; + + if ( !cpu_policy.basic.xsave || !cpu_has_xsave ) + c->cr[4] &= ~X86_CR4_OSXSAVE; + + if ( !cpu_policy.feat.pku ) + c->cr[4] &= ~X86_CR4_PKE; + + if ( !cpu_policy.feat.cet_ss && !cpu_policy.feat.cet_ibt ) + c->cr[4] &= ~X86_CR4_CET; + + if ( !cpu_policy.feat.pks ) + c->cr[4] &= ~X86_CR4_PKS; + + if ( !cpu_policy.feat.fred ) + c->cr[4] &= ~X86_CR4_FRED; + + /* * For both RIP and RSP make sure we test with canonical values in at * least a fair number of cases. As all other registers aren't tied to * special addressing purposes, leave everything else alone. @@ -839,10 +891,14 @@ static void sanitize_input(struct x86_em if ( c->cr[0] & X86_CR0_PG ) c->cr[0] |= X86_CR0_PE; - /* EFLAGS.VM not available in long mode */ + /* EFLAGS.VM not available in long mode, but CR4.PAE is required. */ if ( long_mode_active(ctxt) ) + { regs->rflags &= ~X86_EFLAGS_VM; + c->cr[4] |= X86_CR4_PAE; + } + /* EFLAGS.VM implies 16-bit mode */ if ( regs->rflags & X86_EFLAGS_VM ) { @@ -862,12 +918,63 @@ static bool check_state(struct x86_emula const struct fuzz_corpus *c = s->corpus; const struct cpu_user_regs *regs = &c->regs; - if ( long_mode_active(ctxt) && !(c->cr[0] & X86_CR0_PG) ) + if ( long_mode_active(ctxt) && + (!(c->cr[0] & X86_CR0_PG) || !(c->cr[4] & X86_CR4_PAE)) ) return false; if ( (c->cr[0] & X86_CR0_PG) && !(c->cr[0] & X86_CR0_PE) ) return false; + if ( (c->cr[4] & (X86_CR4_VME | X86_CR4_PVI)) && !cpu_policy.basic.vme ) + return false; + + if ( (c->cr[4] & X86_CR4_TSD) && !cpu_policy.basic.tsc ) + return false; + + if ( (c->cr[4] & X86_CR4_DE) && !cpu_policy.basic.de ) + return false; + + if ( (c->cr[4] & X86_CR4_OSFXSR) && !cpu_policy.basic.fxsr ) + return false; + + if ( (c->cr[4] & X86_CR4_OSXMMEXCPT) && !cpu_policy.basic.sse ) + return false; + + if ( (c->cr[4] & X86_CR4_UMIP) && !cpu_policy.feat.umip ) + return false; + + if ( (c->cr[4] & X86_CR4_LA57) && !cpu_policy.feat.la57 ) + return false; + + if ( (c->cr[4] & X86_CR4_VMXE) && !cpu_policy.basic.vmx ) + return false; + + if ( (c->cr[4] & X86_CR4_SMXE) && !cpu_policy.basic.smx ) + return false; + + if ( (c->cr[4] & X86_CR4_FSGSBASE) && !cpu_policy.feat.fsgsbase ) + return false; + + if ( (c->cr[4] & X86_CR4_PCIDE) && !cpu_policy.basic.pcid ) + return false; + + if ( (c->cr[4] & X86_CR4_OSXSAVE) && + (!cpu_policy.basic.xsave || !cpu_has_xsave) ) + return false; + + if ( (c->cr[4] & X86_CR4_PKE) && !cpu_policy.feat.pku ) + return false; + + if ( (c->cr[4] & X86_CR4_CET) && + !cpu_policy.feat.cet_ss && !cpu_policy.feat.cet_ibt ) + return false; + + if ( (c->cr[4] & X86_CR4_PKS) && !cpu_policy.feat.pks ) + return false; + + if ( (c->cr[4] & X86_CR4_FRED) && !cpu_policy.feat.fred ) + return false; + if ( (regs->rflags & X86_EFLAGS_VM) && (c->segments[x86_seg_cs].db || c->segments[x86_seg_ss].db) ) return false;