Compare commits
15 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86d80e3acb | ||
|
|
a150492887 | ||
|
|
4d37d7e4ce | ||
|
|
e2de31fea8 | ||
|
|
56f3a702a3 | ||
|
|
833288d408 | ||
|
|
db2bf3b4f8 | ||
|
|
4401709c83 | ||
|
|
b4719e3501 | ||
|
|
2d7f2b9a77 | ||
|
|
67cbf78425 | ||
|
|
70e5ed2b64 | ||
|
|
7185b9d897 | ||
|
|
d4696bae25 | ||
|
|
aec7903969 |
15 changed files with 528 additions and 697 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -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
|
||||
|
|
|
|||
2
sources
2
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
|
||||
|
|
|
|||
85
xen.spec
85
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 <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)
|
||||
|
|
|
|||
|
|
@ -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 @@
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
164
xsa248.patch
164
xsa248.patch
|
|
@ -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)
|
||||
42
xsa249.patch
42
xsa249.patch
|
|
@ -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). */
|
||||
67
xsa250.patch
67
xsa250.patch
|
|
@ -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",
|
||||
21
xsa251.patch
21
xsa251.patch
|
|
@ -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
326
xsa278-4.11.patch
Normal 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
42
xsa282-2.patch
Normal 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
87
xsa282-4.9-1.patch
Normal 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.
|
||||
*
|
||||
Loading…
Add table
Add a link
Reference in a new issue