Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12:Update
xen
57f3a8ee-x86emul-honor-guest-CR0-TS-and-CR0-EM....
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 57f3a8ee-x86emul-honor-guest-CR0-TS-and-CR0-EM.patch of Package xen
# Commit 3ab81e01104d7c05e239f3bd9329c4fc87a463f4 # Date 2016-10-04 14:04:46 +0100 # Author Jan Beulich <jbeulich@suse.com> # Committer Andrew Cooper <andrew.cooper3@citrix.com> x86emul: honor guest CR0.TS and CR0.EM We must not emulate any instructions accessing respective registers when either of these flags is set in the guest view of the register, or else we may do so on data not belonging to the guest's current task. Being architecturally required behavior, the logic gets placed in the instruction emulator instead of hvmemul_get_fpu(). It should be noted, though, that hvmemul_get_fpu() being the only current handler for the get_fpu() callback, we don't have an active problem with CR4: Both CR4.OSFXSR and CR4.OSXSAVE get handled as necessary by that function. This is XSA-190 / CVE-2016-7777. Signed-off-by: Jan Beulich <jbeulich@suse.com> Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com> --- a/tools/tests/x86_emulator/test_x86_emulator.c +++ b/tools/tests/x86_emulator/test_x86_emulator.c @@ -127,6 +127,22 @@ static inline uint64_t xgetbv(uint32_t x (ebx & (1U << 5)) != 0; \ }) +static int read_cr( + unsigned int reg, + unsigned long *val, + struct x86_emulate_ctxt *ctxt) +{ + /* Fake just enough state for the emulator's _get_fpu() to be happy. */ + switch ( reg ) + { + case 0: + *val = 0x00000001; /* PE */ + return X86EMUL_OKAY; + } + + return X86EMUL_UNHANDLEABLE; +} + int get_fpu( void (*exception_callback)(void *, struct cpu_user_regs *), void *exception_callback_arg, @@ -158,6 +174,7 @@ static struct x86_emulate_ops emulops = .write = write, .cmpxchg = cmpxchg, .cpuid = cpuid, + .read_cr = read_cr, .get_fpu = get_fpu, }; --- a/xen/arch/x86/hvm/emulate.c +++ b/xen/arch/x86/hvm/emulate.c @@ -1097,6 +1097,7 @@ static int hvmemul_get_fpu( switch ( type ) { case X86EMUL_FPU_fpu: + case X86EMUL_FPU_wait: break; case X86EMUL_FPU_mmx: if ( !cpu_has_mmx ) @@ -1104,7 +1105,6 @@ static int hvmemul_get_fpu( break; case X86EMUL_FPU_xmm: if ( !cpu_has_xmm || - (curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_EM) || !(curr->arch.hvm_vcpu.guest_cr[4] & X86_CR4_OSFXSR) ) return X86EMUL_UNHANDLEABLE; break; --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -373,6 +373,9 @@ typedef union { /* Control register flags. */ #define CR0_PE (1<<0) +#define CR0_MP (1<<1) +#define CR0_EM (1<<2) +#define CR0_TS (1<<3) #define CR4_TSD (1<<2) /* EFLAGS bit definitions. */ @@ -400,6 +403,7 @@ typedef union { #define EXC_OF 4 #define EXC_BR 5 #define EXC_UD 6 +#define EXC_NM 7 #define EXC_TS 10 #define EXC_NP 11 #define EXC_SS 12 @@ -679,10 +683,45 @@ static void fpu_handle_exception(void *_ regs->eip += fic->insn_bytes; } +static int _get_fpu( + enum x86_emulate_fpu_type type, + struct fpu_insn_ctxt *fic, + struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops) +{ + int rc; + + fic->exn_raised = 0; + + fail_if(!ops->get_fpu); + rc = ops->get_fpu(fpu_handle_exception, fic, type, ctxt); + + if ( rc == X86EMUL_OKAY ) + { + unsigned long cr0; + + fail_if(!ops->read_cr); + rc = ops->read_cr(0, &cr0, ctxt); + if ( rc != X86EMUL_OKAY ) + return rc; + if ( cr0 & CR0_EM ) + { + generate_exception_if(type == X86EMUL_FPU_fpu, EXC_NM, -1); + generate_exception_if(type == X86EMUL_FPU_mmx, EXC_UD, -1); + generate_exception_if(type == X86EMUL_FPU_xmm, EXC_UD, -1); + } + generate_exception_if((cr0 & CR0_TS) && + (type != X86EMUL_FPU_wait || (cr0 & CR0_MP)), + EXC_NM, -1); + } + + done: + return rc; +} + #define get_fpu(_type, _fic) \ -do{ (_fic)->exn_raised = 0; \ - fail_if(ops->get_fpu == NULL); \ - rc = ops->get_fpu(fpu_handle_exception, _fic, _type, ctxt); \ +do { \ + rc = _get_fpu(_type, _fic, ctxt, ops); \ if ( rc ) goto done; \ } while (0) #define put_fpu(_fic) \ @@ -2388,8 +2427,14 @@ x86_emulate( } case 0x9b: /* wait/fwait */ - emulate_fpu_insn("fwait"); + { + struct fpu_insn_ctxt fic = { .insn_bytes = 1 }; + + get_fpu(X86EMUL_FPU_wait, &fic); + asm volatile ( "fwait" ::: "memory" ); + put_fpu(&fic); break; + } case 0x9c: /* pushf */ src.val = _regs.eflags; --- a/xen/arch/x86/x86_emulate/x86_emulate.h +++ b/xen/arch/x86/x86_emulate/x86_emulate.h @@ -99,6 +99,7 @@ struct segment_register { /* FPU sub-types which may be requested via ->get_fpu(). */ enum x86_emulate_fpu_type { X86EMUL_FPU_fpu, /* Standard FPU coprocessor instruction set */ + X86EMUL_FPU_wait, /* WAIT/FWAIT instruction */ X86EMUL_FPU_mmx, /* MMX instruction set (%mm0-%mm7) */ X86EMUL_FPU_xmm, /* SSE instruction set (%xmm0-%xmm7/15) */ X86EMUL_FPU_ymm /* AVX/XOP instruction set (%ymm0-%ymm7/15) */
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor