diff -Nru xen-4.4.2/debian/changelog xen-4.4.2/debian/changelog --- xen-4.4.2/debian/changelog 2016-06-09 13:12:35.000000000 +0000 +++ xen-4.4.2/debian/changelog 2016-10-06 13:59:42.000000000 +0000 @@ -1,3 +1,22 @@ +xen (4.4.2-0ubuntu0.14.04.7) trusty-security; urgency=low + + * Applying Xen Security Advisories: + - CVE-2016-6258 / XSA-182 + * x86/pv: Remove unsafe bits from the mod_l?_entry() fastpath + - CVE-2016-5403 / XSA-184 + * virtio: error out if guest exceeds virtqueue size + - CVE-2016-7092 / XSA-185 + * x86/32on64: don't allow recursive page tables from L3 + - CVE-2016-7094 / XSA-187 + * x86/shadow: Avoid overflowing sh_ctxt->seg_reg[] + * x86/segment: Bounds check accesses to emulation ctxt->seg_reg[] + - CVE-2016-7154 / XSA-188 + * evtchn-fifo: prevent use after free + - CVE-2016-7777 / XSA-190 + * x86emul: honor guest CR0.TS and CR0.EM + + -- Stefan Bader Thu, 06 Oct 2016 15:56:51 +0200 + xen (4.4.2-0ubuntu0.14.04.6) trusty-security; urgency=low * Applying Xen Security Advisories: diff -Nru xen-4.4.2/debian/patches/series xen-4.4.2/debian/patches/series --- xen-4.4.2/debian/patches/series 2016-06-09 13:11:49.000000000 +0000 +++ xen-4.4.2/debian/patches/series 2016-10-06 15:51:25.000000000 +0000 @@ -179,3 +179,10 @@ xsa179-qemut-4.4-0005-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch xsa180-qemut.patch xsa181-4.4.patch +xsa182-4.5.patch +xsa184-qemut-master.patch +xsa185.patch +xsa187-4.7-0001-x86-shadow-Avoid-overflowing-sh_ctxt-seg.patch +xsa187-4.4-0002-x86-segment-Bounds-check-accesses-to-emulation-ctx.patch +xsa188.patch +xsa190-4.5.patch diff -Nru xen-4.4.2/debian/patches/xsa182-4.5.patch xen-4.4.2/debian/patches/xsa182-4.5.patch --- xen-4.4.2/debian/patches/xsa182-4.5.patch 1970-01-01 00:00:00.000000000 +0000 +++ xen-4.4.2/debian/patches/xsa182-4.5.patch 2016-10-06 14:01:23.000000000 +0000 @@ -0,0 +1,102 @@ +From 798c1498f764bfaa7b0b955bab40b01b0610d372 Mon Sep 17 00:00:00 2001 +From: Andrew Cooper +Date: Mon, 11 Jul 2016 14:32:03 +0100 +Subject: [PATCH] x86/pv: Remove unsafe bits from the mod_l?_entry() fastpath + +All changes in writeability and cacheability must go through full +re-validation. + +Rework the logic as a whitelist, to make it clearer to follow. + +This is XSA-182 + +Reported-by: Jérémie Boutoille +Signed-off-by: Andrew Cooper +Reviewed-by: Tim Deegan +--- + xen/arch/x86/mm.c | 28 ++++++++++++++++------------ + xen/include/asm-x86/page.h | 1 + + 2 files changed, 17 insertions(+), 12 deletions(-) + +diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c +index b4c4fa4..a68a1ab 100644 +--- a/xen/arch/x86/mm.c ++++ b/xen/arch/x86/mm.c +@@ -1695,6 +1695,14 @@ static inline int update_intpte(intpte_t *p, + _t ## e_get_intpte(_o), _t ## e_get_intpte(_n), \ + (_m), (_v), (_ad)) + ++/* ++ * PTE flags that a guest may change without re-validating the PTE. ++ * All other bits affect translation, caching, or Xen's safety. ++ */ ++#define FASTPATH_FLAG_WHITELIST \ ++ (_PAGE_NX_BIT | _PAGE_AVAIL_HIGH | _PAGE_AVAIL | _PAGE_GLOBAL | \ ++ _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_USER) ++ + /* Update the L1 entry at pl1e to new value nl1e. */ + static int mod_l1_entry(l1_pgentry_t *pl1e, l1_pgentry_t nl1e, + unsigned long gl1mfn, int preserve_ad, +@@ -1735,9 +1743,8 @@ static int mod_l1_entry(l1_pgentry_t *pl1e, l1_pgentry_t nl1e, + return -EINVAL; + } + +- /* Fast path for identical mapping, r/w, presence, and cachability. */ +- if ( !l1e_has_changed(ol1e, nl1e, +- PAGE_CACHE_ATTRS | _PAGE_RW | _PAGE_PRESENT) ) ++ /* Fast path for sufficiently-similar mappings. */ ++ if ( !l1e_has_changed(ol1e, nl1e, ~FASTPATH_FLAG_WHITELIST) ) + { + adjust_guest_l1e(nl1e, pt_dom); + if ( UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, pt_vcpu, +@@ -1819,11 +1826,8 @@ static int mod_l2_entry(l2_pgentry_t *pl2e, + return -EINVAL; + } + +- /* Fast path for identical mapping and presence. */ +- if ( !l2e_has_changed(ol2e, nl2e, +- unlikely(opt_allow_superpage) +- ? _PAGE_PSE | _PAGE_RW | _PAGE_PRESENT +- : _PAGE_PRESENT) ) ++ /* Fast path for sufficiently-similar mappings. */ ++ if ( !l2e_has_changed(ol2e, nl2e, ~FASTPATH_FLAG_WHITELIST) ) + { + adjust_guest_l2e(nl2e, d); + if ( UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, pfn, vcpu, preserve_ad) ) +@@ -1888,8 +1892,8 @@ static int mod_l3_entry(l3_pgentry_t *pl3e, + return -EINVAL; + } + +- /* Fast path for identical mapping and presence. */ +- if ( !l3e_has_changed(ol3e, nl3e, _PAGE_PRESENT) ) ++ /* Fast path for sufficiently-similar mappings. */ ++ if ( !l3e_has_changed(ol3e, nl3e, ~FASTPATH_FLAG_WHITELIST) ) + { + adjust_guest_l3e(nl3e, d); + rc = UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, pfn, vcpu, preserve_ad); +@@ -1952,8 +1956,8 @@ static int mod_l4_entry(l4_pgentry_t *pl4e, + return -EINVAL; + } + +- /* Fast path for identical mapping and presence. */ +- if ( !l4e_has_changed(ol4e, nl4e, _PAGE_PRESENT) ) ++ /* Fast path for sufficiently-similar mappings. */ ++ if ( !l4e_has_changed(ol4e, nl4e, ~FASTPATH_FLAG_WHITELIST) ) + { + adjust_guest_l4e(nl4e, d); + rc = UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, pfn, vcpu, preserve_ad); +diff --git a/xen/include/asm-x86/page.h b/xen/include/asm-x86/page.h +index 6dc9646..03c024c 100644 +--- a/xen/include/asm-x86/page.h ++++ b/xen/include/asm-x86/page.h +@@ -308,6 +308,7 @@ void efi_update_l4_pgtable(unsigned int l4idx, l4_pgentry_t); + #define _PAGE_AVAIL2 _AC(0x800,U) + #define _PAGE_AVAIL _AC(0xE00,U) + #define _PAGE_PSE_PAT _AC(0x1000,U) ++#define _PAGE_AVAIL_HIGH (_AC(0x7ff, U) << 12) + /* non-architectural flags */ + #define _PAGE_PAGED 0x2000U + #define _PAGE_SHARED 0x4000U +-- +2.1.4 + diff -Nru xen-4.4.2/debian/patches/xsa184-qemut-master.patch xen-4.4.2/debian/patches/xsa184-qemut-master.patch --- xen-4.4.2/debian/patches/xsa184-qemut-master.patch 1970-01-01 00:00:00.000000000 +0000 +++ xen-4.4.2/debian/patches/xsa184-qemut-master.patch 2016-10-06 14:02:21.000000000 +0000 @@ -0,0 +1,43 @@ +From 17d8c4e47dfb41cb6778520ff2eab7a11fe12dfd Mon Sep 17 00:00:00 2001 +From: P J P +Date: Tue, 26 Jul 2016 15:31:59 +0100 +Subject: [PATCH] virtio: error out if guest exceeds virtqueue size + +A broken or malicious guest can submit more requests than the virtqueue +size permits. + +The guest can submit requests without bothering to wait for completion +and is therefore not bound by virtqueue size. This requires reusing +vring descriptors in more than one request, which is incorrect but +possible. Processing a request allocates a VirtQueueElement and +therefore causes unbounded memory allocation controlled by the guest. + +Exit with an error if the guest provides more requests than the +virtqueue size permits. This bounds memory allocation and makes the +buggy guest visible to the user. + +Reported-by: Zhenhao Hong +Signed-off-by: Stefan Hajnoczi +--- + hw/virtio.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/qemu/hw/virtio.c b/qemu/hw/virtio.c +index c26feff..42897bf 100644 +--- a/qemu/hw/virtio.c ++++ b/qemu/hw/virtio.c +@@ -421,6 +421,11 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) + /* When we start there are none of either input nor output. */ + elem->out_num = elem->in_num = 0; + ++ if (vq->inuse >= vq->vring.num) { ++ fprintf(stderr, "Virtqueue size exceeded"); ++ exit(1); ++ } ++ + i = head = virtqueue_get_head(vq, vq->last_avail_idx++); + do { + struct iovec *sg; +-- +2.1.4 + diff -Nru xen-4.4.2/debian/patches/xsa185.patch xen-4.4.2/debian/patches/xsa185.patch --- xen-4.4.2/debian/patches/xsa185.patch 1970-01-01 00:00:00.000000000 +0000 +++ xen-4.4.2/debian/patches/xsa185.patch 2016-10-06 14:02:50.000000000 +0000 @@ -0,0 +1,38 @@ +From 30aba4992b18245c436f16df7326a16c01a51570 Mon Sep 17 00:00:00 2001 +From: Jan Beulich +Date: Mon, 8 Aug 2016 10:58:12 +0100 +Subject: x86/32on64: don't allow recursive page tables from L3 + +L3 entries are special in PAE mode, and hence can't reasonably be used +for setting up recursive (and hence linear) page table mappings. Since +abuse is possible when the guest in fact gets run on 4-level page +tables, this needs to be excluded explicitly. + +This is XSA-185. + +Reported-by: Jérémie Boutoille +Reported-by: 栾尚聪(好风) +Signed-off-by: Jan Beulich +Reviewed-by: Andrew Cooper +--- + xen/arch/x86/mm.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c +index 109b8be..69b8b8d 100644 +--- a/xen/arch/x86/mm.c ++++ b/xen/arch/x86/mm.c +@@ -1122,7 +1122,9 @@ get_page_from_l3e( + + rc = get_page_and_type_from_pagenr( + l3e_get_pfn(l3e), PGT_l2_page_table, d, partial, 1); +- if ( unlikely(rc == -EINVAL) && get_l3_linear_pagetable(l3e, pfn, d) ) ++ if ( unlikely(rc == -EINVAL) && ++ !is_pv_32bit_domain(d) && ++ get_l3_linear_pagetable(l3e, pfn, d) ) + rc = 0; + + return rc; +-- +2.1.4 + diff -Nru xen-4.4.2/debian/patches/xsa187-4.4-0002-x86-segment-Bounds-check-accesses-to-emulation-ctx.patch xen-4.4.2/debian/patches/xsa187-4.4-0002-x86-segment-Bounds-check-accesses-to-emulation-ctx.patch --- xen-4.4.2/debian/patches/xsa187-4.4-0002-x86-segment-Bounds-check-accesses-to-emulation-ctx.patch 1970-01-01 00:00:00.000000000 +0000 +++ xen-4.4.2/debian/patches/xsa187-4.4-0002-x86-segment-Bounds-check-accesses-to-emulation-ctx.patch 2016-10-06 15:51:46.000000000 +0000 @@ -0,0 +1,148 @@ +From: Andrew Cooper +Subject: x86/segment: Bounds check accesses to emulation ctxt->seg_reg[] + +HVM HAP codepaths have space for all segment registers in the seg_reg[] +cache (with x86_seg_none still risking an array overrun), while the shadow +codepaths only have space for the user segments. + +Range check the input segment of *_get_seg_reg() against the size of the array +used to cache the results, to avoid overruns in the case that the callers +don't filter their input suitably. + +Subsume the is_x86_user_segment(seg) checks from the shadow code, which were +an incomplete attempt at range checking, and are now superceeded. Make +hvm_get_seg_reg() static, as it is not used outside of shadow/common.c + +No functional change, but far easier to reason that no overflow is possible. + +Reported-by: Andrew Cooper +Signed-off-by: Andrew Cooper +Acked-by: Tim Deegan +Acked-by: Jan Beulich + +Index: xen-4.4.2/xen/arch/x86/hvm/emulate.c +=================================================================== +--- xen-4.4.2.orig/xen/arch/x86/hvm/emulate.c 2016-10-06 17:51:37.120009197 +0200 ++++ xen-4.4.2/xen/arch/x86/hvm/emulate.c 2016-10-06 17:51:37.116009197 +0200 +@@ -424,6 +424,8 @@ static int hvmemul_virtual_to_linear( + *reps = min_t(unsigned long, *reps, 4096); + + reg = hvmemul_get_seg_reg(seg, hvmemul_ctxt); ++ if ( IS_ERR(reg) ) ++ return -PTR_ERR(reg); + + if ( (hvmemul_ctxt->ctxt.regs->eflags & X86_EFLAGS_DF) && (*reps > 1) ) + { +@@ -908,6 +910,10 @@ static int hvmemul_read_segment( + struct hvm_emulate_ctxt *hvmemul_ctxt = + container_of(ctxt, struct hvm_emulate_ctxt, ctxt); + struct segment_register *sreg = hvmemul_get_seg_reg(seg, hvmemul_ctxt); ++ ++ if ( IS_ERR(sreg) ) ++ return -PTR_ERR(sreg); ++ + memcpy(reg, sreg, sizeof(struct segment_register)); + return X86EMUL_OKAY; + } +@@ -921,6 +927,9 @@ static int hvmemul_write_segment( + container_of(ctxt, struct hvm_emulate_ctxt, ctxt); + struct segment_register *sreg = hvmemul_get_seg_reg(seg, hvmemul_ctxt); + ++ if ( IS_ERR(sreg) ) ++ return -PTR_ERR(sreg); ++ + memcpy(sreg, reg, sizeof(struct segment_register)); + __set_bit(seg, &hvmemul_ctxt->seg_reg_dirty); + +@@ -1284,10 +1293,17 @@ void hvm_emulate_writeback( + } + } + ++/* ++ * Callers which pass a known in-range x86_segment can rely on the return ++ * pointer being valid. Other callers must explicitly check for errors. ++ */ + struct segment_register *hvmemul_get_seg_reg( + enum x86_segment seg, + struct hvm_emulate_ctxt *hvmemul_ctxt) + { ++ if ( seg < 0 || seg >= ARRAY_SIZE(hvmemul_ctxt->seg_reg) ) ++ return ERR_PTR(-X86EMUL_UNHANDLEABLE); ++ + if ( !__test_and_set_bit(seg, &hvmemul_ctxt->seg_reg_accessed) ) + hvm_get_segment_register(current, seg, &hvmemul_ctxt->seg_reg[seg]); + return &hvmemul_ctxt->seg_reg[seg]; +Index: xen-4.4.2/xen/arch/x86/mm/shadow/common.c +=================================================================== +--- xen-4.4.2.orig/xen/arch/x86/mm/shadow/common.c 2016-10-06 17:51:37.120009197 +0200 ++++ xen-4.4.2/xen/arch/x86/mm/shadow/common.c 2016-10-06 17:51:37.116009197 +0200 +@@ -120,10 +120,19 @@ __initcall(shadow_audit_key_init); + /* x86 emulator support for the shadow code + */ + ++/* ++ * Callers which pass a known in-range x86_segment can rely on the return ++ * pointer being valid. Other callers must explicitly check for errors. ++ */ + struct segment_register *hvm_get_seg_reg( + enum x86_segment seg, struct sh_emulate_ctxt *sh_ctxt) + { +- struct segment_register *seg_reg = &sh_ctxt->seg_reg[seg]; ++ struct segment_register *seg_reg; ++ ++ if ( seg < 0 || seg >= ARRAY_SIZE(sh_ctxt->seg_reg) ) ++ return ERR_PTR(-X86EMUL_UNHANDLEABLE); ++ ++ seg_reg = &sh_ctxt->seg_reg[seg]; + if ( !__test_and_set_bit(seg, &sh_ctxt->valid_seg_regs) ) + hvm_get_segment_register(current, seg, seg_reg); + return seg_reg; +@@ -140,14 +149,9 @@ static int hvm_translate_linear_addr( + struct segment_register *reg; + int okay; + +- /* +- * Can arrive here with non-user segments. However, no such cirucmstance +- * is part of a legitimate pagetable update, so fail the emulation. +- */ +- if ( !is_x86_user_segment(seg) ) +- return X86EMUL_UNHANDLEABLE; +- + reg = hvm_get_seg_reg(seg, sh_ctxt); ++ if ( IS_ERR(reg) ) ++ return -PTR_ERR(reg); + + okay = hvm_virtual_to_linear_addr( + seg, reg, offset, bytes, access_type, sh_ctxt->ctxt.addr_size, paddr); +@@ -249,9 +253,6 @@ hvm_emulate_write(enum x86_segment seg, + unsigned long addr; + int rc; + +- if ( !is_x86_user_segment(seg) ) +- return X86EMUL_UNHANDLEABLE; +- + /* How many emulations could we save if we unshadowed on stack writes? */ + if ( seg == x86_seg_ss ) + perfc_incr(shadow_fault_emulate_stack); +@@ -279,9 +280,6 @@ hvm_emulate_cmpxchg(enum x86_segment seg + unsigned long addr, old[2], new[2]; + int rc; + +- if ( !is_x86_user_segment(seg) ) +- return X86EMUL_UNHANDLEABLE; +- + rc = hvm_translate_linear_addr( + seg, offset, bytes, hvm_access_write, sh_ctxt, &addr); + if ( rc ) +Index: xen-4.4.2/xen/include/asm-x86/hvm/emulate.h +=================================================================== +--- xen-4.4.2.orig/xen/include/asm-x86/hvm/emulate.h 2016-10-06 17:51:37.120009197 +0200 ++++ xen-4.4.2/xen/include/asm-x86/hvm/emulate.h 2016-10-06 17:51:37.116009197 +0200 +@@ -13,6 +13,7 @@ + #define __ASM_X86_HVM_EMULATE_H__ + + #include ++#include + #include + + struct hvm_emulate_ctxt { diff -Nru xen-4.4.2/debian/patches/xsa187-4.7-0001-x86-shadow-Avoid-overflowing-sh_ctxt-seg.patch xen-4.4.2/debian/patches/xsa187-4.7-0001-x86-shadow-Avoid-overflowing-sh_ctxt-seg.patch --- xen-4.4.2/debian/patches/xsa187-4.7-0001-x86-shadow-Avoid-overflowing-sh_ctxt-seg.patch 1970-01-01 00:00:00.000000000 +0000 +++ xen-4.4.2/debian/patches/xsa187-4.7-0001-x86-shadow-Avoid-overflowing-sh_ctxt-seg.patch 2016-10-06 15:49:24.000000000 +0000 @@ -0,0 +1,42 @@ +From: Andrew Cooper +Subject: x86/shadow: Avoid overflowing sh_ctxt->seg_reg[] + +hvm_get_seg_reg() does not perform a range check on its input segment, calls +hvm_get_segment_register() and writes straight into sh_ctxt->seg_reg[]. + +x86_seg_none is outside the bounds of sh_ctxt->seg_reg[], and will hit a BUG() +in {vmx,svm}_get_segment_register(). + +HVM guests running with shadow paging can end up performing a virtual to +linear translation with x86_seg_none. This is used for addresses which are +already linear. However, none of this is a legitimate pagetable update, so +fail the emulation in such a case. + +This is XSA-187 + +Reported-by: Andrew Cooper +Signed-off-by: Andrew Cooper +Reviewed-by: Tim Deegan + +--- a/xen/arch/x86/mm/shadow/common.c ++++ b/xen/arch/x86/mm/shadow/common.c +@@ -140,9 +140,18 @@ static int hvm_translate_linear_addr( + struct sh_emulate_ctxt *sh_ctxt, + unsigned long *paddr) + { +- struct segment_register *reg = hvm_get_seg_reg(seg, sh_ctxt); ++ struct segment_register *reg; + int okay; + ++ /* ++ * Can arrive here with non-user segments. However, no such cirucmstance ++ * is part of a legitimate pagetable update, so fail the emulation. ++ */ ++ if ( !is_x86_user_segment(seg) ) ++ return X86EMUL_UNHANDLEABLE; ++ ++ reg = hvm_get_seg_reg(seg, sh_ctxt); ++ + okay = hvm_virtual_to_linear_addr( + seg, reg, offset, bytes, access_type, sh_ctxt->ctxt.addr_size, paddr); + diff -Nru xen-4.4.2/debian/patches/xsa188.patch xen-4.4.2/debian/patches/xsa188.patch --- xen-4.4.2/debian/patches/xsa188.patch 1970-01-01 00:00:00.000000000 +0000 +++ xen-4.4.2/debian/patches/xsa188.patch 2016-10-06 14:04:34.000000000 +0000 @@ -0,0 +1,23 @@ +evtchn-fifo: prevent use after free + +evtchn_fifo_init_control() calls evtchn_fifo_destroy() on an error +path, leading to cleanup_event_array() which frees d->evtchn_fifo +without also clearing the pointer. Otoh the bulk of +evtchn_fifo_init_control() is dependent on d->evtchn_fifo being NULL. + +This is XSA-188. + +Reported-by: Mikhail V Gorobets +Suggested-by: Mikhail V Gorobets +Signed-off-by: Jan Beulich + +--- a/xen/common/event_fifo.c ++++ b/xen/common/event_fifo.c +@@ -482,6 +482,7 @@ static void cleanup_event_array(struct d + for ( i = 0; i < EVTCHN_FIFO_MAX_EVENT_ARRAY_PAGES; i++ ) + unmap_guest_page(d->evtchn_fifo->event_array[i]); + xfree(d->evtchn_fifo); ++ d->evtchn_fifo = NULL; + } + + static void setup_ports(struct domain *d) diff -Nru xen-4.4.2/debian/patches/xsa190-4.5.patch xen-4.4.2/debian/patches/xsa190-4.5.patch --- xen-4.4.2/debian/patches/xsa190-4.5.patch 1970-01-01 00:00:00.000000000 +0000 +++ xen-4.4.2/debian/patches/xsa190-4.5.patch 2016-10-06 14:04:47.000000000 +0000 @@ -0,0 +1,163 @@ +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. + +Signed-off-by: Jan Beulich +Reviewed-by: Andrew Cooper + +--- a/tools/tests/x86_emulator/test_x86_emulator.c ++++ b/tools/tests/x86_emulator/test_x86_emulator.c +@@ -129,6 +129,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, +@@ -160,6 +176,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 +@@ -1192,6 +1192,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 ) +@@ -1199,7 +1200,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 +@@ -684,10 +688,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) \ +@@ -2491,8 +2530,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 +@@ -114,6 +114,7 @@ struct __packed 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) */