diff --git a/.gitignore b/.gitignore index 8bcbc57..74488f7 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ lwip-1.3.0.tar.gz pciutils-2.2.9.tar.bz2 zlib-1.2.3.tar.gz polarssl-1.1.4-gpl.tgz -/xen-4.9.1.tar.gz +/xen-4.9.3.tar.gz diff --git a/sources b/sources index 4704816..0afee29 100644 --- a/sources +++ b/sources @@ -4,4 +4,4 @@ SHA512 (newlib-1.16.0.tar.gz) = 40eb96bbc6736a16b6399e0cdb73e853d0d90b685c967e77 SHA512 (zlib-1.2.3.tar.gz) = 021b958fcd0d346c4ba761bcf0cc40f3522de6186cf5a0a6ea34a70504ce9622b1c2626fce40675bc8282cf5f5ade18473656abc38050f72f5d6480507a2106e SHA512 (polarssl-1.1.4-gpl.tgz) = 88da614e4d3f4409c4fd3bb3e44c7587ba051e3fed4e33d526069a67e8180212e1ea22da984656f50e290049f60ddca65383e5983c0f8884f648d71f698303ad SHA512 (pciutils-2.2.9.tar.bz2) = 2b3d98d027e46d8c08037366dde6f0781ca03c610ef2b380984639e4ef39899ed8d8b8e4cd9c9dc54df101279b95879bd66bfd4d04ad07fef41e847ea7ae32b5 -SHA512 (xen-4.9.1.tar.gz) = 9d22f0aa5dcd01a1c105d17c14bce570cc597e884ddb9b4a46b80a72f647625b76ae5213cede423d0458c14e1906983595a9269bb6e6ff2e9e7e4dea840f4274 +SHA512 (xen-4.9.3.tar.gz) = 989efad2b09504ea56a887991c6741e99d9691e483434650759e6a5cfbdbf78e265ee4f34f8609252d121ada361e364b49c5293c099ba2fff1a1da9331778eb3 diff --git a/xen.spec b/xen.spec index a795ef4..8c9d124 100644 --- a/xen.spec +++ b/xen.spec @@ -49,8 +49,8 @@ Summary: Xen is a virtual machine monitor Name: xen -Version: 4.9.1 -Release: 4%{?dist} +Version: 4.9.3 +Release: 3%{?dist} Group: Development/Libraries License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ @@ -120,14 +120,9 @@ Patch76: qemu.git-041e32b8d9d076980b4e35317c0339e57ab888f1.patch Patch77: qemu.git-04bf2526ce87f21b32c9acba1c5518708c243ad0.patch Patch84: qemu.git-fec5e8c92becad223df9d972770522f64aafdb72.patch Patch85: qemu.git-e65294157d4b69393b3f819c99f4f647452b48e3.patch -Patch86: xsa246-4.9.patch -Patch87: xsa247-4.9-0001-p2m-Always-check-to-see-if-removing-a-p2m-entry-actu.patch -Patch88: xsa247-4.9-0002-p2m-Check-return-value-of-p2m_set_entry-when-decreas.patch -Patch89: xsa240-4.9-0004-x86-dont-wrongly-trigger-linear-page-table-assertion-2.patch -Patch90: xsa248.patch -Patch91: xsa249.patch -Patch92: xsa250.patch -Patch93: xsa251.patch +Patch86: xsa278-4.11.patch +Patch87: xsa282-4.9-1.patch +Patch88: xsa282-2.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root @@ -332,11 +327,6 @@ manage Xen virtual machines. %patch86 -p1 %patch87 -p1 %patch88 -p1 -%patch89 -p1 -%patch90 -p1 -%patch91 -p1 -%patch92 -p1 -%patch93 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -876,6 +866,71 @@ rm -rf %{buildroot} %endif %changelog +* Tue Nov 06 2018 Michael Young - 4.9.3-3 +- guest use of HLE constructs may lock up host [XSA-282] + +* Thu Oct 25 2018 Michael Young - 4.9.3-2 +- x86: Nested VT-x usable even when disabled [XSA-278, CVE-2018-18883] + (#1643118) + +* Tue Sep 25 2018 Michael Young - 4.9.3-1 +- update to 4.9.3 + adjust xen.use.fedora.ipxe.patch + remove patches for issues now fixed upstream + +* Wed Aug 15 2018 Michael Young - 4.9.2-7 +- L1 Terminal Fault speculative side channel patch bundle [XSA-273, + CVE-2018-3620, CVE-2018-3646] + drop patches also in the bundle, which also includes + Use of v2 grant tables may cause crash on ARM [XSA-268, CVE-2018-15469] + (#1616081) + x86: Incorrect MSR_DEBUGCTL handling lets guests enable BTS [XSA-269, + CVE-2018-15468] (#1616077) + oxenstored does not apply quota-maxentity [XSA-272, CVE-2018-15470] + (#1616080) + +* Wed Jun 27 2018 Michael Young - 4.9.2-6 +- preemption checks bypassed in x86 PV MM handling [XSA-264, CVE-2018-12891] + (#1595959) +- x86: #DB exception safety check can be triggered by a guest [XSA-265, + CVE-2018-12893] (#1595958) +- libxl fails to honour readonly flag on HVM emulated SCSI disks [XSA-266, + CVE-2018-12892] (#1595957) + +* Sat Jun 16 2018 Michael Young - 4.9.2-5 +- Speculative register leakage from lazy FPU context switching + [XSA-267, CVE-2018-3665] +- fix for change in iasl output + +* Tue May 22 2018 Michael Young - 4.9.2-4 +- Speculative Store Bypass [XSA-263, CVE-2018-3639] + (with extra patches so it applies cleanly) + +* Wed May 09 2018 Michael Young - 4.9.2-3 +- x86: mishandling of debug exceptions [XSA-260, CVE-2018-8897] + (with extra patch so it applies cleanly) +- x86 vHPET interrupt injection errors [XSA-261, CVE-2018-10982] (#1576089) +- qemu may drive Xen into unbounded loop [XSA-262, CVE-2018-10981] (#1576680) + +* Wed Apr 25 2018 Michael Young - 4.9.2-2 +- Information leak via crafted user-supplied CDROM [XSA-258] (#1571867) +- x86: PV guest may crash Xen with XPTI [XSA-259] (#1571878) + +* Wed Apr 04 2018 Michael Young - 4.9.2-1 +- update to 4.9.2 + adjust xen.use.fedora.ipxe.patch + remove patches for issues now fixed upstream + +* Tue Feb 27 2018 Michael Young - 4.9.1-5 +- add Xen page-table isolation (XPTI) mitigation + and Branch Target Injection (BTI) mitigation for XSA-254 +- DoS via non-preemptable L3/L4 pagetable freeing [XSA-252, CVE-2018-7540] + (#1549568) +- grant table v2 -> v1 transition may crash Xen [XSA-255, CVE-2018-7541] + (#1549570) +- x86 PVH guest without LAPIC may DoS the host [XSA-256, CVE-2018-7542] + (#1549572) + * Tue Dec 12 2017 Michael Young - 4.9.1-4 - another patch related to the [XSA-240, CVE-2017-15595] issue - xen: various flaws (#1525018) diff --git a/xen.use.fedora.ipxe.patch b/xen.use.fedora.ipxe.patch index 67eee5e..9bc7408 100644 --- a/xen.use.fedora.ipxe.patch +++ b/xen.use.fedora.ipxe.patch @@ -19,7 +19,7 @@ +ETHERBOOT_NICS ?= 10ec8139 8086100e - QEMU_TRADITIONAL_REVISION ?= xen-4.9.1 + QEMU_TRADITIONAL_REVISION ?= xen-4.9.3 --- xen-4.2.0/tools/firmware/Makefile.orig 2012-05-27 21:57:04.480812871 +0100 +++ xen-4.2.0/tools/firmware/Makefile 2012-06-02 19:03:52.254691484 +0100 @@ -10,7 +10,7 @@ diff --git a/xsa240-4.9-0004-x86-dont-wrongly-trigger-linear-page-table-assertion-2.patch b/xsa240-4.9-0004-x86-dont-wrongly-trigger-linear-page-table-assertion-2.patch deleted file mode 100644 index 9ad94e8..0000000 --- a/xsa240-4.9-0004-x86-dont-wrongly-trigger-linear-page-table-assertion-2.patch +++ /dev/null @@ -1,26 +0,0 @@ -From: Jan Beulich -Subject: x86: don't wrongly trigger linear page table assertion (2) - -_put_final_page_type(), when free_page_type() has exited early to allow -for preemption, should not update the time stamp, as the page continues -to retain the typ which is in the process of being unvalidated. I can't -see why the time stamp update was put on that path in the first place -(albeit it may well have been me who had put it there years ago). - -This is part of XSA-240. - -Signed-off-by: Jan Beulich -Reviewed-by: - ---- a/xen/arch/x86/mm.c -+++ b/xen/arch/x86/mm.c -@@ -2594,9 +2594,6 @@ static int _put_final_page_type(struct p - { - ASSERT((page->u.inuse.type_info & - (PGT_count_mask|PGT_validated|PGT_partial)) == 1); -- if ( !(shadow_mode_enabled(page_get_owner(page)) && -- (page->count_info & PGC_page_table)) ) -- page_set_tlbflush_timestamp(page); - wmb(); - page->u.inuse.type_info |= PGT_validated; - } diff --git a/xsa246-4.9.patch b/xsa246-4.9.patch deleted file mode 100644 index 6370a10..0000000 --- a/xsa246-4.9.patch +++ /dev/null @@ -1,74 +0,0 @@ -From: Julien Grall -Subject: x86/pod: prevent infinite loop when shattering large pages - -When populating pages, the PoD may need to split large ones using -p2m_set_entry and request the caller to retry (see ept_get_entry for -instance). - -p2m_set_entry may fail to shatter if it is not possible to allocate -memory for the new page table. However, the error is not propagated -resulting to the callers to retry infinitely the PoD. - -Prevent the infinite loop by return false when it is not possible to -shatter the large mapping. - -This is XSA-246. - -Signed-off-by: Julien Grall -Signed-off-by: Jan Beulich -Reviewed-by: George Dunlap - ---- a/xen/arch/x86/mm/p2m-pod.c -+++ b/xen/arch/x86/mm/p2m-pod.c -@@ -1071,9 +1071,8 @@ p2m_pod_demand_populate(struct p2m_domai - * NOTE: In a fine-grained p2m locking scenario this operation - * may need to promote its locking from gfn->1g superpage - */ -- p2m_set_entry(p2m, gfn_aligned, INVALID_MFN, PAGE_ORDER_2M, -- p2m_populate_on_demand, p2m->default_access); -- return 0; -+ return p2m_set_entry(p2m, gfn_aligned, INVALID_MFN, PAGE_ORDER_2M, -+ p2m_populate_on_demand, p2m->default_access); - } - - /* Only reclaim if we're in actual need of more cache. */ -@@ -1104,8 +1103,12 @@ p2m_pod_demand_populate(struct p2m_domai - - gfn_aligned = (gfn >> order) << order; - -- p2m_set_entry(p2m, gfn_aligned, mfn, order, p2m_ram_rw, -- p2m->default_access); -+ if ( p2m_set_entry(p2m, gfn_aligned, mfn, order, p2m_ram_rw, -+ p2m->default_access) ) -+ { -+ p2m_pod_cache_add(p2m, p, order); -+ goto out_fail; -+ } - - for( i = 0; i < (1UL << order); i++ ) - { -@@ -1150,13 +1153,18 @@ remap_and_retry: - BUG_ON(order != PAGE_ORDER_2M); - pod_unlock(p2m); - -- /* Remap this 2-meg region in singleton chunks */ -- /* NOTE: In a p2m fine-grained lock scenario this might -- * need promoting the gfn lock from gfn->2M superpage */ -+ /* -+ * Remap this 2-meg region in singleton chunks. See the comment on the -+ * 1G page splitting path above for why a single call suffices. -+ * -+ * NOTE: In a p2m fine-grained lock scenario this might -+ * need promoting the gfn lock from gfn->2M superpage. -+ */ - gfn_aligned = (gfn>>order)<default_access); -+ if ( p2m_set_entry(p2m, gfn_aligned, INVALID_MFN, PAGE_ORDER_4K, -+ p2m_populate_on_demand, p2m->default_access) ) -+ return -1; -+ - if ( tb_init_done ) - { - struct { diff --git a/xsa247-4.9-0001-p2m-Always-check-to-see-if-removing-a-p2m-entry-actu.patch b/xsa247-4.9-0001-p2m-Always-check-to-see-if-removing-a-p2m-entry-actu.patch deleted file mode 100644 index e86d561..0000000 --- a/xsa247-4.9-0001-p2m-Always-check-to-see-if-removing-a-p2m-entry-actu.patch +++ /dev/null @@ -1,176 +0,0 @@ -From ad208b8b7e45fb2b7c572b86c61c26412609e82d Mon Sep 17 00:00:00 2001 -From: George Dunlap -Date: Fri, 10 Nov 2017 16:53:54 +0000 -Subject: [PATCH 1/2] p2m: Always check to see if removing a p2m entry actually - worked - -The PoD zero-check functions speculatively remove memory from the p2m, -then check to see if it's completely zeroed, before putting it in the -cache. - -Unfortunately, the p2m_set_entry() calls may fail if the underlying -pagetable structure needs to change and the domain has exhausted its -p2m memory pool: for instance, if we're removing a 2MiB region out of -a 1GiB entry (in the p2m_pod_zero_check_superpage() case), or a 4k -region out of a 2MiB or larger entry (in the p2m_pod_zero_check() -case); and the return value is not checked. - -The underlying mfn will then be added into the PoD cache, and at some -point mapped into another location in the p2m. If the guest -afterwards ballons out this memory, it will be freed to the hypervisor -and potentially reused by another domain, in spite of the fact that -the original domain still has writable mappings to it. - -There are several places where p2m_set_entry() shouldn't be able to -fail, as it is guaranteed to write an entry of the same order that -succeeded before. Add a backstop of crashing the domain just in case, -and an ASSERT_UNREACHABLE() to flag up the broken assumption on debug -builds. - -While we're here, use PAGE_ORDER_2M rather than a magic constant. - -This is part of XSA-247. - -Reported-by: XXX PERSON -Signed-off-by: George Dunlap -Reviewed-by: Jan Beulich ---- -v4: -- Removed some training whitespace -v3: -- Reformat reset clause to be more compact -- Make sure to set map[i] = NULL when unmapping in case we need to bail -v2: -- Crash a domain if a p2m_set_entry we think cannot fail fails anyway. ---- - xen/arch/x86/mm/p2m-pod.c | 77 +++++++++++++++++++++++++++++++++++++---------- - 1 file changed, 61 insertions(+), 16 deletions(-) - -diff --git a/xen/arch/x86/mm/p2m-pod.c b/xen/arch/x86/mm/p2m-pod.c -index 730a48f928..f2ed751892 100644 ---- a/xen/arch/x86/mm/p2m-pod.c -+++ b/xen/arch/x86/mm/p2m-pod.c -@@ -752,8 +752,10 @@ p2m_pod_zero_check_superpage(struct p2m_domain *p2m, unsigned long gfn) - } - - /* Try to remove the page, restoring old mapping if it fails. */ -- p2m_set_entry(p2m, gfn, INVALID_MFN, PAGE_ORDER_2M, -- p2m_populate_on_demand, p2m->default_access); -+ if ( p2m_set_entry(p2m, gfn, INVALID_MFN, PAGE_ORDER_2M, -+ p2m_populate_on_demand, p2m->default_access) ) -+ goto out; -+ - p2m_tlb_flush_sync(p2m); - - /* Make none of the MFNs are used elsewhere... for example, mapped -@@ -810,9 +812,18 @@ p2m_pod_zero_check_superpage(struct p2m_domain *p2m, unsigned long gfn) - ret = SUPERPAGE_PAGES; - - out_reset: -- if ( reset ) -- p2m_set_entry(p2m, gfn, mfn0, 9, type0, p2m->default_access); -- -+ /* -+ * This p2m_set_entry() call shouldn't be able to fail, since the same order -+ * on the same gfn succeeded above. If that turns out to be false, crashing -+ * the domain should be the safest way of making sure we don't leak memory. -+ */ -+ if ( reset && p2m_set_entry(p2m, gfn, mfn0, PAGE_ORDER_2M, -+ type0, p2m->default_access) ) -+ { -+ ASSERT_UNREACHABLE(); -+ domain_crash(d); -+ } -+ - out: - gfn_unlock(p2m, gfn, SUPERPAGE_ORDER); - return ret; -@@ -869,19 +880,30 @@ p2m_pod_zero_check(struct p2m_domain *p2m, unsigned long *gfns, int count) - } - - /* Try to remove the page, restoring old mapping if it fails. */ -- p2m_set_entry(p2m, gfns[i], INVALID_MFN, PAGE_ORDER_4K, -- p2m_populate_on_demand, p2m->default_access); -+ if ( p2m_set_entry(p2m, gfns[i], INVALID_MFN, PAGE_ORDER_4K, -+ p2m_populate_on_demand, p2m->default_access) ) -+ goto skip; - - /* See if the page was successfully unmapped. (Allow one refcount - * for being allocated to a domain.) */ - if ( (mfn_to_page(mfns[i])->count_info & PGC_count_mask) > 1 ) - { -+ /* -+ * If the previous p2m_set_entry call succeeded, this one shouldn't -+ * be able to fail. If it does, crashing the domain should be safe. -+ */ -+ if ( p2m_set_entry(p2m, gfns[i], mfns[i], PAGE_ORDER_4K, -+ types[i], p2m->default_access) ) -+ { -+ ASSERT_UNREACHABLE(); -+ domain_crash(d); -+ goto out_unmap; -+ } -+ -+ skip: - unmap_domain_page(map[i]); - map[i] = NULL; - -- p2m_set_entry(p2m, gfns[i], mfns[i], PAGE_ORDER_4K, -- types[i], p2m->default_access); -- - continue; - } - } -@@ -900,12 +922,25 @@ p2m_pod_zero_check(struct p2m_domain *p2m, unsigned long *gfns, int count) - - unmap_domain_page(map[i]); - -- /* See comment in p2m_pod_zero_check_superpage() re gnttab -- * check timing. */ -- if ( j < PAGE_SIZE/sizeof(*map[i]) ) -+ map[i] = NULL; -+ -+ /* -+ * See comment in p2m_pod_zero_check_superpage() re gnttab -+ * check timing. -+ */ -+ if ( j < (PAGE_SIZE / sizeof(*map[i])) ) - { -- p2m_set_entry(p2m, gfns[i], mfns[i], PAGE_ORDER_4K, -- types[i], p2m->default_access); -+ /* -+ * If the previous p2m_set_entry call succeeded, this one shouldn't -+ * be able to fail. If it does, crashing the domain should be safe. -+ */ -+ if ( p2m_set_entry(p2m, gfns[i], mfns[i], PAGE_ORDER_4K, -+ types[i], p2m->default_access) ) -+ { -+ ASSERT_UNREACHABLE(); -+ domain_crash(d); -+ goto out_unmap; -+ } - } - else - { -@@ -929,7 +964,17 @@ p2m_pod_zero_check(struct p2m_domain *p2m, unsigned long *gfns, int count) - p2m->pod.entry_count++; - } - } -- -+ -+ return; -+ -+out_unmap: -+ /* -+ * Something went wrong, probably crashing the domain. Unmap -+ * everything and return. -+ */ -+ for ( i = 0; i < count; i++ ) -+ if ( map[i] ) -+ unmap_domain_page(map[i]); - } - - #define POD_SWEEP_LIMIT 1024 --- -2.15.0 - diff --git a/xsa247-4.9-0002-p2m-Check-return-value-of-p2m_set_entry-when-decreas.patch b/xsa247-4.9-0002-p2m-Check-return-value-of-p2m_set_entry-when-decreas.patch deleted file mode 100644 index 13737a9..0000000 --- a/xsa247-4.9-0002-p2m-Check-return-value-of-p2m_set_entry-when-decreas.patch +++ /dev/null @@ -1,109 +0,0 @@ -From d4bc7833707351a5341a6bdf04c752a028d9560d Mon Sep 17 00:00:00 2001 -From: George Dunlap -Date: Fri, 10 Nov 2017 16:53:55 +0000 -Subject: [PATCH 2/2] p2m: Check return value of p2m_set_entry() when - decreasing reservation - -If the entire range specified to p2m_pod_decrease_reservation() is marked -populate-on-demand, then it will make a single p2m_set_entry() call, -reducing its PoD entry count. - -Unfortunately, in the right circumstances, this p2m_set_entry() call -may fail. It that case, repeated calls to decrease_reservation() may -cause p2m->pod.entry_count to fall below zero, potentially tripping -over BUG_ON()s to the contrary. - -Instead, check to see if the entry succeeded, and return false if not. -The caller will then call guest_remove_page() on the gfns, which will -return -EINVAL upon finding no valid memory there to return. - -Unfortunately if the order > 0, the entry may have partially changed. -A domain_crash() is probably the safest thing in that case. - -Other p2m_set_entry() calls in the same function should be fine, -because they are writing the entry at its current order. Nonetheless, -check the return value and crash if our assumption turns otu to be -wrong. - -This is part of XSA-247. - -Reported-by: XXX PERSON -Signed-off-by: George Dunlap -Reviewed-by: Jan Beulich ---- -v2: Crash the domain if we're not sure it's safe (or if we think it -can't happen) ---- - xen/arch/x86/mm/p2m-pod.c | 42 +++++++++++++++++++++++++++++++++--------- - 1 file changed, 33 insertions(+), 9 deletions(-) - -diff --git a/xen/arch/x86/mm/p2m-pod.c b/xen/arch/x86/mm/p2m-pod.c -index f2ed751892..473d6a6dbf 100644 ---- a/xen/arch/x86/mm/p2m-pod.c -+++ b/xen/arch/x86/mm/p2m-pod.c -@@ -555,11 +555,23 @@ p2m_pod_decrease_reservation(struct domain *d, - - if ( !nonpod ) - { -- /* All PoD: Mark the whole region invalid and tell caller -- * we're done. */ -- p2m_set_entry(p2m, gpfn, INVALID_MFN, order, p2m_invalid, -- p2m->default_access); -- p2m->pod.entry_count-=(1<default_access) ) -+ { -+ /* -+ * If this fails, we can't tell how much of the range was changed. -+ * Best to crash the domain unless we're sure a partial change is -+ * impossible. -+ */ -+ if ( order != 0 ) -+ domain_crash(d); -+ goto out_unlock; -+ } -+ p2m->pod.entry_count -= 1UL << order; - BUG_ON(p2m->pod.entry_count < 0); - ret = 1; - goto out_entry_check; -@@ -600,8 +612,14 @@ p2m_pod_decrease_reservation(struct domain *d, - n = 1UL << cur_order; - if ( t == p2m_populate_on_demand ) - { -- p2m_set_entry(p2m, gpfn + i, INVALID_MFN, cur_order, -- p2m_invalid, p2m->default_access); -+ /* This shouldn't be able to fail */ -+ if ( p2m_set_entry(p2m, gpfn + i, INVALID_MFN, cur_order, -+ p2m_invalid, p2m->default_access) ) -+ { -+ ASSERT_UNREACHABLE(); -+ domain_crash(d); -+ goto out_unlock; -+ } - p2m->pod.entry_count -= n; - BUG_ON(p2m->pod.entry_count < 0); - pod -= n; -@@ -622,8 +640,14 @@ p2m_pod_decrease_reservation(struct domain *d, - - page = mfn_to_page(mfn); - -- p2m_set_entry(p2m, gpfn + i, INVALID_MFN, cur_order, -- p2m_invalid, p2m->default_access); -+ /* This shouldn't be able to fail */ -+ if ( p2m_set_entry(p2m, gpfn + i, INVALID_MFN, cur_order, -+ p2m_invalid, p2m->default_access) ) -+ { -+ ASSERT_UNREACHABLE(); -+ domain_crash(d); -+ goto out_unlock; -+ } - p2m_tlb_flush_sync(p2m); - for ( j = 0; j < n; ++j ) - set_gpfn_from_mfn(mfn_x(mfn), INVALID_M2P_ENTRY); --- -2.15.0 - diff --git a/xsa248.patch b/xsa248.patch deleted file mode 100644 index 966c16e..0000000 --- a/xsa248.patch +++ /dev/null @@ -1,164 +0,0 @@ -From: Jan Beulich -Subject: x86/mm: don't wrongly set page ownership - -PV domains can obtain mappings of any pages owned by the correct domain, -including ones that aren't actually assigned as "normal" RAM, but used -by Xen internally. At the moment such "internal" pages marked as owned -by a guest include pages used to track logdirty bits, as well as p2m -pages and the "unpaged pagetable" for HVM guests. Since the PV memory -management and shadow code conflict in their use of struct page_info -fields, and since shadow code is being used for log-dirty handling for -PV domains, pages coming from the shadow pool must, for PV domains, not -have the domain set as their owner. - -While the change could be done conditionally for just the PV case in -shadow code, do it unconditionally (and for consistency also for HAP), -just to be on the safe side. - -There's one special case though for shadow code: The page table used for -running a HVM guest in unpaged mode is subject to get_page() (in -set_shadow_status()) and hence must have its owner set. - -This is XSA-248. - -Signed-off-by: Jan Beulich -Reviewed-by: Tim Deegan -Reviewed-by: George Dunlap ---- -v2: Drop PGC_page_table related pieces. - ---- a/xen/arch/x86/mm/hap/hap.c -+++ b/xen/arch/x86/mm/hap/hap.c -@@ -286,8 +286,7 @@ static struct page_info *hap_alloc_p2m_p - { - d->arch.paging.hap.total_pages--; - d->arch.paging.hap.p2m_pages++; -- page_set_owner(pg, d); -- pg->count_info |= 1; -+ ASSERT(!page_get_owner(pg) && !(pg->count_info & PGC_count_mask)); - } - else if ( !d->arch.paging.p2m_alloc_failed ) - { -@@ -302,21 +301,23 @@ static struct page_info *hap_alloc_p2m_p - - static void hap_free_p2m_page(struct domain *d, struct page_info *pg) - { -+ struct domain *owner = page_get_owner(pg); -+ - /* This is called both from the p2m code (which never holds the - * paging lock) and the log-dirty code (which always does). */ - paging_lock_recursive(d); - -- ASSERT(page_get_owner(pg) == d); -- /* Should have just the one ref we gave it in alloc_p2m_page() */ -- if ( (pg->count_info & PGC_count_mask) != 1 ) { -- HAP_ERROR("Odd p2m page %p count c=%#lx t=%"PRtype_info"\n", -- pg, pg->count_info, pg->u.inuse.type_info); -+ /* Should still have no owner and count zero. */ -+ if ( owner || (pg->count_info & PGC_count_mask) ) -+ { -+ HAP_ERROR("d%d: Odd p2m page %"PRI_mfn" d=%d c=%lx t=%"PRtype_info"\n", -+ d->domain_id, mfn_x(page_to_mfn(pg)), -+ owner ? owner->domain_id : DOMID_INVALID, -+ pg->count_info, pg->u.inuse.type_info); - WARN(); -+ pg->count_info &= ~PGC_count_mask; -+ page_set_owner(pg, NULL); - } -- pg->count_info &= ~PGC_count_mask; -- /* Free should not decrement domain's total allocation, since -- * these pages were allocated without an owner. */ -- page_set_owner(pg, NULL); - d->arch.paging.hap.p2m_pages--; - d->arch.paging.hap.total_pages++; - hap_free(d, page_to_mfn(pg)); ---- a/xen/arch/x86/mm/shadow/common.c -+++ b/xen/arch/x86/mm/shadow/common.c -@@ -1503,32 +1503,29 @@ shadow_alloc_p2m_page(struct domain *d) - pg = mfn_to_page(shadow_alloc(d, SH_type_p2m_table, 0)); - d->arch.paging.shadow.p2m_pages++; - d->arch.paging.shadow.total_pages--; -+ ASSERT(!page_get_owner(pg) && !(pg->count_info & PGC_count_mask)); - - paging_unlock(d); - -- /* Unlike shadow pages, mark p2m pages as owned by the domain. -- * Marking the domain as the owner would normally allow the guest to -- * create mappings of these pages, but these p2m pages will never be -- * in the domain's guest-physical address space, and so that is not -- * believed to be a concern. */ -- page_set_owner(pg, d); -- pg->count_info |= 1; - return pg; - } - - static void - shadow_free_p2m_page(struct domain *d, struct page_info *pg) - { -- ASSERT(page_get_owner(pg) == d); -- /* Should have just the one ref we gave it in alloc_p2m_page() */ -- if ( (pg->count_info & PGC_count_mask) != 1 ) -+ struct domain *owner = page_get_owner(pg); -+ -+ /* Should still have no owner and count zero. */ -+ if ( owner || (pg->count_info & PGC_count_mask) ) - { -- SHADOW_ERROR("Odd p2m page count c=%#lx t=%"PRtype_info"\n", -+ SHADOW_ERROR("d%d: Odd p2m page %"PRI_mfn" d=%d c=%lx t=%"PRtype_info"\n", -+ d->domain_id, mfn_x(page_to_mfn(pg)), -+ owner ? owner->domain_id : DOMID_INVALID, - pg->count_info, pg->u.inuse.type_info); -+ pg->count_info &= ~PGC_count_mask; -+ page_set_owner(pg, NULL); - } -- pg->count_info &= ~PGC_count_mask; - pg->u.sh.type = SH_type_p2m_table; /* p2m code reuses type-info */ -- page_set_owner(pg, NULL); - - /* This is called both from the p2m code (which never holds the - * paging lock) and the log-dirty code (which always does). */ -@@ -3132,7 +3129,9 @@ int shadow_enable(struct domain *d, u32 - e = __map_domain_page(pg); - write_32bit_pse_identmap(e); - unmap_domain_page(e); -+ pg->count_info = 1; - pg->u.inuse.type_info = PGT_l2_page_table | 1 | PGT_validated; -+ page_set_owner(pg, d); - } - - paging_lock(d); -@@ -3170,7 +3169,11 @@ int shadow_enable(struct domain *d, u32 - if ( rv != 0 && !pagetable_is_null(p2m_get_pagetable(p2m)) ) - p2m_teardown(p2m); - if ( rv != 0 && pg != NULL ) -+ { -+ pg->count_info &= ~PGC_count_mask; -+ page_set_owner(pg, NULL); - shadow_free_p2m_page(d, pg); -+ } - domain_unpause(d); - return rv; - } -@@ -3279,7 +3282,22 @@ out: - - /* Must be called outside the lock */ - if ( unpaged_pagetable ) -+ { -+ if ( page_get_owner(unpaged_pagetable) == d && -+ (unpaged_pagetable->count_info & PGC_count_mask) == 1 ) -+ { -+ unpaged_pagetable->count_info &= ~PGC_count_mask; -+ page_set_owner(unpaged_pagetable, NULL); -+ } -+ /* Complain here in cases where shadow_free_p2m_page() won't. */ -+ else if ( !page_get_owner(unpaged_pagetable) && -+ !(unpaged_pagetable->count_info & PGC_count_mask) ) -+ SHADOW_ERROR("d%d: Odd unpaged pt %"PRI_mfn" c=%lx t=%"PRtype_info"\n", -+ d->domain_id, mfn_x(page_to_mfn(unpaged_pagetable)), -+ unpaged_pagetable->count_info, -+ unpaged_pagetable->u.inuse.type_info); - shadow_free_p2m_page(d, unpaged_pagetable); -+ } - } - - void shadow_final_teardown(struct domain *d) diff --git a/xsa249.patch b/xsa249.patch deleted file mode 100644 index ecfa430..0000000 --- a/xsa249.patch +++ /dev/null @@ -1,42 +0,0 @@ -From: Jan Beulich -Subject: x86/shadow: fix refcount overflow check - -Commit c385d27079 ("x86 shadow: for multi-page shadows, explicitly track -the first page") reduced the refcount width to 25, without adjusting the -overflow check. Eliminate the disconnect by using a manifest constant. - -Interestingly, up to commit 047782fa01 ("Out-of-sync L1 shadows: OOS -snapshot") the refcount was 27 bits wide, yet the check was already -using 26. - -This is XSA-249. - -Signed-off-by: Jan Beulich -Reviewed-by: George Dunlap -Reviewed-by: Tim Deegan ---- -v2: Simplify expression back to the style it was. - ---- a/xen/arch/x86/mm/shadow/private.h -+++ b/xen/arch/x86/mm/shadow/private.h -@@ -529,7 +529,7 @@ static inline int sh_get_ref(struct doma - x = sp->u.sh.count; - nx = x + 1; - -- if ( unlikely(nx >= 1U<<26) ) -+ if ( unlikely(nx >= (1U << PAGE_SH_REFCOUNT_WIDTH)) ) - { - SHADOW_PRINTK("shadow ref overflow, gmfn=%lx smfn=%lx\n", - __backpointer(sp), mfn_x(smfn)); ---- a/xen/include/asm-x86/mm.h -+++ b/xen/include/asm-x86/mm.h -@@ -82,7 +82,8 @@ struct page_info - unsigned long type:5; /* What kind of shadow is this? */ - unsigned long pinned:1; /* Is the shadow pinned? */ - unsigned long head:1; /* Is this the first page of the shadow? */ -- unsigned long count:25; /* Reference count */ -+#define PAGE_SH_REFCOUNT_WIDTH 25 -+ unsigned long count:PAGE_SH_REFCOUNT_WIDTH; /* Reference count */ - } sh; - - /* Page is on a free list: ((count_info & PGC_count_mask) == 0). */ diff --git a/xsa250.patch b/xsa250.patch deleted file mode 100644 index 26aeb33..0000000 --- a/xsa250.patch +++ /dev/null @@ -1,67 +0,0 @@ -From: Jan Beulich -Subject: x86/shadow: fix ref-counting error handling - -The old-Linux handling in shadow_set_l4e() mistakenly ORed together the -results of sh_get_ref() and sh_pin(). As the latter failing is not a -correctness problem, simply ignore its return value. - -In sh_set_toplevel_shadow() a failing sh_get_ref() must not be -accompanied by installing the entry, despite the domain being crashed. - -This is XSA-250. - -Signed-off-by: Jan Beulich -Reviewed-by: Tim Deegan - ---- a/xen/arch/x86/mm/shadow/multi.c -+++ b/xen/arch/x86/mm/shadow/multi.c -@@ -923,7 +923,7 @@ static int shadow_set_l4e(struct domain - shadow_l4e_t new_sl4e, - mfn_t sl4mfn) - { -- int flags = 0, ok; -+ int flags = 0; - shadow_l4e_t old_sl4e; - paddr_t paddr; - ASSERT(sl4e != NULL); -@@ -938,15 +938,16 @@ static int shadow_set_l4e(struct domain - { - /* About to install a new reference */ - mfn_t sl3mfn = shadow_l4e_get_mfn(new_sl4e); -- ok = sh_get_ref(d, sl3mfn, paddr); -- /* Are we pinning l3 shadows to handle wierd linux behaviour? */ -- if ( sh_type_is_pinnable(d, SH_type_l3_64_shadow) ) -- ok |= sh_pin(d, sl3mfn); -- if ( !ok ) -+ -+ if ( !sh_get_ref(d, sl3mfn, paddr) ) - { - domain_crash(d); - return SHADOW_SET_ERROR; - } -+ -+ /* Are we pinning l3 shadows to handle weird Linux behaviour? */ -+ if ( sh_type_is_pinnable(d, SH_type_l3_64_shadow) ) -+ sh_pin(d, sl3mfn); - } - - /* Write the new entry */ -@@ -3965,14 +3966,15 @@ sh_set_toplevel_shadow(struct vcpu *v, - - /* Take a ref to this page: it will be released in sh_detach_old_tables() - * or the next call to set_toplevel_shadow() */ -- if ( !sh_get_ref(d, smfn, 0) ) -+ if ( sh_get_ref(d, smfn, 0) ) -+ new_entry = pagetable_from_mfn(smfn); -+ else - { - SHADOW_ERROR("can't install %#lx as toplevel shadow\n", mfn_x(smfn)); - domain_crash(d); -+ new_entry = pagetable_null(); - } - -- new_entry = pagetable_from_mfn(smfn); -- - install_new_entry: - /* Done. Install it */ - SHADOW_PRINTK("%u/%u [%u] gmfn %#"PRI_mfn" smfn %#"PRI_mfn"\n", diff --git a/xsa251.patch b/xsa251.patch deleted file mode 100644 index 582ef62..0000000 --- a/xsa251.patch +++ /dev/null @@ -1,21 +0,0 @@ -From: Jan Beulich -Subject: x86/paging: don't unconditionally BUG() on finding SHARED_M2P_ENTRY - -PV guests can fully control the values written into the P2M. - -This is XSA-251. - -Signed-off-by: Jan Beulich -Reviewed-by: Andrew Cooper - ---- a/xen/arch/x86/mm/paging.c -+++ b/xen/arch/x86/mm/paging.c -@@ -274,7 +274,7 @@ void paging_mark_pfn_dirty(struct domain - return; - - /* Shared MFNs should NEVER be marked dirty */ -- BUG_ON(SHARED_M2P(pfn_x(pfn))); -+ BUG_ON(paging_mode_translate(d) && SHARED_M2P(pfn_x(pfn))); - - /* - * Values with the MSB set denote MFNs that aren't really part of the diff --git a/xsa278-4.11.patch b/xsa278-4.11.patch new file mode 100644 index 0000000..9e14849 --- /dev/null +++ b/xsa278-4.11.patch @@ -0,0 +1,326 @@ +From: Andrew Cooper +Subject: x86/vvmx: Disallow the use of VT-x instructions when nested virt is disabled + +c/s ac6a4500b "vvmx: set vmxon_region_pa of vcpu out of VMX operation to an +invalid address" was a real bugfix as described, but has a very subtle bug +which results in all VT-x instructions being usable by a guest. + +The toolstack constructs a guest by issuing: + + XEN_DOMCTL_createdomain + XEN_DOMCTL_max_vcpus + +and optionally later, HVMOP_set_param to enable nested virt. + +As a result, the call to nvmx_vcpu_initialise() in hvm_vcpu_initialise() +(which is what makes the above patch look correct during review) is actually +dead code. In practice, nvmx_vcpu_initialise() first gets called when nested +virt is enabled, which is typically never. + +As a result, the zeroed memory of struct vcpu causes nvmx_vcpu_in_vmx() to +return true before nested virt is enabled for the guest. + +Fixing the order of initialisation is a work in progress for other reasons, +but not viable for security backports. + +A compounding factor is that the vmexit handlers for all instructions, other +than VMXON, pass 0 into vmx_inst_check_privilege()'s vmxop_check parameter, +which skips the CR4.VMXE check. (This is one of many reasons why nested virt +isn't a supported feature yet.) + +However, the overall result is that when nested virt is not enabled by the +toolstack (i.e. the default configuration for all production guests), the VT-x +instructions (other than VMXON) are actually usable, and Xen very quickly +falls over the fact that the nvmx structure is uninitialised. + +In order to fail safe in the supported case, re-implement all the VT-x +instruction handling using a single function with a common prologue, covering +all the checks which should cause #UD or #GP faults. This deliberately +doesn't use any state from the nvmx structure, in case there are other lurking +issues. + +This is XSA-278 + +Reported-by: Sergey Dyasli +Signed-off-by: Andrew Cooper +Reviewed-by: Sergey Dyasli + +diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c +index a6415f0..a4d2829 100644 +--- a/xen/arch/x86/hvm/vmx/vmx.c ++++ b/xen/arch/x86/hvm/vmx/vmx.c +@@ -3982,57 +3982,17 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs) + break; + + case EXIT_REASON_VMXOFF: +- if ( nvmx_handle_vmxoff(regs) == X86EMUL_OKAY ) +- update_guest_eip(); +- break; +- + case EXIT_REASON_VMXON: +- if ( nvmx_handle_vmxon(regs) == X86EMUL_OKAY ) +- update_guest_eip(); +- break; +- + case EXIT_REASON_VMCLEAR: +- if ( nvmx_handle_vmclear(regs) == X86EMUL_OKAY ) +- update_guest_eip(); +- break; +- + case EXIT_REASON_VMPTRLD: +- if ( nvmx_handle_vmptrld(regs) == X86EMUL_OKAY ) +- update_guest_eip(); +- break; +- + case EXIT_REASON_VMPTRST: +- if ( nvmx_handle_vmptrst(regs) == X86EMUL_OKAY ) +- update_guest_eip(); +- break; +- + case EXIT_REASON_VMREAD: +- if ( nvmx_handle_vmread(regs) == X86EMUL_OKAY ) +- update_guest_eip(); +- break; +- + case EXIT_REASON_VMWRITE: +- if ( nvmx_handle_vmwrite(regs) == X86EMUL_OKAY ) +- update_guest_eip(); +- break; +- + case EXIT_REASON_VMLAUNCH: +- if ( nvmx_handle_vmlaunch(regs) == X86EMUL_OKAY ) +- update_guest_eip(); +- break; +- + case EXIT_REASON_VMRESUME: +- if ( nvmx_handle_vmresume(regs) == X86EMUL_OKAY ) +- update_guest_eip(); +- break; +- + case EXIT_REASON_INVEPT: +- if ( nvmx_handle_invept(regs) == X86EMUL_OKAY ) +- update_guest_eip(); +- break; +- + case EXIT_REASON_INVVPID: +- if ( nvmx_handle_invvpid(regs) == X86EMUL_OKAY ) ++ if ( nvmx_handle_vmx_insn(regs, exit_reason) == X86EMUL_OKAY ) + update_guest_eip(); + break; + +diff --git a/xen/arch/x86/hvm/vmx/vvmx.c b/xen/arch/x86/hvm/vmx/vvmx.c +index e97db33..88cb58c 100644 +--- a/xen/arch/x86/hvm/vmx/vvmx.c ++++ b/xen/arch/x86/hvm/vmx/vvmx.c +@@ -1470,7 +1470,7 @@ void nvmx_switch_guest(void) + * VMX instructions handling + */ + +-int nvmx_handle_vmxon(struct cpu_user_regs *regs) ++static int nvmx_handle_vmxon(struct cpu_user_regs *regs) + { + struct vcpu *v=current; + struct nestedvmx *nvmx = &vcpu_2_nvmx(v); +@@ -1522,7 +1522,7 @@ int nvmx_handle_vmxon(struct cpu_user_regs *regs) + return X86EMUL_OKAY; + } + +-int nvmx_handle_vmxoff(struct cpu_user_regs *regs) ++static int nvmx_handle_vmxoff(struct cpu_user_regs *regs) + { + struct vcpu *v=current; + struct nestedvmx *nvmx = &vcpu_2_nvmx(v); +@@ -1611,7 +1611,7 @@ static int nvmx_vmresume(struct vcpu *v, struct cpu_user_regs *regs) + return X86EMUL_OKAY; + } + +-int nvmx_handle_vmresume(struct cpu_user_regs *regs) ++static int nvmx_handle_vmresume(struct cpu_user_regs *regs) + { + bool_t launched; + struct vcpu *v = current; +@@ -1645,7 +1645,7 @@ int nvmx_handle_vmresume(struct cpu_user_regs *regs) + return nvmx_vmresume(v,regs); + } + +-int nvmx_handle_vmlaunch(struct cpu_user_regs *regs) ++static int nvmx_handle_vmlaunch(struct cpu_user_regs *regs) + { + bool_t launched; + struct vcpu *v = current; +@@ -1688,7 +1688,7 @@ int nvmx_handle_vmlaunch(struct cpu_user_regs *regs) + return rc; + } + +-int nvmx_handle_vmptrld(struct cpu_user_regs *regs) ++static int nvmx_handle_vmptrld(struct cpu_user_regs *regs) + { + struct vcpu *v = current; + struct vmx_inst_decoded decode; +@@ -1759,7 +1759,7 @@ int nvmx_handle_vmptrld(struct cpu_user_regs *regs) + return X86EMUL_OKAY; + } + +-int nvmx_handle_vmptrst(struct cpu_user_regs *regs) ++static int nvmx_handle_vmptrst(struct cpu_user_regs *regs) + { + struct vcpu *v = current; + struct vmx_inst_decoded decode; +@@ -1784,7 +1784,7 @@ int nvmx_handle_vmptrst(struct cpu_user_regs *regs) + return X86EMUL_OKAY; + } + +-int nvmx_handle_vmclear(struct cpu_user_regs *regs) ++static int nvmx_handle_vmclear(struct cpu_user_regs *regs) + { + struct vcpu *v = current; + struct vmx_inst_decoded decode; +@@ -1836,7 +1836,7 @@ int nvmx_handle_vmclear(struct cpu_user_regs *regs) + return X86EMUL_OKAY; + } + +-int nvmx_handle_vmread(struct cpu_user_regs *regs) ++static int nvmx_handle_vmread(struct cpu_user_regs *regs) + { + struct vcpu *v = current; + struct vmx_inst_decoded decode; +@@ -1878,7 +1878,7 @@ int nvmx_handle_vmread(struct cpu_user_regs *regs) + return X86EMUL_OKAY; + } + +-int nvmx_handle_vmwrite(struct cpu_user_regs *regs) ++static int nvmx_handle_vmwrite(struct cpu_user_regs *regs) + { + struct vcpu *v = current; + struct vmx_inst_decoded decode; +@@ -1926,7 +1926,7 @@ int nvmx_handle_vmwrite(struct cpu_user_regs *regs) + return X86EMUL_OKAY; + } + +-int nvmx_handle_invept(struct cpu_user_regs *regs) ++static int nvmx_handle_invept(struct cpu_user_regs *regs) + { + struct vmx_inst_decoded decode; + unsigned long eptp; +@@ -1954,7 +1954,7 @@ int nvmx_handle_invept(struct cpu_user_regs *regs) + return X86EMUL_OKAY; + } + +-int nvmx_handle_invvpid(struct cpu_user_regs *regs) ++static int nvmx_handle_invvpid(struct cpu_user_regs *regs) + { + struct vmx_inst_decoded decode; + unsigned long vpid; +@@ -1980,6 +1980,81 @@ int nvmx_handle_invvpid(struct cpu_user_regs *regs) + return X86EMUL_OKAY; + } + ++int nvmx_handle_vmx_insn(struct cpu_user_regs *regs, unsigned int exit_reason) ++{ ++ struct vcpu *curr = current; ++ int ret; ++ ++ if ( !(curr->arch.hvm_vcpu.guest_cr[4] & X86_CR4_VMXE) || ++ !nestedhvm_enabled(curr->domain) || ++ (vmx_guest_x86_mode(curr) < (hvm_long_mode_active(curr) ? 8 : 2)) ) ++ { ++ hvm_inject_hw_exception(TRAP_invalid_op, X86_EVENT_NO_EC); ++ return X86EMUL_EXCEPTION; ++ } ++ ++ if ( vmx_get_cpl() > 0 ) ++ { ++ hvm_inject_hw_exception(TRAP_gp_fault, 0); ++ return X86EMUL_EXCEPTION; ++ } ++ ++ switch ( exit_reason ) ++ { ++ case EXIT_REASON_VMXOFF: ++ ret = nvmx_handle_vmxoff(regs); ++ break; ++ ++ case EXIT_REASON_VMXON: ++ ret = nvmx_handle_vmxon(regs); ++ break; ++ ++ case EXIT_REASON_VMCLEAR: ++ ret = nvmx_handle_vmclear(regs); ++ break; ++ ++ case EXIT_REASON_VMPTRLD: ++ ret = nvmx_handle_vmptrld(regs); ++ break; ++ ++ case EXIT_REASON_VMPTRST: ++ ret = nvmx_handle_vmptrst(regs); ++ break; ++ ++ case EXIT_REASON_VMREAD: ++ ret = nvmx_handle_vmread(regs); ++ break; ++ ++ case EXIT_REASON_VMWRITE: ++ ret = nvmx_handle_vmwrite(regs); ++ break; ++ ++ case EXIT_REASON_VMLAUNCH: ++ ret = nvmx_handle_vmlaunch(regs); ++ break; ++ ++ case EXIT_REASON_VMRESUME: ++ ret = nvmx_handle_vmresume(regs); ++ break; ++ ++ case EXIT_REASON_INVEPT: ++ ret = nvmx_handle_invept(regs); ++ break; ++ ++ case EXIT_REASON_INVVPID: ++ ret = nvmx_handle_invvpid(regs); ++ break; ++ ++ default: ++ ASSERT_UNREACHABLE(); ++ domain_crash(curr->domain); ++ ret = X86EMUL_UNHANDLEABLE; ++ break; ++ } ++ ++ return ret; ++} ++ + #define __emul_value(enable1, default1) \ + ((enable1 | default1) << 32 | (default1)) + +diff --git a/xen/include/asm-x86/hvm/vmx/vvmx.h b/xen/include/asm-x86/hvm/vmx/vvmx.h +index 9ea35eb..fc4a8d1 100644 +--- a/xen/include/asm-x86/hvm/vmx/vvmx.h ++++ b/xen/include/asm-x86/hvm/vmx/vvmx.h +@@ -94,9 +94,6 @@ void nvmx_domain_relinquish_resources(struct domain *d); + + bool_t nvmx_ept_enabled(struct vcpu *v); + +-int nvmx_handle_vmxon(struct cpu_user_regs *regs); +-int nvmx_handle_vmxoff(struct cpu_user_regs *regs); +- + #define EPT_TRANSLATE_SUCCEED 0 + #define EPT_TRANSLATE_VIOLATION 1 + #define EPT_TRANSLATE_MISCONFIG 2 +@@ -191,15 +188,7 @@ enum vmx_insn_errno set_vvmcs_real_safe(const struct vcpu *, u32 encoding, + uint64_t get_shadow_eptp(struct vcpu *v); + + void nvmx_destroy_vmcs(struct vcpu *v); +-int nvmx_handle_vmptrld(struct cpu_user_regs *regs); +-int nvmx_handle_vmptrst(struct cpu_user_regs *regs); +-int nvmx_handle_vmclear(struct cpu_user_regs *regs); +-int nvmx_handle_vmread(struct cpu_user_regs *regs); +-int nvmx_handle_vmwrite(struct cpu_user_regs *regs); +-int nvmx_handle_vmresume(struct cpu_user_regs *regs); +-int nvmx_handle_vmlaunch(struct cpu_user_regs *regs); +-int nvmx_handle_invept(struct cpu_user_regs *regs); +-int nvmx_handle_invvpid(struct cpu_user_regs *regs); ++int nvmx_handle_vmx_insn(struct cpu_user_regs *regs, unsigned int exit_reason); + int nvmx_msr_read_intercept(unsigned int msr, + u64 *msr_content); + diff --git a/xsa282-2.patch b/xsa282-2.patch new file mode 100644 index 0000000..4c34691 --- /dev/null +++ b/xsa282-2.patch @@ -0,0 +1,42 @@ +From: Jan Beulich +Subject: x86: work around HLE host lockup erratum + +XACQUIRE prefixed accesses to the 4Mb range of memory starting at 1Gb +are liable to lock up the processor. Disallow use of this memory range. + +Unfortunately the available Core Gen7 and Gen8 spec updates are pretty +old, so I can only guess that they're similarly affected when Core Gen6 +is and the Xeon counterparts are, too. + +This is part of XSA-282. + +Signed-off-by: Jan Beulich +Reviewed-by: Andrew Cooper +--- +v2: Don't apply the workaround when running ourselves virtualized. + +--- a/xen/arch/x86/mm.c ++++ b/xen/arch/x86/mm.c +@@ -5853,6 +5853,22 @@ const struct platform_bad_page *__init g + { .mfn = 0x20138000 >> PAGE_SHIFT }, + { .mfn = 0x40004000 >> PAGE_SHIFT }, + }; ++ static const struct platform_bad_page __initconst hle_bad_page = { ++ .mfn = 0x40000000 >> PAGE_SHIFT, .order = 10 ++ }; ++ ++ switch ( cpuid_eax(1) & 0x000f3ff0 ) ++ { ++ case 0x000406e0: /* erratum SKL167 */ ++ case 0x00050650: /* erratum SKZ63 */ ++ case 0x000506e0: /* errata SKL167 / SKW159 */ ++ case 0x000806e0: /* erratum KBL??? */ ++ case 0x000906e0: /* errata KBL??? / KBW114 / CFW103 */ ++ *array_size = (cpuid_eax(0) >= 7 && ++ !(cpuid_ecx(1) & cpufeat_mask(X86_FEATURE_HYPERVISOR)) && ++ (cpuid_count_ebx(7, 0) & cpufeat_mask(X86_FEATURE_HLE))); ++ return &hle_bad_page; ++ } + + *array_size = ARRAY_SIZE(snb_bad_pages); + igd_id = pci_conf_read32(0, 0, 2, 0, 0); diff --git a/xsa282-4.9-1.patch b/xsa282-4.9-1.patch new file mode 100644 index 0000000..580933d --- /dev/null +++ b/xsa282-4.9-1.patch @@ -0,0 +1,87 @@ +From: Jan Beulich +Subject: x86: extend get_platform_badpages() interface + +Use a structure so along with an address (now frame number) an order can +also be specified. + +This is part of XSA-282. + +Signed-off-by: Jan Beulich +Reviewed-by: Andrew Cooper + +--- a/xen/arch/x86/mm.c ++++ b/xen/arch/x86/mm.c +@@ -7111,23 +7111,23 @@ void arch_dump_shared_mem_info(void) + mem_sharing_get_nr_saved_mfns()); + } + +-const unsigned long *__init get_platform_badpages(unsigned int *array_size) ++const struct platform_bad_page *__init get_platform_badpages(unsigned int *array_size) + { + u32 igd_id; +- static unsigned long __initdata bad_pages[] = { +- 0x20050000, +- 0x20110000, +- 0x20130000, +- 0x20138000, +- 0x40004000, ++ static const struct platform_bad_page __initconst snb_bad_pages[] = { ++ { .mfn = 0x20050000 >> PAGE_SHIFT }, ++ { .mfn = 0x20110000 >> PAGE_SHIFT }, ++ { .mfn = 0x20130000 >> PAGE_SHIFT }, ++ { .mfn = 0x20138000 >> PAGE_SHIFT }, ++ { .mfn = 0x40004000 >> PAGE_SHIFT }, + }; + +- *array_size = ARRAY_SIZE(bad_pages); ++ *array_size = ARRAY_SIZE(snb_bad_pages); + igd_id = pci_conf_read32(0, 0, 2, 0, 0); +- if ( !IS_SNB_GFX(igd_id) ) +- return NULL; ++ if ( IS_SNB_GFX(igd_id) ) ++ return snb_bad_pages; + +- return bad_pages; ++ return NULL; + } + + void paging_invlpg(struct vcpu *v, unsigned long va) +--- a/xen/common/page_alloc.c ++++ b/xen/common/page_alloc.c +@@ -270,7 +270,7 @@ void __init init_boot_pages(paddr_t ps, + unsigned long bad_spfn, bad_epfn; + const char *p; + #ifdef CONFIG_X86 +- const unsigned long *badpage = NULL; ++ const struct platform_bad_page *badpage; + unsigned int i, array_size; + #endif + +@@ -295,8 +295,8 @@ void __init init_boot_pages(paddr_t ps, + { + for ( i = 0; i < array_size; i++ ) + { +- bootmem_region_zap(*badpage >> PAGE_SHIFT, +- (*badpage >> PAGE_SHIFT) + 1); ++ bootmem_region_zap(badpage->mfn, ++ badpage->mfn + (1U << badpage->order)); + badpage++; + } + } +--- a/xen/include/asm-x86/mm.h ++++ b/xen/include/asm-x86/mm.h +@@ -350,7 +350,13 @@ bool is_iomem_page(mfn_t mfn); + + void clear_superpage_mark(struct page_info *page); + +-const unsigned long *get_platform_badpages(unsigned int *array_size); ++struct platform_bad_page { ++ unsigned long mfn; ++ unsigned int order; ++}; ++ ++const struct platform_bad_page *get_platform_badpages(unsigned int *array_size); ++ + /* Per page locks: + * page_lock() is used for two purposes: pte serialization, and memory sharing. + *