Xen Security Advisory 385 v2 (CVE-2021-28706) - guests may exceed their designated memory limit
Xen.org security team <[email protected]> Tue, 23 Nov 2021 12:11:12 +0000
| Newsgroups | gmane.comp.emulators.xen.announce |
|---|---|
| Message-ID | <E1mpUdk-0004TE-9S__28527.2913913772$1637669738$gmane$org@xenbits.xenproject.org> |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
Xen Security Advisory CVE-2021-28706 / XSA-385
version 2
guests may exceed their designated memory limit
UPDATES IN VERSION 2
====================
Add CVE numbers to patches.
Public release.
ISSUE DESCRIPTION
=================
When a guest is permitted to have close to 16TiB of memory, it may be
able to issue hypercalls to increase its memory allocation beyond the
administrator established limit. This is a result of a calculation
done with 32-bit precision, which may overflow. It would then only
be the overflowed (and hence small) number which gets compared against
the established upper bound.
IMPACT
======
A guest may be able too allocate unbounded amounts of memory to itself.
This may result in a Denial of Service (DoS) affecting the entire host.
VULNERABLE SYSTEMS
==================
All Xen versions from at least 3.2 onwards are affected.
On x86, only Xen builds with the BIGMEM configuration option enabled are
affected. (This option is off by default.)
Only hosts with more than 16 TiB of memory are affected.
MITIGATION
==========
Setting the maximum amount of memory a guest may allocate to strictly
less than 1023 GiB will avoid the vulnerability.
CREDITS
=======
This issue was discovered by Julien Grall of Amazon.
RESOLUTION
==========
Applying the appropriate first attached patch resolves this specific
issue. The second patch in addition documents altered support status of
Xen on huge memory systems.
Note that patches for released versions are generally prepared to
apply to the stable branches, and may not apply cleanly to the most
recent release tarball. Downstreams are encouraged to update to the
tip of the stable branch before applying these patches.
xsa385-?.patch xen-unstable
xsa385-4.15.patch Xen 4.15.x - 4.14.x
xsa385-4.13.patch Xen 4.13.x
xsa385-4.12.patch Xen 4.12.x
$ sha256sum xsa385*
b278902e293730a117605200910180bb842cf95db4bdedfd54b42b7314041d8c xsa385-1.patch
46a5ccfbb763b857f6cd0df46a9b7eed155b9de399ca4c68c9925faf4d1d9adb xsa385-2.patch
69ebe63dc7dca71f74260af19205a6387be56c7dc67b97fa7695ab1acd3c4da4 xsa385-4.12.patch
858eaad715e7cc62c4ab9784360f4ec77df70b2636b0755afe780d5c618cf9b4 xsa385-4.13.patch
831e86c3adfec532b1a48a0b967b7c58c37db3733aee8d78216eb9d535b34f12 xsa385-4.15.patch
$
DEPLOYMENT DURING EMBARGO
=========================
Deployment of the patches described above (or others which are
substantially similar) is permitted during the embargo, even on public-
facing systems with untrusted guest users and administrators.
HOWEVER, deployment of the mitigation described above is NOT permitted
during the embargo on public-facing systems with untrusted guest users
and administrators. This is because such a configuration change is
recognizable by the affected guests.
AND: Distribution of updated software is prohibited (except to other
members of the predisclosure list).
Predisclosure list members who wish to deploy significantly different
patches and/or mitigations, please contact the Xen Project Security
Team.
(Note: this during-embargo deployment notice is retained in
post-embargo publicly released Xen Project advisories, even though it
is then no longer applicable. This is to enable the community to have
oversight of the Xen Project Security Team's decisionmaking.)
For more information about permissible uses of embargoed information,
consult the Xen Project community's agreed Security Policy:
http://www.xenproject.org/security-policy.html
-----BEGIN PGP SIGNATURE-----
iQFABAEBCAAqFiEEI+MiLBRfRHX6gGCng/4UyVfoK9kFAmGc2jYMHHBncEB4ZW4u
b3JnAAoJEIP+FMlX6CvZEd4IAMwrHHAqFvSHgZ8Uw+DzMeT54db9nowudP9i/kYy
+KobbVlGkxwLAU3mvh5lRkOLYzoIonrcA99cajZQNIcOKt3Mfi/8qzGGUN+hWZvh
6EZo3m7+7vx9mhtAeDBUbjkcZBLiVyxRAWALMS67ScBEX9lZTvbyj9nGkdQJmmfR
pKt98z2Da2uR9YF521KWobuPYC0AFXujYBoavaTQpU/M8SiM+Wp1A2Fc6ZG+9ZKo
frMeqFbHvwj94Hbqpn6CoLu2d/XnykMvttuLlqCKTccQc3puHXdQRz14W8IxxGYx
gqYaIShZCFw/bUCu8mYHroDUlELJI3PIWQ1nJxy02bd5+N0=
=7E6A
-----END PGP SIGNATURE-----
xsa385-1.patch
(application/octet-stream, 3.9 KB)
From: Julien Grall <[email protected]> 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 / part of XSA-385. Signed-off-by: Julien Grall <[email protected]> Signed-off-by: Jan Beulich <[email protected]> Reviewed-by: Roger Pau Monné <[email protected]> --- v3: Re-base. v2: Limit to just the security relevant part. Use tot_pages (not d->tot_pages) as necessary. Also account for overflow from PGC_extra allocations. Use distinct error codes for the two cases. Avoid logging a bogus (wrapped) very small value. Also adjust gnttab_transfer(). --- There's yet another similar case in mem-sharing, but that's not security supported, so doesn't get adjusted here. --- a/xen/common/grant_table.c +++ b/xen/common/grant_table.c @@ -2324,7 +2324,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); @@ -2333,8 +2334,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 @@ -2305,20 +2305,41 @@ int assign_pages( } else if ( !(memflags & MEMF_no_refcount) ) { - unsigned int tot_pages = domain_tot_pages(d) + nr; + unsigned int tot_pages = domain_tot_pages(d); 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, nr) == nr) ) - get_knownalive_domain(d); + if ( !(memflags & MEMF_no_refcount) ) + { + 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 < nr; i++ ) {
xsa385-2.patch
(application/octet-stream, 735 B)
From: Jan Beulich <[email protected]> Subject: SUPPORT.md: limit security support for hosts with very much memory Sufficient and in particular regular testing on very large hosts cannot currently be guaranteed. Anyone wanting us to support larger hosts is free to propose so, but will need to supply not only test results, but also a test plan. This is part of XSA-385. Signed-off-by: Jan Beulich <[email protected]> --- a/SUPPORT.md +++ b/SUPPORT.md @@ -48,6 +48,12 @@ For the Cortex A57 r0p0 - r1p1, see Erra Status, x86: Supported +### Physical Memory + + Status: Supported up to 8 TiB + +Hosts with more memory are supported, but not security supported. + ### Physical Memory Hotplug Status, x86: Supported
xsa385-4.12.patch
(application/octet-stream, 3 KB)
From: Julien Grall <[email protected]> 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 <[email protected]> Signed-off-by: Jan Beulich <[email protected]> Reviewed-by: Roger Pau Monné <[email protected]> --- a/xen/common/grant_table.c +++ b/xen/common/grant_table.c @@ -2239,7 +2239,8 @@ gnttab_transfer( * pages when it is dying. */ if ( unlikely(e->is_dying) || - unlikely(e->tot_pages >= e->max_pages) ) + unlikely(e->tot_pages >= e->max_pages) || + unlikely(!(e->tot_pages + 1)) ) { spin_unlock(&e->page_alloc_lock); @@ -2248,8 +2249,8 @@ gnttab_transfer( e->domain_id); else gdprintk(XENLOG_INFO, - "Transferee d%d has no headroom (tot %u, max %u)\n", - e->domain_id, e->tot_pages, e->max_pages); + "Transferee %pd has no headroom (tot %u, max %u)\n", + e, e->tot_pages, e->max_pages); gop.status = GNTST_general_error; goto unlock_and_copyback; --- a/xen/common/page_alloc.c +++ b/xen/common/page_alloc.c @@ -2278,17 +2278,26 @@ int assign_pages( if ( !(memflags & MEMF_no_refcount) ) { - if ( unlikely((d->tot_pages + (1 << order)) > d->max_pages) ) + unsigned int nr = 1u << order; + + if ( unlikely(d->tot_pages > d->max_pages) ) + { + gprintk(XENLOG_INFO, "Inconsistent allocation for %pd: %u > %u\n", + d, d->tot_pages, d->max_pages); + rc = -EPERM; + goto out; + } + + if ( unlikely(nr > d->max_pages - d->tot_pages) ) { if ( !tmem_enabled() || order != 0 || d->tot_pages != d->max_pages ) - gprintk(XENLOG_INFO, "Over-allocation for domain %u: " - "%u > %u\n", d->domain_id, - d->tot_pages + (1 << order), d->max_pages); + gprintk(XENLOG_INFO, "Over-allocation for %pd: %Lu > %u\n", + d, d->tot_pages + 0ull + nr, d->max_pages); rc = -E2BIG; goto out; } - if ( unlikely(domain_adjust_tot_pages(d, 1 << order) == (1 << order)) ) + if ( unlikely(domain_adjust_tot_pages(d, nr) == nr) ) get_knownalive_domain(d); }
xsa385-4.13.patch
(application/octet-stream, 2.9 KB)
From: Julien Grall <[email protected]> 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 <[email protected]> Signed-off-by: Jan Beulich <[email protected]> Reviewed-by: Roger Pau Monné <[email protected]> --- a/xen/common/grant_table.c +++ b/xen/common/grant_table.c @@ -2286,7 +2286,8 @@ gnttab_transfer( * pages when it is dying. */ if ( unlikely(e->is_dying) || - unlikely(e->tot_pages >= e->max_pages) ) + unlikely(e->tot_pages >= e->max_pages) || + unlikely(!(e->tot_pages + 1)) ) { spin_unlock(&e->page_alloc_lock); @@ -2295,8 +2296,8 @@ gnttab_transfer( e->domain_id); else gdprintk(XENLOG_INFO, - "Transferee d%d has no headroom (tot %u, max %u)\n", - e->domain_id, e->tot_pages, e->max_pages); + "Transferee %pd has no headroom (tot %u, max %u)\n", + e, e->tot_pages, e->max_pages); gop.status = GNTST_general_error; goto unlock_and_copyback; --- a/xen/common/page_alloc.c +++ b/xen/common/page_alloc.c @@ -2276,16 +2276,25 @@ int assign_pages( if ( !(memflags & MEMF_no_refcount) ) { - if ( unlikely((d->tot_pages + (1 << order)) > d->max_pages) ) + unsigned int nr = 1u << order; + + if ( unlikely(d->tot_pages > d->max_pages) ) + { + gprintk(XENLOG_INFO, "Inconsistent allocation for %pd: %u > %u\n", + d, d->tot_pages, d->max_pages); + rc = -EPERM; + goto out; + } + + if ( unlikely(nr > d->max_pages - d->tot_pages) ) { - gprintk(XENLOG_INFO, "Over-allocation for domain %u: " - "%u > %u\n", d->domain_id, - d->tot_pages + (1 << order), d->max_pages); + gprintk(XENLOG_INFO, "Over-allocation for %pd: %Lu > %u\n", + d, d->tot_pages + 0ull + nr, d->max_pages); rc = -E2BIG; goto out; } - if ( unlikely(domain_adjust_tot_pages(d, 1 << order) == (1 << order)) ) + if ( unlikely(domain_adjust_tot_pages(d, nr) == nr) ) get_knownalive_domain(d); }
xsa385-4.15.patch
(application/octet-stream, 3.5 KB)
From: Julien Grall <[email protected]> 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 <[email protected]> Signed-off-by: Jan Beulich <[email protected]> --- 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++ ) {