From: Andrew Cooper Date: Mon, 6 Mar 2017 11:41:10 +0000 (+0000) Subject: Switch tests over to using .text.user X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=55260c180db50b84690bb13a6946787a7ecd5ccc;p=people%2Fandrewcoop%2Fxen-test-framework.git Switch tests over to using .text.user ... in preference to test_wants_user_mappings. This involves duplicating the stubs which need to be executed in user context, and moving them into .text.user. As a result, the tests become SMEP/SMAP-safe, even in cases were such settings are leaked from Xen. Signed-off-by: Andrew Cooper --- diff --git a/tests/cpuid-faulting/main.c b/tests/cpuid-faulting/main.c index 2726576..78f4652 100644 --- a/tests/cpuid-faulting/main.c +++ b/tests/cpuid-faulting/main.c @@ -27,8 +27,6 @@ const char test_title[] = "Guest CPUID Faulting support"; -bool test_wants_user_mappings = true; - unsigned long stub_cpuid(void) { unsigned int fault = 0, tmp; @@ -42,6 +40,19 @@ unsigned long stub_cpuid(void) return fault; } +unsigned long __user_text stub_user_cpuid(void) +{ + unsigned int fault = 0, tmp; + + asm volatile("1: cpuid; 2:" + _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_edi) + : "=a" (tmp), "+D" (fault) + : "a" (0) + : "ebx", "ecx", "edx"); + + return fault; +} + unsigned long stub_fep_cpuid(void) { unsigned int fault = 0, tmp; @@ -56,6 +67,20 @@ unsigned long stub_fep_cpuid(void) return fault; } +unsigned long __user_text stub_user_fep_cpuid(void) +{ + unsigned int fault = 0, tmp; + + asm volatile(_ASM_XEN_FEP + "1: cpuid; 2:" + _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_edi) + : "=a" (tmp), "+D" (fault) + : "a" (0) + : "ebx", "ecx", "edx"); + + return fault; +} + static void test_cpuid(bool exp_faulting) { /* @@ -76,13 +101,13 @@ static void test_cpuid(bool exp_faulting) unsigned long exp = exp_faulting ? EXINFO_SYM(GP, 0) : 0; const char *exp_fail_str = exp_faulting ? "didn't fault" : "faulted"; - if ( exec_user(stub_cpuid) != exp ) + if ( exec_user(stub_user_cpuid) != exp ) xtf_failure("Fail: user cpuid %s\n", exp_fail_str); - if ( IS_DEFINED(CONFIG_PV) && exec_user(stub_fep_cpuid) != exp ) + if ( IS_DEFINED(CONFIG_PV) && exec_user(stub_user_fep_cpuid) != exp ) xtf_failure("Fail: user pv cpuid %s\n", exp_fail_str); - if ( xtf_has_fep && exec_user(stub_fep_cpuid) != exp ) + if ( xtf_has_fep && exec_user(stub_user_fep_cpuid) != exp ) xtf_failure("Fail: user emulated cpuid %s\n", exp_fail_str); } diff --git a/tests/pv-iopl/main.c b/tests/pv-iopl/main.c index 74f47b6..a17d1f8 100644 --- a/tests/pv-iopl/main.c +++ b/tests/pv-iopl/main.c @@ -44,8 +44,6 @@ const char test_title[] = "PV IOPL emulation"; -bool test_wants_user_mappings = true; - /** * Execute @p fn at user privilege, folding @p iopl into the iret frame. */ @@ -58,6 +56,13 @@ static void stub_cli(void) _ASM_EXTABLE(1b, 2b)); } +/** Stub CLI instruction with @#GP fixup. */ +static void __user_text stub_user_cli(void) +{ + asm volatile ("1: cli; 2:" + _ASM_EXTABLE(1b, 2b)); +} + /** Stub OUTB instruction with @#GP fixup. */ static void stub_outb(void) { @@ -66,15 +71,24 @@ static void stub_outb(void) :: "a" (0)); } +/** Stub OUTB instruction with @#GP fixup. */ +static void __user_text stub_user_outb(void) +{ + asm volatile ("1: outb %b0, $0x80; 2:" + _ASM_EXTABLE(1b, 2b) + :: "a" (0)); +} + static const struct insn { const char *name; void (*fn)(void); + void (*user_fn)(void); } /** Sequence of instructions to run. */ insn_sequence[] = { - { "cli", stub_cli, }, - { "outb", stub_outb, }, + { "cli", stub_cli, stub_user_cli, }, + { "outb", stub_outb, stub_user_outb, }, }; static struct expectation @@ -168,7 +182,7 @@ static void run_test(const struct test *t) /* Run insn in userspace. */ expect(seq->name, 1, t->should_fault(1, iopl)); - exec_user_with_iopl(seq->fn, iopl); + exec_user_with_iopl(seq->user_fn, iopl); check(); } } @@ -213,7 +227,7 @@ static const struct test hypercall = .should_fault = hypercall_should_fault, }; -static void nop(void){} +static void __user_text nop(void){} static void vmassist_set_iopl(unsigned int iopl) { /* diff --git a/tests/swint-emulation/lowlevel.S b/tests/swint-emulation/lowlevel.S index 7995764..3be82e8 100644 --- a/tests/swint-emulation/lowlevel.S +++ b/tests/swint-emulation/lowlevel.S @@ -5,10 +5,10 @@ /* Macro to generate a single test function. */ /* See lowlevel.h for a description of nomenclature. */ -.macro GEN_SINGLE insn, type +.macro GEN_SINGLE name, insn, type /* Function label. e.g. stub_int3_red(). */ -ENTRY(stub_\insn\()_\type) +ENTRY(stub_\name\()_\type) .ifc \insn, into /* Ensure the overflow flag is set, to trigger 'into'. */ @@ -29,7 +29,7 @@ ENTRY(stub_\insn\()_\type) .endif /* Label where a fault should occur. e.g. label_int3_red_fault. */ -GLOBAL(label_\insn\()_\type\()_fault) +GLOBAL(label_\name\()_\type\()_fault) /* * Possibly insert a redundant prefix. @@ -62,24 +62,24 @@ GLOBAL(label_\insn\()_\type\()_fault) .endif /* Label where a trap should occur. e.g. label_int3_red_trap. */ -GLOBAL(label_\insn\()_\type\()_trap) +GLOBAL(label_\name\()_\type\()_trap) /* Function return. */ ret /* Fixup from fault label to trap label. */ - _ASM_EXTABLE(label_\insn\()_\type\()_fault, - label_\insn\()_\type\()_trap) + _ASM_EXTABLE(label_\name\()_\type\()_fault, + label_\name\()_\type\()_trap) -ENDFUNC(stub_\insn\()_\type) +ENDFUNC(stub_\name\()_\type) .endm /* For a single instruction, generate each test variant. */ .macro GEN_SEQUENCE insn - GEN_SINGLE \insn reg - GEN_SINGLE \insn red - GEN_SINGLE \insn force - GEN_SINGLE \insn forcered + GEN_SINGLE \insn \insn reg + GEN_SINGLE \insn \insn red + GEN_SINGLE \insn \insn force + GEN_SINGLE \insn \insn forcered .endm /* Generate test sequences for each instruction. */ @@ -89,6 +89,25 @@ GEN_SEQUENCE icebp GEN_SEQUENCE int_0x1 GEN_SEQUENCE into +.pushsection .text.user, "ax", @progbits + + /* For a single instruction, generate each user test variant. */ +.macro GEN_SEQUENCE_USER insn + GEN_SINGLE user_\insn \insn reg + GEN_SINGLE user_\insn \insn red + GEN_SINGLE user_\insn \insn force + GEN_SINGLE user_\insn \insn forcered +.endm + + /* Generate user test sequences for each instruction. */ +GEN_SEQUENCE_USER int3 +GEN_SEQUENCE_USER int_0x3 +GEN_SEQUENCE_USER icebp +GEN_SEQUENCE_USER int_0x1 +GEN_SEQUENCE_USER into + +.popsection + /* * Local variables: * tab-width: 8 diff --git a/tests/swint-emulation/lowlevel.h b/tests/swint-emulation/lowlevel.h index 1cbe8cb..126e0b6 100644 --- a/tests/swint-emulation/lowlevel.h +++ b/tests/swint-emulation/lowlevel.h @@ -8,6 +8,8 @@ * - Stub function executing instruction `$X` with prefix `$Y`. * - `label_$X_$Y_{trap, fault}:` * - Labels for where `$X` is expected to trap or fault. + * - `{stub,label}_user_*` + * - Stubs/labels in user mappings. * * Instructions `$X`: * - int3 @@ -79,6 +81,51 @@ extern unsigned long label_into_red_trap[], label_into_red_fault[]; extern unsigned long label_into_force_trap[], label_into_force_fault[]; extern unsigned long label_into_forcered_trap[], label_into_forcered_fault[]; +void stub_user_int3_reg(void); +void stub_user_int3_red(void); +void stub_user_int3_force(void); +void stub_user_int3_forcered(void); +extern unsigned long label_user_int3_reg_trap[], label_user_int3_reg_fault[]; +extern unsigned long label_user_int3_red_trap[], label_user_int3_red_fault[]; +extern unsigned long label_user_int3_force_trap[], label_user_int3_force_fault[]; +extern unsigned long label_user_int3_forcered_trap[], label_user_int3_forcered_fault[]; + +void stub_user_int_0x3_reg(void); +void stub_user_int_0x3_red(void); +void stub_user_int_0x3_force(void); +void stub_user_int_0x3_forcered(void); +extern unsigned long label_user_int_0x3_reg_trap[], label_user_int_0x3_reg_fault[]; +extern unsigned long label_user_int_0x3_red_trap[], label_user_int_0x3_red_fault[]; +extern unsigned long label_user_int_0x3_force_trap[], label_user_int_0x3_force_fault[]; +extern unsigned long label_user_int_0x3_forcered_trap[], label_user_int_0x3_forcered_fault[]; + +void stub_user_icebp_reg(void); +void stub_user_icebp_red(void); +void stub_user_icebp_force(void); +void stub_user_icebp_forcered(void); +extern unsigned long label_user_icebp_reg_trap[], label_user_icebp_reg_fault[]; +extern unsigned long label_user_icebp_red_trap[], label_user_icebp_red_fault[]; +extern unsigned long label_user_icebp_force_trap[], label_user_icebp_force_fault[]; +extern unsigned long label_user_icebp_forcered_trap[], label_user_icebp_forcered_fault[]; + +void stub_user_int_0x1_reg(void); +void stub_user_int_0x1_red(void); +void stub_user_int_0x1_force(void); +void stub_user_int_0x1_forcered(void); +extern unsigned long label_user_int_0x1_reg_trap[], label_user_int_0x1_reg_fault[]; +extern unsigned long label_user_int_0x1_red_trap[], label_user_int_0x1_red_fault[]; +extern unsigned long label_user_int_0x1_force_trap[], label_user_int_0x1_force_fault[]; +extern unsigned long label_user_int_0x1_forcered_trap[], label_user_int_0x1_forcered_fault[]; + +void stub_user_into_reg(void); +void stub_user_into_red(void); +void stub_user_into_force(void); +void stub_user_into_forcered(void); +extern unsigned long label_user_into_reg_trap[], label_user_into_reg_fault[]; +extern unsigned long label_user_into_red_trap[], label_user_into_red_fault[]; +extern unsigned long label_user_into_force_trap[], label_user_into_force_fault[]; +extern unsigned long label_user_into_forcered_trap[], label_user_into_forcered_fault[]; + #endif /* __LOWLEVEL_H__ */ /* diff --git a/tests/swint-emulation/main.c b/tests/swint-emulation/main.c index 0fb8352..011a6c4 100644 --- a/tests/swint-emulation/main.c +++ b/tests/swint-emulation/main.c @@ -53,14 +53,15 @@ const char test_title[] = "Software interrupt emulation"; -bool test_wants_user_mappings = true; - /** Single stub's worth of information. */ struct single { const char *type; void (*fn)(void); void *trap, *fault; + + void (*user_fn)(void); + void *user_trap, *user_fault; }; /** A collection of subs for an instruction. */ @@ -75,16 +76,32 @@ struct sequence int3 = { "int3", { {"regular", stub_int3_reg, - label_int3_reg_trap, label_int3_reg_fault}, + label_int3_reg_trap, label_int3_reg_fault, + + stub_user_int3_reg, + label_user_int3_reg_trap, label_user_int3_reg_fault, + }, {"redundant", stub_int3_red, - label_int3_red_trap, label_int3_red_fault}, + label_int3_red_trap, label_int3_red_fault, + + stub_user_int3_red, + label_user_int3_red_trap, label_user_int3_red_fault, + }, {"forced", stub_int3_force, - label_int3_force_trap, label_int3_force_fault}, + label_int3_force_trap, label_int3_force_fault, + + stub_user_int3_force, + label_user_int3_force_trap, label_user_int3_force_fault, + }, {"forced redundant", stub_int3_forcered, - label_int3_forcered_trap, label_int3_forcered_fault}, + label_int3_forcered_trap, label_int3_forcered_fault, + + stub_user_int3_forcered, + label_user_int3_forcered_trap, label_user_int3_forcered_fault, + }, }, }; @@ -93,16 +110,32 @@ struct sequence int_0x3 = { "int $3", { {"regular", stub_int_0x3_reg, - label_int_0x3_reg_trap, label_int_0x3_reg_fault}, + label_int_0x3_reg_trap, label_int_0x3_reg_fault, + + stub_user_int_0x3_reg, + label_user_int_0x3_reg_trap, label_user_int_0x3_reg_fault, + }, {"redundant", stub_int_0x3_red, - label_int_0x3_red_trap, label_int_0x3_red_fault}, + label_int_0x3_red_trap, label_int_0x3_red_fault, + + stub_user_int_0x3_red, + label_user_int_0x3_red_trap, label_user_int_0x3_red_fault, + }, {"forced", stub_int_0x3_force, - label_int_0x3_force_trap, label_int_0x3_force_fault}, + label_int_0x3_force_trap, label_int_0x3_force_fault, + + stub_user_int_0x3_force, + label_user_int_0x3_force_trap, label_user_int_0x3_force_fault, + }, {"forced redundant", stub_int_0x3_forcered, - label_int_0x3_forcered_trap, label_int_0x3_forcered_fault}, + label_int_0x3_forcered_trap, label_int_0x3_forcered_fault, + + stub_user_int_0x3_forcered, + label_user_int_0x3_forcered_trap, label_user_int_0x3_forcered_fault, + }, }, }; @@ -111,16 +144,32 @@ struct sequence icebp = { "icebp", { {"regular", stub_icebp_reg, - label_icebp_reg_trap, label_icebp_reg_fault}, + label_icebp_reg_trap, label_icebp_reg_fault, + + stub_user_icebp_reg, + label_user_icebp_reg_trap, label_user_icebp_reg_fault, + }, {"redundant", stub_icebp_red, - label_icebp_red_trap, label_icebp_red_fault}, + label_icebp_red_trap, label_icebp_red_fault, + + stub_user_icebp_red, + label_user_icebp_red_trap, label_user_icebp_red_fault, + }, {"forced", stub_icebp_force, - label_icebp_force_trap, label_icebp_force_fault}, + label_icebp_force_trap, label_icebp_force_fault, + + stub_user_icebp_force, + label_user_icebp_force_trap, label_user_icebp_force_fault, + }, {"forced redundant", stub_icebp_forcered, - label_icebp_forcered_trap, label_icebp_forcered_fault}, + label_icebp_forcered_trap, label_icebp_forcered_fault, + + stub_user_icebp_forcered, + label_user_icebp_forcered_trap, label_user_icebp_forcered_fault, + }, }, }; @@ -129,16 +178,32 @@ struct sequence int_0x1 = { "int $1", { {"regular", stub_int_0x1_reg, - label_int_0x1_reg_trap, label_int_0x1_reg_fault}, + label_int_0x1_reg_trap, label_int_0x1_reg_fault, + + stub_user_int_0x1_reg, + label_user_int_0x1_reg_trap, label_user_int_0x1_reg_fault + }, {"redundant", stub_int_0x1_red, - label_int_0x1_red_trap, label_int_0x1_red_fault}, + label_int_0x1_red_trap, label_int_0x1_red_fault, + + stub_user_int_0x1_red, + label_user_int_0x1_red_trap, label_user_int_0x1_red_fault, + }, {"forced", stub_int_0x1_force, - label_int_0x1_force_trap, label_int_0x1_force_fault}, + label_int_0x1_force_trap, label_int_0x1_force_fault, + + stub_user_int_0x1_force, + label_user_int_0x1_force_trap, label_user_int_0x1_force_fault, + }, {"forced redundant", stub_int_0x1_forcered, - label_int_0x1_forcered_trap, label_int_0x1_forcered_fault}, + label_int_0x1_forcered_trap, label_int_0x1_forcered_fault, + + stub_user_int_0x1_forcered, + label_user_int_0x1_forcered_trap, label_user_int_0x1_forcered_fault, + }, }, }; @@ -147,16 +212,32 @@ struct sequence into = { "into", { {"regular", stub_into_reg, - label_into_reg_trap, label_into_reg_fault}, + label_into_reg_trap, label_into_reg_fault, + + stub_user_into_reg, + label_user_into_reg_trap, label_user_into_reg_fault, + }, {"redundant", stub_into_red, - label_into_red_trap, label_into_red_fault}, + label_into_red_trap, label_into_red_fault, + + stub_user_into_red, + label_user_into_red_trap, label_user_into_red_fault, + }, {"forced", stub_into_force, - label_into_force_trap, label_into_force_fault}, + label_into_force_trap, label_into_force_fault, + + stub_user_into_force, + label_user_into_force_trap, label_user_into_force_fault, + }, {"forced redundant", stub_into_forcered, - label_into_forcered_trap, label_into_forcered_fault}, + label_into_forcered_trap, label_into_forcered_fault, + + stub_user_into_forcered, + label_user_into_forcered_trap, label_user_into_forcered_fault, + }, }, }; @@ -234,12 +315,16 @@ void test_seq(struct sequence *seq, unsigned int vector, for ( i = 0; i < ARRAY_SIZE(seq->tests); ++i ) { struct single *s = &seq->tests[i]; + void *addr; + + if ( user ) + addr = fault ? s->user_fault : s->user_trap; + else + addr = fault ? s->fault : s->trap; - expect(s->type, - fault ? s->fault : s->trap, - vector, error); + expect(s->type, addr, vector, error); - user ? exec_user_void(s->fn) : s->fn(); + user ? exec_user_void(s->user_fn) : s->fn(); check(); diff --git a/tests/xsa-170/main.c b/tests/xsa-170/main.c index c8fbf18..bb79336 100644 --- a/tests/xsa-170/main.c +++ b/tests/xsa-170/main.c @@ -27,10 +27,9 @@ const char test_title[] = "XSA-170 PoC"; -bool test_wants_user_mappings = true; bool test_needs_fep = true; -void wild_jump(void) +void __user_text wild_jump(void) { /* * After XSA-170, Xen's instruction emulator was improved to perform a @@ -45,7 +44,7 @@ void wild_jump(void) :: "qI" (0x8000000000000000ULL)); } -void nop_slide(void) +void __user_text nop_slide(void) { /* * AMD hardware can correctly re-enter the guest with a non-canonical diff --git a/tests/xsa-196/main.c b/tests/xsa-196/main.c index 4a0ec12..7d1331e 100644 --- a/tests/xsa-196/main.c +++ b/tests/xsa-196/main.c @@ -31,7 +31,6 @@ const char test_title[] = "XSA-196 PoC"; -bool test_wants_user_mappings = true; bool test_needs_fep = true; void custom_doublefault_handler(void); @@ -42,7 +41,7 @@ asm(".align 16;" "iretq;" ); -unsigned long compat_userspace(void) +static unsigned long __user_text compat_userspace(void) { exinfo_t fault = 0;