x86emul/fuzz: sanitize CR4 values

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 <andrewprecious388@gmail.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
This commit is contained in:
Jan Beulich committed 2026-08-26 14:14:03 +02:00
1 parent 79175b1390
commit 829d67e244
1 file changed
+109 -2
+109 -2
View File
@@ -824,6 +824,58 @@ static void sanitize_input(struct x86_emulate_ctxt *ctxt)
regs->error_code = 0;
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
@@ -839,10 +891,14 @@ static void sanitize_input(struct x86_emulate_ctxt *ctxt)
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_emulate_ctxt *ctxt)
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;
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.