Compare commits

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

10 commits

Author SHA1 Message Date
Michael Young
1126cbfcae 3 security fixes
guests may exceed their designated memory limit [XSA-385, CVE-2021-28706]
PoD operations on misaligned GFNs [XSA-388, CVE-2021-28704, CVE-2021-28707
	CVE-2021-28708]
issues with partially successful P2M updates on x86 [XSA-389,
	CVE-2021-28705, CVE-2021-28709]
2021-11-23 20:17:55 +00:00
Michael Young
8d859c10ee PCI devices with RMRRs not deassigned correctly [XSA-386, CVE-2021-28702] 2021-10-06 20:37:12 +01:00
Michael Young
a9eb426b07 update to xen-4.14.3 2021-09-13 20:57:20 +01:00
Michael Young
2334838f4e add bug reference 2021-09-09 20:06:46 +01:00
Michael Young
3c3686c2d6 Another race in XENMAPSPACE_grant_table handling [XSA-384, CVE-2021-28701]
bugfix for XSA-380
stop editing grub files in /boot/efi/EFI/fedora on Fedora 34
2021-09-08 21:54:13 +01:00
Michael Young
659a9b49ea 5 security fixes, 1 grub fix
IOMMU page mapping issues on x86 [XSA-378, CVE-2021-28694,
        CVE-2021-28695, CVE-2021-28696] (#1997531) (#1997568)
        (#1997537)
grant table v2 status pages may remain accessible after de-allocation
        [XSA-379, CVE-2021-28697] (#1997520)
long running loops in grant table handling [XSA-380, CVE-2021-28698]
        (#1997526)
inadequate grant-v2 status frames array bounds check [XSA-382,
        CVE-2021-28699] (#1997523)
xen/arm: No memory limit for dom0less domUs [XSA-383, CVE-2021-28700]
        (#1997527)
grub x86_64-efi modules now go into /boot/grub2
2021-08-28 22:39:19 +01:00
Michael Young
928ca23fa0 add bug references and an extra CVE 2021-06-10 21:09:02 +01:00
Michael Young
e0018c4e82 4 security updates
xen/arm: Boot modules are not scrubbed [XSA-372, CVE-2021-28693]
inappropriate x86 IOMMU timeout detection / handling
	[XSA-373, CVE-2021-28692]
Speculative Code Store Bypass [XSA-375, CVE-2021-0089]
x86: TSX Async Abort protections not restored after S3
	[XSA-377, CVE-2021-28690]
2021-06-08 22:56:27 +01:00
Michael Young
5e6740fccc update to xen-4.14.2
remove or adjust patch content now included or superceded upstream

re-copy grub modules if they have changed
2021-05-04 22:06:08 +01:00
Michael Young
d5e266a6ac HVM soft-reset crashes toolstack [XSA-368, CVE-2021-28687] (#1940610) 2021-03-18 20:23:16 +00:00
11 changed files with 601 additions and 230 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.14.1.tar.gz
/xen-4.14.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.14.1.tar.gz) = c75cbec82793435f5a7026626ffdb2e9a2166b42d2be4b2f1194240e0312458124f0ebd53eeb02ce7330c22afe402a28a96b32f8af66e41e9416fe94535724c9
SHA512 (xen-4.14.3.tar.gz) = b462fcc1549f6e57f7f2a4fd10ce1e957a25a6a7c0319672b62699468f6c4330b9cd0cf2b0231b5cce94f4bb142a957eb8aa58aa0ffb5c85b37211d6b34ccf16

View file

@ -1,15 +1,3 @@
--- xen-4.14.0/xen/include/crypto/rijndael.h.orig 2020-07-23 16:07:51.000000000 +0100
+++ xen-4.14.0/xen/include/crypto/rijndael.h 2020-10-24 14:59:34.349318594 +0100
@@ -52,7 +52,7 @@
int rijndaelKeySetupEnc(unsigned int [], const unsigned char [], int);
int rijndaelKeySetupDec(unsigned int [], const unsigned char [], int);
-void rijndaelEncrypt(const unsigned int [], int, const unsigned char [],
- unsigned char []);
+void rijndaelEncrypt(const unsigned int [], int, const unsigned char [16],
+ unsigned char [16]);
#endif /* __RIJNDAEL_H */
--- xen-4.14.0/xen/include/crypto/vmac.h.orig 2020-07-23 16:07:51.000000000 +0100
+++ xen-4.14.0/xen/include/crypto/vmac.h 2020-10-24 15:45:49.246467465 +0100
@@ -142,7 +142,7 @@
@ -21,28 +9,6 @@
unsigned int mbytes,
vmac_ctx_t *ctx);
--- xen-4.14.0/tools/libs/foreignmemory/linux.c.orig 2020-07-23 16:07:51.000000000 +0100
+++ xen-4.14.0/tools/libs/foreignmemory/linux.c 2020-10-25 21:36:00.982040566 +0000
@@ -162,7 +162,7 @@
void *osdep_xenforeignmemory_map(xenforeignmemory_handle *fmem,
uint32_t dom, void *addr,
int prot, int flags, size_t num,
- const xen_pfn_t arr[/*num*/], int err[/*num*/])
+ const xen_pfn_t arr[num], int err[num])
{
int fd = fmem->fd;
privcmd_mmapbatch_v2_t ioctlx;
--- xen-4.14.0/tools/libs/foreignmemory/minios.c.orig 2020-07-23 16:07:51.000000000 +0100
+++ xen-4.14.0/tools/libs/foreignmemory/minios.c 2020-10-26 22:36:12.423883688 +0000
@@ -42,7 +42,7 @@
void *osdep_xenforeignmemory_map(xenforeignmemory_handle *fmem,
uint32_t dom, void *addr,
int prot, int flags, size_t num,
- const xen_pfn_t arr[/*num*/], int err[/*num*/])
+ const xen_pfn_t arr[num], int err[num])
{
unsigned long pt_prot = 0;
if (prot & PROT_READ)
diff --git a/xen/arch/x86/tboot.c b/xen/arch/x86/tboot.c
index 320e06f..618ae92 100644
--- a/xen/arch/x86/tboot.c
@ -56,20 +22,3 @@ index 320e06f..618ae92 100644
/* Look for valid page-aligned address for shared page. */
if ( !opt_tboot_pa || (opt_tboot_pa & ~PAGE_MASK) )
diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c b/xen/arch/x86/x86_emulate/x86_emulate.c
index 84bb8e0..6ecf5db 100644
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -725,9 +725,9 @@ union vex {
#define copy_VEX(ptr, vex) ({ \
if ( !mode_64bit() ) \
(vex).reg |= 8; \
- (ptr)[0 - PFX_BYTES] = ext < ext_8f08 ? 0xc4 : 0x8f; \
- (ptr)[1 - PFX_BYTES] = (vex).raw[0]; \
- (ptr)[2 - PFX_BYTES] = (vex).raw[1]; \
+ ((volatile uint8_t *)ptr)[0 - PFX_BYTES] = ext < ext_8f08 ? 0xc4 : 0x8f; \
+ ((volatile uint8_t *)ptr)[1 - PFX_BYTES] = (vex).raw[0]; \
+ ((volatile uint8_t *)ptr)[2 - PFX_BYTES] = (vex).raw[1]; \
container_of((ptr) + 1 - PFX_BYTES, typeof(vex), raw[0]); \
})

View file

@ -57,8 +57,8 @@
Summary: Xen is a virtual machine monitor
Name: xen
Version: 4.14.1
Release: 5%{?dist}
Version: 4.14.3
Release: 3%{?dist}
License: GPLv2+ and LGPLv2+ and BSD
URL: http://xen.org/
Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz
@ -112,14 +112,17 @@ Patch40: xen.drop.brctl.patch
Patch41: xen.gcc9.fixes.patch
Patch42: xen.gcc10.fixes.patch
Patch43: xen.gcc11.fixes.patch
Patch44: xsa360-4.14.patch
Patch45: xen.git-7c9f81687ad611515474b1c17afc2f79f19faef5.patch
Patch46: xen.git-35d2960ae65f28106fdc5c2130f5f08fadca0e4c.patch
Patch47: xen.git-d6627cf1b63ce57a6a7e2c1800dbc50eed742c32.patch
Patch48: xen.git-d8099d94dfaa3573bd86ebfc457cbc8f70a3ecda.patch
Patch49: xen.git-8169f82049efb5b2044b33aa482ba3a136b7804d.patch
Patch50: xsa363.patch
Patch51: xsa364.patch
Patch51: xsa386.patch
Patch52: xsa385-4.15.patch
Patch53: xsa388-4.14-1.patch
Patch54: xsa388-4.14-2.patch
Patch55: xsa389-4.14.patch
%if %build_qemutrad
@ -328,7 +331,6 @@ manage Xen virtual machines.
%patch41 -p1
%patch42 -p1
%patch43 -p1
%patch44 -p1
%patch45 -p1
%patch46 -p1
%patch47 -p1
@ -336,6 +338,10 @@ manage Xen virtual machines.
%patch49 -p1
%patch50 -p1
%patch51 -p1
%patch52 -p1
%patch53 -p1
%patch54 -p1
%patch55 -p1
# qemu-xen-traditional patches
pushd tools/qemu-xen-traditional
@ -612,16 +618,21 @@ do_it() {
if [ ! -d $TARGET ]; then
mkdir $TARGET
fi
if [ -f $DIR/relocator.mod -a ! -f $TARGET/relocator.mod ]; then
cp -p $DIR/relocator.mod $TARGET/relocator.mod
fi
if [ -f $DIR/multiboot2.mod -a ! -f $TARGET/multiboot2.mod ]; then
cp -p $DIR/multiboot2.mod $TARGET/multiboot2.mod
fi
for m in relocator.mod multiboot2.mod; do
if [ -f $DIR/$m ]; then
if [ ! -f $TARGET/$m ] || ! cmp -s $DIR/$m $TARGET/$m; then
cp -p $DIR/$m $TARGET/$m
fi
fi
done
fi
}
if [ $1 == 1 -a -f /sbin/grub2-mkconfig ]; then
%if "%dist" <= ".fc33"
for f in /boot/grub2/grub.cfg /boot/efi/EFI/fedora/grub.cfg; do
%else
for f in /boot/grub2/grub.cfg; do
%endif
if [ -f $f ]; then
/sbin/grub2-mkconfig -o $f
sed -i -e '/insmod module2/d' $f
@ -633,17 +644,26 @@ if [ -f /sbin/grub2-mkconfig ]; then
DIR=/usr/lib/grub/i386-pc
TARGET=/boot/grub2/i386-pc
do_it $DIR $TARGET
DIR=/usr/lib/grub/x86_64-efi
TARGET=/boot/grub2/x86_64-efi
do_it $DIR $TARGET
fi
%if "%dist" <= ".fc33"
if [ -f /boot/efi/EFI/fedora/grub.cfg ]; then
DIR=/usr/lib/grub/x86_64-efi
TARGET=/boot/efi/EFI/fedora/x86_64-efi
do_it $DIR $TARGET
fi
%endif
fi
%postun hypervisor
if [ -f /sbin/grub2-mkconfig ]; then
%if "%dist" <= ".fc33"
for f in /boot/grub2/grub.cfg /boot/efi/EFI/fedora/grub.cfg; do
%else
for f in /boot/grub2/grub.cfg; do
%endif
if [ -f $f ]; then
/sbin/grub2-mkconfig -o $f
sed -i -e '/insmod module2/d' $f
@ -928,6 +948,59 @@ fi
%endif
%changelog
* Tue Nov 23 2021 Michael Young <m.a.young@durham.ac.uk> - 4.14.3-3
- guests may exceed their designated memory limit [XSA-385, CVE-2021-28706]
- PoD operations on misaligned GFNs [XSA-388, CVE-2021-28704, CVE-2021-28707
CVE-2021-28708]
- issues with partially successful P2M updates on x86 [XSA-389,
CVE-2021-28705, CVE-2021-28709]
* Wed Oct 06 2021 Michael Young <m.a.young@durham.ac.uk> - 4.14.3-2
- PCI devices with RMRRs not deassigned correctly [XSA-386, CVE-2021-28702]
(#2011248)
* Mon Sep 13 2021 Michael Young <m.a.young@durham.ac.uk> - 4.14.3-1
- update to xen-4.14.3
remove or adjust patches now included or superceded upstream
* Wed Sep 08 2021 Michael Young <m.a.young@durham.ac.uk> - 4.14.2-4
- Another race in XENMAPSPACE_grant_table handling [XSA-384, CVE-2021-28701]
(#2002786)
- bugfix for XSA-380
- stop editing grub files in /boot/efi/EFI/fedora on Fedora 34
* Sat Aug 28 2021 Michael Young <m.a.young@durham.ac.uk> - 4.14.2-3
- IOMMU page mapping issues on x86 [XSA-378, CVE-2021-28694,
CVE-2021-28695, CVE-2021-28696] (#1997531) (#1997568)
(#1997537)
- grant table v2 status pages may remain accessible after de-allocation
[XSA-379, CVE-2021-28697] (#1997520)
- long running loops in grant table handling [XSA-380, CVE-2021-28698]
(#1997526)
- inadequate grant-v2 status frames array bounds check [XSA-382,
CVE-2021-28699] (#1997523)
- xen/arm: No memory limit for dom0less domUs [XSA-383, CVE-2021-28700]
(#1997527)
- grub x86_64-efi modules now go into /boot/grub2
* Tue Jun 08 2021 Michael Young <m.a.young@durham.ac.uk> - 4.14.2-2
- xen/arm: Boot modules are not scrubbed [XSA-372, CVE-2021-28693]
(#1970542)
- inappropriate x86 IOMMU timeout detection / handling
[XSA-373, CVE-2021-28692] (#1970540)
- Speculative Code Store Bypass [XSA-375, CVE-2021-0089, CVE-2021-26313]
(#1970531)
- x86: TSX Async Abort protections not restored after S3
[XSA-377, CVE-2021-28690] (#1970546)
* Tue May 04 2021 Michael Young <m.a.young@durham.ac.uk> - 4.14.2-1
- update to 4.14.2
remove or adjust patch content now included or superceded upstream
- re-copy grub modules if they have changed
* Thu Mar 18 2021 Michael Young <m.a.young@durham.ac.uk> - 4.14.1-7
- HVM soft-reset crashes toolstack [XSA-368, CVE-2021-28687] (#1940610)
* Tue Feb 16 2021 Michael Young <m.a.young@durham.ac.uk> - 4.14.1-5
- Linux: display frontend "be-alloc" mode is unsupported (comment only)
[XSA-363, CVE-2021-26934] (#1929549)

View file

@ -1,97 +0,0 @@
From: Roger Pau Monne <roger.pau@citrix.com>
Subject: x86/dpci: do not remove pirqs from domain tree on unbind
A fix for a previous issue removed the pirqs from the domain tree when
they are unbound in order to prevent shared pirqs from triggering a
BUG_ON in __pirq_guest_unbind if they are unbound multiple times. That
caused free_domain_pirqs to no longer unmap the pirqs because they
are gone from the domain pirq tree, thus leaving stale unbound pirqs
after domain destruction if the domain had mapped dpci pirqs after
shutdown.
Take a different approach to fix the original issue, instead of
removing the pirq from d->pirq_tree clear the flags of the dpci pirq
struct to signal that the pirq is now unbound. This prevents calling
pirq_guest_unbind multiple times for the same pirq without having to
remove it from the domain pirq tree.
This is XSA-360.
Fixes: 5b58dad089 ('x86/pass-through: avoid double IRQ unbind during domain cleanup')
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
--- a/xen/arch/x86/irq.c
+++ b/xen/arch/x86/irq.c
@@ -1331,7 +1331,7 @@ void (pirq_cleanup_check)(struct pirq *p
}
if ( radix_tree_delete(&d->pirq_tree, pirq->pirq) != pirq )
- BUG_ON(!d->is_dying);
+ BUG();
}
/* Flush all ready EOIs from the top of this CPU's pending-EOI stack. */
--- a/xen/drivers/passthrough/pci.c
+++ b/xen/drivers/passthrough/pci.c
@@ -862,6 +862,10 @@ static int pci_clean_dpci_irq(struct dom
{
struct dev_intx_gsi_link *digl, *tmp;
+ if ( !pirq_dpci->flags )
+ /* Already processed. */
+ return 0;
+
pirq_guest_unbind(d, dpci_pirq(pirq_dpci));
if ( pt_irq_need_timer(pirq_dpci->flags) )
@@ -872,15 +876,10 @@ static int pci_clean_dpci_irq(struct dom
list_del(&digl->list);
xfree(digl);
}
+ /* Note the pirq is now unbound. */
+ pirq_dpci->flags = 0;
- radix_tree_delete(&d->pirq_tree, dpci_pirq(pirq_dpci)->pirq);
-
- if ( !pt_pirq_softirq_active(pirq_dpci) )
- return 0;
-
- domain_get_irq_dpci(d)->pending_pirq_dpci = pirq_dpci;
-
- return -ERESTART;
+ return pt_pirq_softirq_active(pirq_dpci) ? -ERESTART : 0;
}
static int pci_clean_dpci_irqs(struct domain *d)
@@ -897,18 +896,8 @@ static int pci_clean_dpci_irqs(struct do
hvm_irq_dpci = domain_get_irq_dpci(d);
if ( hvm_irq_dpci != NULL )
{
- int ret = 0;
-
- if ( hvm_irq_dpci->pending_pirq_dpci )
- {
- if ( pt_pirq_softirq_active(hvm_irq_dpci->pending_pirq_dpci) )
- ret = -ERESTART;
- else
- hvm_irq_dpci->pending_pirq_dpci = NULL;
- }
+ int ret = pt_pirq_iterate(d, pci_clean_dpci_irq, NULL);
- if ( !ret )
- ret = pt_pirq_iterate(d, pci_clean_dpci_irq, NULL);
if ( ret )
{
spin_unlock(&d->event_lock);
--- a/xen/include/asm-x86/hvm/irq.h
+++ b/xen/include/asm-x86/hvm/irq.h
@@ -160,8 +160,6 @@ struct hvm_irq_dpci {
DECLARE_BITMAP(isairq_map, NR_ISAIRQS);
/* Record of mapped Links */
uint8_t link_cnt[NR_LINK];
- /* Clean up: Entry with a softirq invocation pending / in progress. */
- struct hvm_pirq_dpci *pending_pirq_dpci;
};
/* Machine IRQ to guest device/intx mapping. */

View file

@ -1,69 +0,0 @@
From dadb5b4b21c904ce59024c686eb1c55be8f46c52 Mon Sep 17 00:00:00 2001
From: Julien Grall <jgrall@amazon.com>
Date: Thu, 21 Jan 2021 10:16:08 +0000
Subject: [PATCH] xen/page_alloc: Only flush the page to RAM once we know they
are scrubbed
At the moment, each page are flushed to RAM just after the allocator
found some free pages. However, this is happening before check if the
page was scrubbed.
As a consequence, on Arm, a guest may be able to access the old content
of the scrubbed pages if it has cache disabled (default at boot) and
the content didn't reach the Point of Coherency.
The flush is now moved after we know the content of the page will not
change. This also has the benefit to reduce the amount of work happening
with the heap_lock held.
This is XSA-364.
Fixes: 307c3be3ccb2 ("mm: Don't scrub pages while holding heap lock in alloc_heap_pages()")
Signed-off-by: Julien Grall <jgrall@amazon.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
---
xen/common/page_alloc.c | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
index 02ac1fa613e7..1744e6faa5c4 100644
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -924,6 +924,7 @@ static struct page_info *alloc_heap_pages(
bool need_tlbflush = false;
uint32_t tlbflush_timestamp = 0;
unsigned int dirty_cnt = 0;
+ mfn_t mfn;
/* Make sure there are enough bits in memflags for nodeID. */
BUILD_BUG_ON((_MEMF_bits - _MEMF_node) < (8 * sizeof(nodeid_t)));
@@ -1022,11 +1023,6 @@ static struct page_info *alloc_heap_pages(
pg[i].u.inuse.type_info = 0;
page_set_owner(&pg[i], NULL);
- /* Ensure cache and RAM are consistent for platforms where the
- * guest can control its own visibility of/through the cache.
- */
- flush_page_to_ram(mfn_x(page_to_mfn(&pg[i])),
- !(memflags & MEMF_no_icache_flush));
}
spin_unlock(&heap_lock);
@@ -1062,6 +1058,14 @@ static struct page_info *alloc_heap_pages(
if ( need_tlbflush )
filtered_flush_tlb_mask(tlbflush_timestamp);
+ /*
+ * Ensure cache and RAM are consistent for platforms where the guest
+ * can control its own visibility of/through the cache.
+ */
+ mfn = page_to_mfn(pg);
+ for ( i = 0; i < (1U << order); i++ )
+ flush_page_to_ram(mfn_x(mfn) + i, !(memflags & MEMF_no_icache_flush));
+
return pg;
}
--
2.17.1

96
xsa385-4.15.patch Normal file
View file

@ -0,0 +1,96 @@
From: Julien Grall <jgrall@amazon.com>
Subject: xen/page_alloc: Harden assign_pages()
domain_tot_pages() and d->max_pages are 32-bit values. While the order
should always be quite small, it would still be possible to overflow
if domain_tot_pages() is near to (2^32 - 1).
As this code may be called by a guest via XENMEM_increase_reservation
and XENMEM_populate_physmap, we want to make sure the guest is not going
to be able to allocate more than it is allowed.
Rework the allocation check to avoid any possible overflow. While the
check domain_tot_pages() < d->max_pages should technically not be
necessary, it is probably best to have it to catch any possible
inconsistencies in the future.
This is CVE-2021-28706 / XSA-385.
Signed-off-by: Julien Grall <jgrall@amazon.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -2336,7 +2336,8 @@ gnttab_transfer(
* pages when it is dying.
*/
if ( unlikely(e->is_dying) ||
- unlikely(domain_tot_pages(e) >= e->max_pages) )
+ unlikely(domain_tot_pages(e) >= e->max_pages) ||
+ unlikely(!(e->tot_pages + 1)) )
{
spin_unlock(&e->page_alloc_lock);
@@ -2345,8 +2346,8 @@ gnttab_transfer(
e->domain_id);
else
gdprintk(XENLOG_INFO,
- "Transferee d%d has no headroom (tot %u, max %u)\n",
- e->domain_id, domain_tot_pages(e), e->max_pages);
+ "Transferee %pd has no headroom (tot %u, max %u, ex %u)\n",
+ e, domain_tot_pages(e), e->max_pages, e->extra_pages);
gop.status = GNTST_general_error;
goto unlock_and_copyback;
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -2298,20 +2298,43 @@ int assign_pages(
}
else if ( !(memflags & MEMF_no_refcount) )
{
- unsigned int tot_pages = domain_tot_pages(d) + (1 << order);
+ unsigned int tot_pages = domain_tot_pages(d), nr = 1u << order;
if ( unlikely(tot_pages > d->max_pages) )
{
- gprintk(XENLOG_INFO, "Over-allocation for domain %u: "
- "%u > %u\n", d->domain_id, tot_pages, d->max_pages);
+ gprintk(XENLOG_INFO, "Inconsistent allocation for %pd: %u > %u\n",
+ d, tot_pages, d->max_pages);
+ rc = -EPERM;
+ goto out;
+ }
+
+ if ( unlikely(nr > d->max_pages - tot_pages) )
+ {
+ gprintk(XENLOG_INFO, "Over-allocation for %pd: %Lu > %u\n",
+ d, tot_pages + 0ull + nr, d->max_pages);
rc = -E2BIG;
goto out;
}
}
- if ( !(memflags & MEMF_no_refcount) &&
- unlikely(domain_adjust_tot_pages(d, 1 << order) == (1 << order)) )
- get_knownalive_domain(d);
+ if ( !(memflags & MEMF_no_refcount) )
+ {
+ unsigned int nr = 1u << order;
+
+ if ( unlikely(d->tot_pages + nr < nr) )
+ {
+ gprintk(XENLOG_INFO,
+ "Excess allocation for %pd: %Lu (%u extra)\n",
+ d, d->tot_pages + 0ull + nr, d->extra_pages);
+ if ( pg[0].count_info & PGC_extra )
+ d->extra_pages -= nr;
+ rc = -E2BIG;
+ goto out;
+ }
+
+ if ( unlikely(domain_adjust_tot_pages(d, nr) == nr) )
+ get_knownalive_domain(d);
+ }
for ( i = 0; i < (1 << order); i++ )
{

29
xsa386.patch Normal file
View file

@ -0,0 +1,29 @@
From: Jan Beulich <jbeulich@suse.com>
Subject: VT-d: fix deassign of device with RMRR
Date: Fri, 1 Oct 2021 15:05:42 +0200
Ignoring a specific error code here was not meant to short circuit
deassign to _just_ the unmapping of RMRRs. This bug was previously
hidden by the bogus (potentially indefinite) looping in
pci_release_devices(), until f591755823a7 ("IOMMU/PCI: don't let domain
cleanup continue when device de-assignment failed") fixed that loop.
This is CVE-2021-28702 / XSA-386.
Fixes: 8b99f4400b69 ("VT-d: fix RMRR related error handling")
Reported-by: Ivan Kardykov <kardykov@tabit.pro>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Tested-by: Ivan Kardykov <kardykov@tabit.pro>
--- a/xen/drivers/passthrough/vtd/iommu.c
+++ b/xen/drivers/passthrough/vtd/iommu.c
@@ -2409,7 +2409,7 @@ static int reassign_device_ownership(
ret = iommu_identity_mapping(source, p2m_access_x,
rmrr->base_address,
rmrr->end_address, 0);
- if ( ret != -ENOENT )
+ if ( ret && ret != -ENOENT )
return ret;
}
}

174
xsa388-4.14-1.patch Normal file
View file

@ -0,0 +1,174 @@
From: Jan Beulich <jbeulich@suse.com>
Subject: x86/PoD: deal with misaligned GFNs
Users of XENMEM_decrease_reservation and XENMEM_populate_physmap aren't
required to pass in order-aligned GFN values. (While I consider this
bogus, I don't think we can fix this there, as that might break existing
code, e.g Linux'es swiotlb, which - while affecting PV only - until
recently had been enforcing only page alignment on the original
allocation.) Only non-PoD code paths (guest_physmap_{add,remove}_page(),
p2m_set_entry()) look to be dealing with this properly (in part by being
implemented inefficiently, handling every 4k page separately).
Introduce wrappers taking care of splitting the incoming request into
aligned chunks, without putting much effort in trying to determine the
largest possible chunk at every iteration.
Also "handle" p2m_set_entry() failure for non-order-0 requests by
crashing the domain in one more place. Alongside putting a log message
there, also add one to the other similar path.
Note regarding locking: This is left in the actual worker functions on
the assumption that callers aren't guaranteed atomicity wrt acting on
multiple pages at a time. For mis-aligned GFNs gfn_lock() wouldn't have
locked the correct GFN range anyway, if it didn't simply resolve to
p2m_lock(), and for well-behaved callers there continues to be only a
single iteration, i.e. behavior is unchanged for them. (FTAOD pulling
out just pod_lock() into p2m_pod_decrease_reservation() would result in
a lock order violation.)
This is CVE-2021-28704 and CVE-2021-28707 / part of XSA-388.
Fixes: 3c352011c0d3 ("x86/PoD: shorten certain operations on higher order ranges")
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
--- a/xen/arch/x86/mm/p2m-pod.c
+++ b/xen/arch/x86/mm/p2m-pod.c
@@ -495,7 +495,7 @@ p2m_pod_zero_check_superpage(struct p2m_
/*
- * This function is needed for two reasons:
+ * This pair of functions is needed for two reasons:
* + To properly handle clearing of PoD entries
* + To "steal back" memory being freed for the PoD cache, rather than
* releasing it.
@@ -503,8 +503,8 @@ p2m_pod_zero_check_superpage(struct p2m_
* Once both of these functions have been completed, we can return and
* allow decrease_reservation() to handle everything else.
*/
-unsigned long
-p2m_pod_decrease_reservation(struct domain *d, gfn_t gfn, unsigned int order)
+static unsigned long
+decrease_reservation(struct domain *d, gfn_t gfn, unsigned int order)
{
unsigned long ret = 0, i, n;
struct p2m_domain *p2m = p2m_get_hostp2m(d);
@@ -551,8 +551,10 @@ p2m_pod_decrease_reservation(struct doma
* All PoD: Mark the whole region invalid and tell caller
* we're done.
*/
- if ( p2m_set_entry(p2m, gfn, INVALID_MFN, order, p2m_invalid,
- p2m->default_access) )
+ int rc = p2m_set_entry(p2m, gfn, INVALID_MFN, order, p2m_invalid,
+ p2m->default_access);
+
+ if ( rc )
{
/*
* If this fails, we can't tell how much of the range was changed.
@@ -560,7 +562,12 @@ p2m_pod_decrease_reservation(struct doma
* impossible.
*/
if ( order != 0 )
+ {
+ printk(XENLOG_G_ERR
+ "%pd: marking GFN %#lx (order %u) as non-PoD failed: %d\n",
+ d, gfn_x(gfn), order, rc);
domain_crash(d);
+ }
goto out_unlock;
}
ret = 1UL << order;
@@ -667,6 +674,22 @@ out_unlock:
return ret;
}
+unsigned long
+p2m_pod_decrease_reservation(struct domain *d, gfn_t gfn, unsigned int order)
+{
+ unsigned long left = 1UL << order, ret = 0;
+ unsigned int chunk_order = find_first_set_bit(gfn_x(gfn) | left);
+
+ do {
+ ret += decrease_reservation(d, gfn, chunk_order);
+
+ left -= 1UL << chunk_order;
+ gfn = gfn_add(gfn, 1UL << chunk_order);
+ } while ( left );
+
+ return ret;
+}
+
void p2m_pod_dump_data(struct domain *d)
{
struct p2m_domain *p2m = p2m_get_hostp2m(d);
@@ -1266,19 +1289,15 @@ remap_and_retry:
return true;
}
-
-int
-guest_physmap_mark_populate_on_demand(struct domain *d, unsigned long gfn_l,
- unsigned int order)
+static int
+mark_populate_on_demand(struct domain *d, unsigned long gfn_l,
+ unsigned int order)
{
struct p2m_domain *p2m = p2m_get_hostp2m(d);
gfn_t gfn = _gfn(gfn_l);
unsigned long i, n, pod_count = 0;
int rc = 0;
- if ( !paging_mode_translate(d) )
- return -EINVAL;
-
gfn_lock(p2m, gfn, order);
P2M_DEBUG("mark pod gfn=%#lx\n", gfn_l);
@@ -1316,12 +1335,44 @@ guest_physmap_mark_populate_on_demand(st
BUG_ON(p2m->pod.entry_count < 0);
pod_unlock(p2m);
}
+ else if ( order )
+ {
+ /*
+ * If this failed, we can't tell how much of the range was changed.
+ * Best to crash the domain.
+ */
+ printk(XENLOG_G_ERR
+ "%pd: marking GFN %#lx (order %u) as PoD failed: %d\n",
+ d, gfn_l, order, rc);
+ domain_crash(d);
+ }
out:
gfn_unlock(p2m, gfn, order);
return rc;
}
+
+int
+guest_physmap_mark_populate_on_demand(struct domain *d, unsigned long gfn,
+ unsigned int order)
+{
+ unsigned long left = 1UL << order;
+ unsigned int chunk_order = find_first_set_bit(gfn | left);
+ int rc;
+
+ if ( !paging_mode_translate(d) )
+ return -EINVAL;
+
+ do {
+ rc = mark_populate_on_demand(d, gfn, chunk_order);
+
+ left -= 1UL << chunk_order;
+ gfn += 1UL << chunk_order;
+ } while ( !rc && left );
+
+ return rc;
+}
void p2m_pod_init(struct p2m_domain *p2m)
{

36
xsa388-4.14-2.patch Normal file
View file

@ -0,0 +1,36 @@
From: Jan Beulich <jbeulich@suse.com>
Subject: x86/PoD: handle intermediate page orders in p2m_pod_cache_add()
p2m_pod_decrease_reservation() may pass pages to the function which
aren't 4k, 2M, or 1G. Handle all intermediate orders as well, to avoid
hitting the BUG() at the switch() statement's "default" case.
This is CVE-2021-28708 / part of XSA-388.
Fixes: 3c352011c0d3 ("x86/PoD: shorten certain operations on higher order ranges")
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
--- a/xen/arch/x86/mm/p2m-pod.c
+++ b/xen/arch/x86/mm/p2m-pod.c
@@ -111,15 +111,13 @@ p2m_pod_cache_add(struct p2m_domain *p2m
/* Then add to the appropriate populate-on-demand list. */
switch ( order )
{
- case PAGE_ORDER_1G:
- for ( i = 0; i < (1UL << PAGE_ORDER_1G); i += 1UL << PAGE_ORDER_2M )
+ case PAGE_ORDER_2M ... PAGE_ORDER_1G:
+ for ( i = 0; i < (1UL << order); i += 1UL << PAGE_ORDER_2M )
page_list_add_tail(page + i, &p2m->pod.super);
break;
- case PAGE_ORDER_2M:
- page_list_add_tail(page, &p2m->pod.super);
- break;
- case PAGE_ORDER_4K:
- page_list_add_tail(page, &p2m->pod.single);
+ case PAGE_ORDER_4K ... PAGE_ORDER_2M - 1:
+ for ( i = 0; i < (1UL << order); i += 1UL << PAGE_ORDER_4K )
+ page_list_add_tail(page + i, &p2m->pod.single);
break;
default:
BUG();

180
xsa389-4.14.patch Normal file
View file

@ -0,0 +1,180 @@
From: Jan Beulich <jbeulich@suse.com>
Subject: x86/P2M: deal with partial success of p2m_set_entry()
M2P and PoD stats need to remain in sync with P2M; if an update succeeds
only partially, respective adjustments need to be made. If updates get
made before the call, they may also need undoing upon complete failure
(i.e. including the single-page case).
Log-dirty state would better also be kept in sync.
Note that the change to set_typed_p2m_entry() may not be strictly
necessary (due to the order restriction enforced near the top of the
function), but is being kept here to be on the safe side.
This is CVE-2021-28705 and CVE-2021-28709 / XSA-389.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -780,6 +780,7 @@ p2m_remove_page(struct p2m_domain *p2m,
unsigned long i;
p2m_type_t t;
p2m_access_t a;
+ int rc;
/* IOMMU for PV guests is handled in get_page_type() and put_page(). */
if ( !paging_mode_translate(p2m->domain) )
@@ -813,8 +814,27 @@ p2m_remove_page(struct p2m_domain *p2m,
}
}
- return p2m_set_entry(p2m, gfn, INVALID_MFN, page_order, p2m_invalid,
- p2m->default_access);
+ rc = p2m_set_entry(p2m, gfn, INVALID_MFN, page_order, p2m_invalid,
+ p2m->default_access);
+ if ( likely(!rc) || !mfn_valid(mfn) )
+ return rc;
+
+ /*
+ * The operation may have partially succeeded. For the failed part we need
+ * to undo the M2P update and, out of precaution, mark the pages dirty
+ * again.
+ */
+ for ( i = 0; i < (1UL << page_order); ++i )
+ {
+ p2m->get_entry(p2m, gfn_add(gfn, i), &t, &a, 0, NULL, NULL);
+ if ( !p2m_is_hole(t) && !p2m_is_special(t) && !p2m_is_shared(t) )
+ {
+ set_gpfn_from_mfn(mfn_x(mfn) + i, gfn_x(gfn) + i);
+ paging_mark_pfn_dirty(p2m->domain, _pfn(gfn_x(gfn) + i));
+ }
+ }
+
+ return rc;
}
int
@@ -1003,13 +1023,8 @@ guest_physmap_add_entry(struct domain *d
/* Now, actually do the two-way mapping */
rc = p2m_set_entry(p2m, gfn, mfn, page_order, t, p2m->default_access);
- if ( rc == 0 )
+ if ( likely(!rc) )
{
- pod_lock(p2m);
- p2m->pod.entry_count -= pod_count;
- BUG_ON(p2m->pod.entry_count < 0);
- pod_unlock(p2m);
-
if ( !p2m_is_grant(t) )
{
for ( i = 0; i < (1UL << page_order); i++ )
@@ -1017,6 +1032,42 @@ guest_physmap_add_entry(struct domain *d
gfn_x(gfn_add(gfn, i)));
}
}
+ else
+ {
+ /*
+ * The operation may have partially succeeded. For the successful part
+ * we need to update M2P and dirty state, while for the failed part we
+ * may need to adjust PoD stats as well as undo the earlier M2P update.
+ */
+ for ( i = 0; i < (1UL << page_order); ++i )
+ {
+ omfn = p2m->get_entry(p2m, gfn_add(gfn, i), &ot, &a, 0, NULL, NULL);
+ if ( p2m_is_pod(ot) )
+ {
+ BUG_ON(!pod_count);
+ --pod_count;
+ }
+ else if ( mfn_eq(omfn, mfn_add(mfn, i)) && ot == t &&
+ a == p2m->default_access && !p2m_is_grant(t) )
+ {
+ set_gpfn_from_mfn(mfn_x(omfn), gfn_x(gfn) + i);
+ paging_mark_pfn_dirty(d, _pfn(gfn_x(gfn) + i));
+ }
+ else if ( p2m_is_ram(ot) && !p2m_is_paged(ot) )
+ {
+ ASSERT(mfn_valid(omfn));
+ set_gpfn_from_mfn(mfn_x(omfn), gfn_x(gfn) + i);
+ }
+ }
+ }
+
+ if ( pod_count )
+ {
+ pod_lock(p2m);
+ p2m->pod.entry_count -= pod_count;
+ BUG_ON(p2m->pod.entry_count < 0);
+ pod_unlock(p2m);
+ }
out:
p2m_unlock(p2m);
@@ -1308,6 +1359,49 @@ static int set_typed_p2m_entry(struct do
return 0;
}
}
+
+ P2M_DEBUG("set %d %lx %lx\n", gfn_p2mt, gfn_l, mfn_x(mfn));
+ rc = p2m_set_entry(p2m, gfn, mfn, order, gfn_p2mt, access);
+ if ( unlikely(rc) )
+ {
+ gdprintk(XENLOG_ERR, "p2m_set_entry: %#lx:%u -> %d (0x%"PRI_mfn")\n",
+ gfn_l, order, rc, mfn_x(mfn));
+
+ /*
+ * The operation may have partially succeeded. For the successful part
+ * we need to update PoD stats, M2P, and dirty state.
+ */
+ if ( order != PAGE_ORDER_4K )
+ {
+ unsigned long i;
+
+ for ( i = 0; i < (1UL << order); ++i )
+ {
+ p2m_type_t t;
+ mfn_t cmfn = p2m->get_entry(p2m, gfn_add(gfn, i), &t, &a, 0,
+ NULL, NULL);
+
+ if ( !mfn_eq(cmfn, mfn_add(mfn, i)) || t != gfn_p2mt ||
+ a != access )
+ continue;
+
+ if ( p2m_is_ram(ot) )
+ {
+ ASSERT(mfn_valid(mfn_add(omfn, i)));
+ set_gpfn_from_mfn(mfn_x(omfn) + i, INVALID_M2P_ENTRY);
+ }
+#ifdef CONFIG_HVM
+ else if ( p2m_is_pod(ot) )
+ {
+ pod_lock(p2m);
+ BUG_ON(!p2m->pod.entry_count);
+ --p2m->pod.entry_count;
+ pod_unlock(p2m);
+ }
+#endif
+ }
+ }
+ }
else if ( p2m_is_ram(ot) )
{
unsigned long i;
@@ -1318,12 +1412,6 @@ static int set_typed_p2m_entry(struct do
set_gpfn_from_mfn(mfn_x(omfn) + i, INVALID_M2P_ENTRY);
}
}
-
- P2M_DEBUG("set %d %lx %lx\n", gfn_p2mt, gfn_l, mfn_x(mfn));
- rc = p2m_set_entry(p2m, gfn, mfn, order, gfn_p2mt, access);
- if ( rc )
- gdprintk(XENLOG_ERR, "p2m_set_entry: %#lx:%u -> %d (0x%"PRI_mfn")\n",
- gfn_l, order, rc, mfn_x(mfn));
#ifdef CONFIG_HVM
else if ( p2m_is_pod(ot) )
{