summaryrefslogtreecommitdiff
path: root/system/xen/xsa/xsa236-4.9.patch
diff options
context:
space:
mode:
Diffstat (limited to 'system/xen/xsa/xsa236-4.9.patch')
-rw-r--r--system/xen/xsa/xsa236-4.9.patch66
1 files changed, 66 insertions, 0 deletions
diff --git a/system/xen/xsa/xsa236-4.9.patch b/system/xen/xsa/xsa236-4.9.patch
new file mode 100644
index 0000000000..203025dbae
--- /dev/null
+++ b/system/xen/xsa/xsa236-4.9.patch
@@ -0,0 +1,66 @@
+From: Jan Beulich <jbeulich@suse.com>
+Subject: gnttab: fix pin count / page reference race
+
+Dropping page references before decrementing pin counts is a bad idea
+if assumptions are being made that a non-zero pin count implies a valid
+page. Fix the order of operations in gnttab_copy_release_buf(), but at
+the same time also remove the assertion that was found to trigger:
+map_grant_ref() also has the potential of causing a race here, and
+changing the order of operations there would likely be quite a bit more
+involved.
+
+This is XSA-236.
+
+Reported-by: Pawel Wieczorkiewicz <wipawel@amazon.de>
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
+
+--- a/xen/common/grant_table.c
++++ b/xen/common/grant_table.c
+@@ -2330,9 +2330,20 @@ __acquire_grant_for_copy(
+ td = page_get_owner_and_reference(*page);
+ /*
+ * act->pin being non-zero should guarantee the page to have a
+- * non-zero refcount and hence a valid owner.
++ * non-zero refcount and hence a valid owner (matching the one on
++ * record), with one exception: If the owning domain is dying we
++ * had better not make implications from pin count (map_grant_ref()
++ * updates pin counts before obtaining page references, for
++ * example).
+ */
+- ASSERT(td);
++ if ( td != rd || rd->is_dying )
++ {
++ if ( td )
++ put_page(*page);
++ *page = NULL;
++ rc = GNTST_bad_domain;
++ goto unlock_out_clear;
++ }
+ }
+
+ act->pin += readonly ? GNTPIN_hstr_inc : GNTPIN_hstw_inc;
+@@ -2451,6 +2462,11 @@ static void gnttab_copy_release_buf(stru
+ unmap_domain_page(buf->virt);
+ buf->virt = NULL;
+ }
++ if ( buf->have_grant )
++ {
++ __release_grant_for_copy(buf->domain, buf->ptr.u.ref, buf->read_only);
++ buf->have_grant = 0;
++ }
+ if ( buf->have_type )
+ {
+ put_page_type(buf->page);
+@@ -2461,11 +2477,6 @@ static void gnttab_copy_release_buf(stru
+ put_page(buf->page);
+ buf->page = NULL;
+ }
+- if ( buf->have_grant )
+- {
+- __release_grant_for_copy(buf->domain, buf->ptr.u.ref, buf->read_only);
+- buf->have_grant = 0;
+- }
+ }
+
+ static int gnttab_copy_claim_buf(const struct gnttab_copy *op,