Compare commits

...
Sign in to create a new pull request.

15 commits

Author SHA1 Message Date
Michael Young
86d80e3acb guest use of HLE constructs may lock up host [XSA-282] 2018-11-06 22:37:44 +00:00
Michael Young
a150492887 x86: Nested VT-x usable even when disabled [XSA-278] (#1643118) 2018-10-25 21:11:01 +01:00
Michael Young
4d37d7e4ce update to 4.9.3 2018-09-25 20:54:41 +01:00
Michael Young
e2de31fea8 add CVE references 2018-09-12 19:52:42 +01:00
Michael Young
56f3a702a3 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] (#1616081)
x86: Incorrect MSR_DEBUGCTL handling lets guests enable BTS [XSA-269]
	(#1616077)
oxenstored does not apply quota-maxentity [XSA-272] (#1616080)
2018-08-15 23:14:46 +01:00
Michael Young
833288d408 add bug references 2018-06-28 00:03:42 +01:00
Michael Young
db2bf3b4f8 preemption checks bypassed in x86 PV MM handling [XSA-264, CVE-2018-12891]
x86: #DB exception safety check can be triggered by a guest [XSA-265,
        CVE-2018-12893]
libxl fails to honour readonly flag on HVM emulated SCSI disks [XSA-266,
        CVE-2018-12892]
2018-06-27 22:54:20 +01:00
Michael Young
4401709c83 Speculative register leakage from lazy FPU context switching
[XSA-267, CVE-2018-3665]
fix for change in iasl output
2018-06-16 15:06:41 +01:00
Michael Young
b4719e3501 Speculative Store Bypass [XSA-263, CVE-2018-3639] 2018-05-22 22:45:43 +01:00
Michael Young
2d7f2b9a77 add CVEs and bug reference 2018-05-11 22:58:46 +01:00
Michael Young
67cbf78425 x86: mishandling of debug exceptions [XSA-260, CVE-2018-8897]
x86 vHPET interrupt injection errors [XSA-261] (#1576089)
qemu may drive Xen into unbounded loop [XSA-262]
2018-05-09 21:44:45 +01:00
Michael Young
70e5ed2b64 Information leak via crafted user-supplied CDROM [XSA-258] (#1571867)
x86: PV guest may crash Xen with XPTI [XSA-259] (#1571878)
2018-04-25 21:23:18 +01:00
Michael Young
7185b9d897 update to xen-4.9.2 2018-04-04 22:08:44 +01:00
Michael Young
d4696bae25 add CVE references 2018-02-28 12:22:04 +00:00
Michael Young
aec7903969 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] (#1549568)
grant table v2 -> v1 transition may crash Xen [XSA-255] (#1549570)
x86 PVH guest without LAPIC may DoS the host [XSA-256] (#1549572)
2018-02-27 16:40:17 +00:00
15 changed files with 528 additions and 697 deletions

2
.gitignore vendored
View file

@ -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

View file

@ -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

View file

@ -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 <m.a.young@durham.ac.uk> - 4.9.3-3
- guest use of HLE constructs may lock up host [XSA-282]
* Thu Oct 25 2018 Michael Young <m.a.young@durham.ac.uk> - 4.9.3-2
- x86: Nested VT-x usable even when disabled [XSA-278, CVE-2018-18883]
(#1643118)
* Tue Sep 25 2018 Michael Young <m.a.young@durham.ac.uk> - 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 <m.a.young@durham.ac.uk> - 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 <m.a.young@durham.ac.uk> - 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 <m.a.young@durham.ac.uk> - 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 <m.a.young@durham.ac.uk> - 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 <m.a.young@durham.ac.uk> - 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 <m.a.young@durham.ac.uk> - 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 <m.a.young@durham.ac.uk> - 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 <m.a.young@durham.ac.uk> - 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 <m.a.young@durham.ac.uk> - 4.9.1-4
- another patch related to the [XSA-240, CVE-2017-15595] issue
- xen: various flaws (#1525018)

View file

@ -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 @@

View file

@ -1,26 +0,0 @@
From: Jan Beulich <jbeulich@suse.com>
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 <jbeulich@suse.com>
Reviewed-by: <George Dunlap <george.dunlap.com>
--- 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;
}

View file

@ -1,74 +0,0 @@
From: Julien Grall <julien.grall@linaro.org>
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 <julien.grall@linaro.org>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: George Dunlap <george.dunlap@citrix.com>
--- 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)<<order;
- for(i=0; i<(1<<order); i++)
- p2m_set_entry(p2m, gfn_aligned + i, INVALID_MFN, PAGE_ORDER_4K,
- p2m_populate_on_demand, p2m->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 {

View file

@ -1,176 +0,0 @@
From ad208b8b7e45fb2b7c572b86c61c26412609e82d Mon Sep 17 00:00:00 2001
From: George Dunlap <george.dunlap@citrix.com>
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 <XXX EMAIL>
Signed-off-by: George Dunlap <george.dunlap@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
---
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

View file

@ -1,109 +0,0 @@
From d4bc7833707351a5341a6bdf04c752a028d9560d Mon Sep 17 00:00:00 2001
From: George Dunlap <george.dunlap@citrix.com>
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 <XXX EMAIL>
Signed-off-by: George Dunlap <george.dunlap@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
---
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<<order);
+ /*
+ * All PoD: Mark the whole region invalid and tell caller
+ * we're done.
+ */
+ if ( p2m_set_entry(p2m, gpfn, INVALID_MFN, order, p2m_invalid,
+ p2m->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

View file

@ -1,164 +0,0 @@
From: Jan Beulich <jbeulich@suse.com>
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 <jbeulich@suse.com>
Reviewed-by: Tim Deegan <tim@xen.org>
Reviewed-by: George Dunlap <george.dunlap@citrix.com>
---
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)

View file

@ -1,42 +0,0 @@
From: Jan Beulich <jbeulich@suse.com>
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 <jbeulich@suse.com>
Reviewed-by: George Dunlap <george.dunlap@citrix.com>
Reviewed-by: Tim Deegan <tim@xen.org>
---
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). */

View file

@ -1,67 +0,0 @@
From: Jan Beulich <jbeulich@suse.com>
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 <jbeulich@suse.com>
Reviewed-by: Tim Deegan <tim@xen.org>
--- 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",

View file

@ -1,21 +0,0 @@
From: Jan Beulich <jbeulich@suse.com>
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 <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
--- 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

326
xsa278-4.11.patch Normal file
View file

@ -0,0 +1,326 @@
From: Andrew Cooper <andrew.cooper3@citrix.com>
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 <sergey.dyasli@citrix.com>
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Sergey Dyasli <sergey.dyasli@citrix.com>
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);

42
xsa282-2.patch Normal file
View file

@ -0,0 +1,42 @@
From: Jan Beulich <jbeulich@suse.com>
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 <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
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);

87
xsa282-4.9-1.patch Normal file
View file

@ -0,0 +1,87 @@
From: Jan Beulich <jbeulich@suse.com>
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 <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
--- 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.
*