aboutsummaryrefslogtreecommitdiffstats
path: root/main/xen/xsa226-1.patch
diff options
context:
space:
mode:
Diffstat (limited to 'main/xen/xsa226-1.patch')
-rw-r--r--main/xen/xsa226-1.patch134
1 files changed, 134 insertions, 0 deletions
diff --git a/main/xen/xsa226-1.patch b/main/xen/xsa226-1.patch
new file mode 100644
index 0000000000..7711d3f888
--- /dev/null
+++ b/main/xen/xsa226-1.patch
@@ -0,0 +1,134 @@
+From: Jan Beulich <jbeulich@suse.com>
+Subject: gnttab: don't use possibly unbounded tail calls
+
+There is no guarantee that the compiler would actually translate them
+to branches instead of calls, so only ones with a known recursion limit
+are okay:
+- __release_grant_for_copy() can call itself only once, as
+ __acquire_grant_for_copy() won't permit use of multi-level transitive
+ grants,
+- __acquire_grant_for_copy() is fine to call itself with the last
+ argument false, as that prevents further recursion,
+- __acquire_grant_for_copy() must not call itself to recover from an
+ observed change to the active entry's pin count
+
+This is part of CVE-2017-12135 / XSA-226.
+
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+
+--- a/xen/common/grant_table.c
++++ b/xen/common/grant_table.c
+@@ -2103,8 +2103,10 @@ __release_grant_for_copy(
+
+ if ( td != rd )
+ {
+- /* Recursive calls, but they're tail calls, so it's
+- okay. */
++ /*
++ * Recursive calls, but they're bounded (acquire permits only a single
++ * level of transitivity), so it's okay.
++ */
+ if ( released_write )
+ __release_grant_for_copy(td, trans_gref, 0);
+ else if ( released_read )
+@@ -2255,10 +2257,11 @@ __acquire_grant_for_copy(
+ return rc;
+ }
+
+- /* We dropped the lock, so we have to check that nobody
+- else tried to pin (or, for that matter, unpin) the
+- reference in *this* domain. If they did, just give up
+- and try again. */
++ /*
++ * We dropped the lock, so we have to check that nobody else tried
++ * to pin (or, for that matter, unpin) the reference in *this*
++ * domain. If they did, just give up and tell the caller to retry.
++ */
+ if ( act->pin != old_pin )
+ {
+ __fixup_status_for_copy_pin(act, status);
+@@ -2266,9 +2269,8 @@ __acquire_grant_for_copy(
+ active_entry_release(act);
+ grant_read_unlock(rgt);
+ put_page(*page);
+- return __acquire_grant_for_copy(rd, gref, ldom, readonly,
+- frame, page, page_off, length,
+- allow_transitive);
++ *page = NULL;
++ return ERESTART;
+ }
+
+ /* The actual remote remote grant may or may not be a
+@@ -2574,7 +2576,7 @@ static int gnttab_copy_one(const struct
+ {
+ gnttab_copy_release_buf(src);
+ rc = gnttab_copy_claim_buf(op, &op->source, src, GNTCOPY_source_gref);
+- if ( rc < 0 )
++ if ( rc )
+ goto out;
+ }
+
+@@ -2584,7 +2586,7 @@ static int gnttab_copy_one(const struct
+ {
+ gnttab_copy_release_buf(dest);
+ rc = gnttab_copy_claim_buf(op, &op->dest, dest, GNTCOPY_dest_gref);
+- if ( rc < 0 )
++ if ( rc )
+ goto out;
+ }
+
+@@ -2593,6 +2595,14 @@ static int gnttab_copy_one(const struct
+ return rc;
+ }
+
++/*
++ * gnttab_copy(), other than the various other helpers of
++ * do_grant_table_op(), returns (besides possible error indicators)
++ * "count - i" rather than "i" to ensure that even if no progress
++ * was made at all (perhaps due to gnttab_copy_one() returning a
++ * positive value) a non-zero value is being handed back (zero needs
++ * to be avoided, as that means "success, all done").
++ */
+ static long gnttab_copy(
+ XEN_GUEST_HANDLE_PARAM(gnttab_copy_t) uop, unsigned int count)
+ {
+@@ -2606,7 +2616,7 @@ static long gnttab_copy(
+ {
+ if ( i && hypercall_preempt_check() )
+ {
+- rc = i;
++ rc = count - i;
+ break;
+ }
+
+@@ -2616,13 +2626,20 @@ static long gnttab_copy(
+ break;
+ }
+
+- op.status = gnttab_copy_one(&op, &dest, &src);
+- if ( op.status != GNTST_okay )
++ rc = gnttab_copy_one(&op, &dest, &src);
++ if ( rc > 0 )
++ {
++ rc = count - i;
++ break;
++ }
++ if ( rc != GNTST_okay )
+ {
+ gnttab_copy_release_buf(&src);
+ gnttab_copy_release_buf(&dest);
+ }
+
++ op.status = rc;
++ rc = 0;
+ if ( unlikely(__copy_field_to_guest(uop, &op, status)) )
+ {
+ rc = -EFAULT;
+@@ -3160,6 +3177,7 @@ do_grant_table_op(
+ rc = gnttab_copy(copy, count);
+ if ( rc > 0 )
+ {
++ rc = count - rc;
+ guest_handle_add_offset(copy, rc);
+ uop = guest_handle_cast(copy, void);
+ }