[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH XTF] Functional: Add a UMIP test
On Thu, Jul 20, 2017 at 10:38:59AM +0100, Andrew Cooper wrote: > On 20/07/17 06:29, Boqun Feng (Intel) wrote: > > 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) <boqun.feng@xxxxxxxxx> > > Thankyou very much for providing a test. > > As a general remark, how have you found XTF to use? > Great tool! Especially when you need to run Xen in a simulated environment like simics and want to test something, bringing up even a simple Linux domainU would be a lot of pain. ;-) While XTF just works like a charm and it's easy to write a test case, though according to your comments I'm now very good at it now ;-) [...] > > + > > +unsigned long umip_sgdt(void) > > The prevailing naming would be stub_sgdt(), and it can be static. For > reasons I will explain later, it should take an unsigned long fep parameter. > > > +{ > > + unsigned long fault = 0; > > exinfo_t fault = 0; > > > + unsigned long tmp; > > sgdt writes out two bytes more than an unsigned long, so this will corrupt > the stack. If you follow the sgdt() example in lib.h, turning this to > "desc_ptr tmp" ought to suffice. > > > + > > + asm volatile("1: sgdt %[tmp]; 2:" > > + _ASM_EXTABLE_HANDLER(1b,2b, ex_record_fault_edi) > > + : "+D" (fault), [tmp] "=m" (tmp) > > + :); > > The extra colon isn't necessary. Did you perhaps originally have memory > clobbers here? > You're right, this could be removed. > > + > > + return fault; > > +} > > + > > +unsigned long umip_sldt(void) > > +{ > > + unsigned long fault = 0; > > + unsigned long tmp; > > + > > + asm volatile("1: sldt %[tmp]; 2:" > > + _ASM_EXTABLE_HANDLER(1b,2b, ex_record_fault_edi) > > + : "+D" (fault), [tmp] "=m" (tmp) > > str and sldt are deceptively hard to encode in their memory operand form, as > the operand is r32/m16. I couldn't find a way of doing it which didn't > leave most of tmp uninitialised on the stack, or without gcc/clang trying to > use prefixes to get the behaviour described. I recommend switching to the > register form which is far easier to work with. > Clearly, I haven't learned those instruction well. Will read the SDM carefully and follow your suggestions, thanks! > > + :); > > + > > + return fault; > > +} > > + > > +unsigned long umip_sidt(void) > > +{ > > + unsigned long fault = 0; > > + unsigned long tmp; > > + > > + asm volatile("1: sidt %[tmp]; 2:" > > + _ASM_EXTABLE_HANDLER(1b,2b, ex_record_fault_edi) > > + : "+D" (fault), [tmp] "=m" (tmp) > > + :); > > + > > + return fault; > > +} > > + > > +unsigned long umip_str(void) > > +{ > > + unsigned long fault = 0; > > + unsigned long tmp; > > + > > + asm volatile("1: str %[tmp]; 2:" > > + _ASM_EXTABLE_HANDLER(1b,2b, ex_record_fault_edi) > > + : "+D" (fault), [tmp] "=m" (tmp) > > + :); > > + > > + return fault; > > +} > > + > > +unsigned long umip_smsw(void) > > +{ > > + unsigned long fault = 0; > > + unsigned long tmp; > > + > > + asm volatile("1: smsw %[tmp]; 2:" > > + _ASM_EXTABLE_HANDLER(1b,2b, ex_record_fault_edi) > > + : "+D" (fault), [tmp] "=m" (tmp) > > + :); > > + > > + return fault; > > +} > > + > > +void test_main(void) > > +{ > > + unsigned long exp; > > + unsigned long cr4 = read_cr4(); > > This is all good. However, it is insufficient to properly test the UMIP > behaviour. Please look at the cpuid-faulting to see how I structured > things. > > In particular, you should: > > 1) Test the regular behaviour of the instructions. > 2) Search for UMIP, skipping if it isn't available. > 3) Enable UMIP. Maybe I also need to provide a write_cr4_safe() similar as wrmsr_safe(), in case that cpuid indicates UMIP supported while UMIP CR4 bit is not allowed to set, which means a bug? > 4) Test the instructions again, this time checking for #GP in userspace. > 5) Disable UMIP. > 6) Check again for regular behaviour. > > This way, you also check that turning it off works as well as turning it on. > > In addition, each test needs to check more than just the block of tests > below. > > 1) The tests should run the instructions natively, and forced through the > instruction emulator. See the FPU Exception Emulation test which is along > the same lines. One thing to be aware of though is that in older versions > of Xen, the s??? instructions weren't implemented in the instruction > emulator, so the test should tolerate and skip if it gets #UD back. > Rogar that. > 2) You need to check supervisor behaviour as well as user behaviour, and in > particular, that supervisor instructions still work irrespective of UMIP. > Unfortunately, I don't have a good example to point you at (because none of > them have been cleaned up and committed yet). Therefore, I've tried mocking > something suitable up rather than leaving you in the dark. This is entirely > untested, but should be along the right lines: > Thank you! This is a great example, very helpful. I will follow your guide and send out a v2(probably in next week). Thanks again and Best Regards, Boqun > 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" }, > }; > > void test_umip(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 res; > > res = 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 && res == EXINFO_SYM(UD, 0) ) > { > static bool once; > > if ( !once ) > { > xtf_skip("Skip: Emulator doesn't implement %s\n", > s->name); > once = true; > } > continue; > } > > if ( res != exp ) > { > char expstr[16], gotstr[16]; > > x86_decode_exinfo(expstr, ARRAY_SIZE(expstr), exp); > x86_decode_exinfo(gotstr, ARRAY_SIZE(gotstr), res); > > xtf_failure("Fail: %s %s\n" > " expected %s\n" > " got %s\n", > user ? "user" : "supervisor", s->name, > expstr, gotstr); > } > } > > if ( user ) > break; > } > } > > Thanks, > > ~Andrew _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |