From: Boqun Feng Date: Tue, 15 Aug 2017 03:18:20 +0000 (+0800) Subject: Functional: Add a UMIP test X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=24635d9265e70b2d75a17f2cfc0c2ca0fad5843b;p=people%2Fandrewcoop%2Fxen-test-framework.git Functional: Add a UMIP test Add a "umip" test for the User-Model Instruction Prevention. The test simply tries to run sgdt/sidt/sldt/str/smsw in guest user-mode with CR4_UMIP = 1. Signed-off-by: Boqun Feng (Intel) Reviewed-by: Andrew Cooper [Whitespace and docs fixups] Signed-off-by: Andrew Cooper --- diff --git a/arch/x86/include/arch/lib.h b/arch/x86/include/arch/lib.h index f608af9..82eb7da 100644 --- a/arch/x86/include/arch/lib.h +++ b/arch/x86/include/arch/lib.h @@ -340,6 +340,19 @@ static inline void write_cr4(unsigned long cr4) asm volatile ("mov %0, %%cr4" :: "r" (cr4)); } +static inline bool write_cr4_safe(unsigned long cr4) +{ + exinfo_t fault = 0; + + asm volatile ("1: mov %1, %%cr4; 2:" + _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_edi) + : "+D" (fault) + : "r" (cr4), + "X" (ex_record_fault_edi)); + + return fault; +} + static inline void write_cr8(unsigned long cr8) { asm volatile ("mov %0, %%cr8" :: "r" (cr8)); diff --git a/docs/all-tests.dox b/docs/all-tests.dox index c1b163a..30a4e2a 100644 --- a/docs/all-tests.dox +++ b/docs/all-tests.dox @@ -33,6 +33,8 @@ and functionality. @subpage test-swint-emulation - Software interrupt emulation for HVM guests. Coveres XSA-106 and XSA-156. +@subpage test-umip - Guest User-Mode Instruction Prevention support. + @section index-xsa XSA Proof-of-Concept tests diff --git a/tests/umip/Makefile b/tests/umip/Makefile new file mode 100644 index 0000000..0248c8b --- /dev/null +++ b/tests/umip/Makefile @@ -0,0 +1,9 @@ +include $(ROOT)/build/common.mk + +NAME := umip +CATEGORY := functional +TEST-ENVS := hvm32 hvm64 + +obj-perenv += main.o + +include $(ROOT)/build/gen.mk diff --git a/tests/umip/main.c b/tests/umip/main.c new file mode 100644 index 0000000..e4afe81 --- /dev/null +++ b/tests/umip/main.c @@ -0,0 +1,211 @@ +/** + * @file tests/umip/main.c + * @ref test-umip + * + * @page test-umip User-Mode Instruction Prevention + * + * User-Mode Instruction Prevention (UMIP) is a feature present in new Intel + * Processors. When active, it causes the `SGDT`, `SIDT`, `SLDT`, `STR` and + * `SMSW` instructions to yield @#GP when executed with CPL > 0. This + * prevents userspace applications from obtaining sensitive operating system + * information. + * + * @see tests/umip/main.c + */ +#include +#include +#include + +const char test_title[] = "User-Mode Instruction Prevention Tests"; +bool test_wants_user_mappings = true; + +static unsigned long stub_sgdt(unsigned long force) +{ + exinfo_t fault = 0; + desc_ptr tmp; + + asm volatile("test %[fep], %[fep];" + "jz 1f;" + _ASM_XEN_FEP + "1: sgdt %[tmp]; 2:" + _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_edi) + : "+D" (fault), [tmp] "=m" (tmp) + : [fep] "q" (force), + "X" (ex_record_fault_edi)); + + return fault; +} +static unsigned long stub_sidt(unsigned long force) +{ + exinfo_t fault = 0; + desc_ptr tmp; + + asm volatile("test %[fep], %[fep];" + "jz 1f;" + _ASM_XEN_FEP + "1: sidt %[tmp]; 2:" + _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_edi) + : "+D" (fault), [tmp] "=m" (tmp) + : [fep] "q" (force), + "X" (ex_record_fault_edi)); + + return fault; +} + +static unsigned long stub_sldt(unsigned long force) +{ + exinfo_t fault = 0; + unsigned int tmp; + + asm volatile("test %[fep], %[fep];" + "jz 1f;" + _ASM_XEN_FEP + "1: sldt %[tmp]; 2:" + _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_edi) + : "+D" (fault), [tmp] "=r" (tmp) + : [fep] "q" (force), + "X" (ex_record_fault_edi)); + + return fault; +} + +static unsigned long stub_str(unsigned long force) +{ + exinfo_t fault = 0; + unsigned int tmp; + + asm volatile("test %[fep], %[fep];" + "jz 1f;" + _ASM_XEN_FEP + "1: str %[tmp]; 2:" + _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_edi) + : "+D" (fault), [tmp] "=r" (tmp) + : [fep] "q" (force), + "X" (ex_record_fault_edi)); + + return fault; +} + +static unsigned long stub_smsw(unsigned long force) +{ + exinfo_t fault = 0; + unsigned int tmp; + + asm volatile("test %[fep], %[fep];" + "jz 1f;" + _ASM_XEN_FEP + "1: smsw %[tmp]; 2:" + _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_edi) + : "+D" (fault), [tmp] "=r" (tmp) + : [fep] "q" (force), + "X" (ex_record_fault_edi)); + + return fault; +} + +static const struct stub { + unsigned long (*fn)(unsigned long); + const char *name; +} stubs[] = { + { stub_sgdt, "SGDT" }, + { stub_sidt, "SIDT" }, + { stub_sldt, "SLDT" }, + { stub_str, "STR" }, + { stub_smsw, "SMSW" }, +}; + +static void test_insns(bool umip_active, bool force) +{ + unsigned int i; + bool user; + + for ( user = false; ; user = true ) + { + exinfo_t exp = user && umip_active ? EXINFO_SYM(GP, 0) : 0; + + for ( i = 0; i < ARRAY_SIZE(stubs); i++) + { + const struct stub *s = &stubs[i]; + exinfo_t ret; + + ret = user ? exec_user_param(s->fn, force) : s->fn(force); + + /* + * Tolerate the instruction emulator not understanding these + * instructions in older releases of Xen. + */ + if ( force && ret == EXINFO_SYM(UD, 0) ) + { + static bool once; + + if ( !once ) + { + xtf_skip("Skip: Emulator doesn't implement %s\n", s->name); + once = true; + } + + continue; + } + + if ( ret != exp ) + xtf_failure("Fail: %s %s\n" + " expected %pe\n" + " got %pe\n", + user ? "user" : "supervisor", s->name, + _p(exp), _p(ret)); + } + + if ( user ) + break; + } +} + +static void test_umip(bool umip_active) +{ + test_insns(umip_active, false); + + if ( xtf_has_fep ) + test_insns(umip_active, true); +} + +void test_main(void) +{ + if ( !xtf_has_fep ) + xtf_skip("FEP support not detected - some tests will be skipped\n"); + + test_umip(false); + + if ( !cpu_has_umip ) + { + xtf_skip("UMIP is not supported, skip the rest of test\n"); + + if ( !write_cr4_safe(read_cr4() | X86_CR4_UMIP) ) + xtf_failure("UMIP unsupported, but setting CR4 bit succeeded\n"); + + return; + } + + /* activate UMIP */ + if ( write_cr4_safe(read_cr4() | X86_CR4_UMIP) ) + return xtf_failure("Fail: Unable to activate UMIP\n"); + + test_umip(true); + + /* deactivate UMIP */ + if ( write_cr4_safe(read_cr4() & ~X86_CR4_UMIP) ) + return xtf_failure("Fail: Unable to deactivate UMIP\n"); + + test_umip(false); + + xtf_success(NULL); +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */