Message ID | 20230331135709.132713-4-minipli@grsecurity.net (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Tests for CR0.WP=0/1 r/o write access | expand |
On Fri, Mar 31, 2023, Mathias Krause wrote: > Add support to enforce access tests to be handled by the emulator, if > supported by KVM. Exclude it from the ac_test_exec() test, though, to > not slow it down too much. /enthusiastic high five I was going to ask if you could extend the test to utilize FEP, and woke up this morning to see it already done. Thanks!!!!! > Signed-off-by: Mathias Krause <minipli@grsecurity.net> > --- ... > @@ -152,6 +161,7 @@ const char *ac_names[] = { > [AC_CPU_CR0_WP_BIT] = "cr0.wp", > [AC_CPU_CR4_SMEP_BIT] = "cr4.smep", > [AC_CPU_CR4_PKE_BIT] = "cr4.pke", > + [AC_FEP_BIT] = "fep", > }; > > static inline void *va(pt_element_t phys) > @@ -190,6 +200,7 @@ typedef struct { > > static void ac_test_show(ac_test_t *at); > > +static bool fep_available; I don't think fep_available needs to be captured in a global bool, the usage in the CR0_WP test can do if (invalid_mask & AC_FEP_MASK) <skip>
On 31.03.23 18:24, Sean Christopherson wrote: > On Fri, Mar 31, 2023, Mathias Krause wrote: >> Add support to enforce access tests to be handled by the emulator, if >> supported by KVM. Exclude it from the ac_test_exec() test, though, to >> not slow it down too much. > > /enthusiastic high five *clap* > > I was going to ask if you could extend the test to utilize FEP, and woke up this > morning to see it already done. Thanks!!!!! > >> Signed-off-by: Mathias Krause <minipli@grsecurity.net> >> --- > > ... > >> @@ -152,6 +161,7 @@ const char *ac_names[] = { >> [AC_CPU_CR0_WP_BIT] = "cr0.wp", >> [AC_CPU_CR4_SMEP_BIT] = "cr4.smep", >> [AC_CPU_CR4_PKE_BIT] = "cr4.pke", >> + [AC_FEP_BIT] = "fep", >> }; >> >> static inline void *va(pt_element_t phys) >> @@ -190,6 +200,7 @@ typedef struct { >> >> static void ac_test_show(ac_test_t *at); >> >> +static bool fep_available; > > I don't think fep_available needs to be captured in a global bool, the usage in > the CR0_WP test can do > > if (invalid_mask & AC_FEP_MASK) > <skip> Ok, makes it a little uglier, IMHO, but will change. Again, I was just looking at other tests and copied what I thought was sensible. But looking at x86/emulator.c again, I see it's not consistent either. It caches the value in test_mov_pop_ss_code_db() but does not in main(). Maybe I should just use is_fep_available() twice as well, as the additional exception handling shouldn't matter much. Thanks, Mathias
diff --git a/x86/access.c b/x86/access.c index d1ec99b4fa73..ae5e7d8e8892 100644 --- a/x86/access.c +++ b/x86/access.c @@ -82,6 +82,13 @@ enum { AC_CPU_CR4_SMEP_BIT, AC_CPU_CR4_PKE_BIT, + NR_AC_TEST_FLAGS, + + /* + * synthetic flags follow, won't be exercised by ac_test_exec(). + */ + AC_FEP_BIT, + NR_AC_FLAGS }; @@ -121,6 +128,8 @@ enum { #define AC_CPU_CR4_SMEP_MASK (1 << AC_CPU_CR4_SMEP_BIT) #define AC_CPU_CR4_PKE_MASK (1 << AC_CPU_CR4_PKE_BIT) +#define AC_FEP_MASK (1 << AC_FEP_BIT) + const char *ac_names[] = { [AC_PTE_PRESENT_BIT] = "pte.p", [AC_PTE_ACCESSED_BIT] = "pte.a", @@ -152,6 +161,7 @@ const char *ac_names[] = { [AC_CPU_CR0_WP_BIT] = "cr0.wp", [AC_CPU_CR4_SMEP_BIT] = "cr4.smep", [AC_CPU_CR4_PKE_BIT] = "cr4.pke", + [AC_FEP_BIT] = "fep", }; static inline void *va(pt_element_t phys) @@ -190,6 +200,7 @@ typedef struct { static void ac_test_show(ac_test_t *at); +static bool fep_available; static unsigned long shadow_cr0; static unsigned long shadow_cr3; static unsigned long shadow_cr4; @@ -396,7 +407,7 @@ static void ac_test_init(ac_test_t *at, unsigned long virt, ac_pt_env_t *pt_env) static int ac_test_bump_one(ac_test_t *at) { at->flags = ((at->flags | invalid_mask) + 1) & ~invalid_mask; - return at->flags < (1 << NR_AC_FLAGS); + return at->flags < (1 << NR_AC_TEST_FLAGS); } #define F(x) ((flags & x##_MASK) != 0) @@ -799,10 +810,13 @@ static int ac_test_do_access(ac_test_t *at) if (F(AC_ACCESS_TWICE)) { asm volatile ("mov $fixed2, %%rsi \n\t" - "mov (%[addr]), %[reg] \n\t" + "cmp $0, %[fep] \n\t" + "jz 1f \n\t" + KVM_FEP + "1: mov (%[addr]), %[reg] \n\t" "fixed2:" : [reg]"=r"(r), [fault]"=a"(fault), "=b"(e) - : [addr]"r"(at->virt) + : [addr]"r"(at->virt), [fep]"r"(F(AC_FEP)) : "rsi"); fault = 0; } @@ -823,9 +837,15 @@ static int ac_test_do_access(ac_test_t *at) "jnz 2f \n\t" "cmp $0, %[write] \n\t" "jnz 1f \n\t" - "mov (%[addr]), %[reg] \n\t" + "cmp $0, %[fep] \n\t" + "jz 0f \n\t" + KVM_FEP + "0: mov (%[addr]), %[reg] \n\t" "jmp done \n\t" - "1: mov %[reg], (%[addr]) \n\t" + "1: cmp $0, %[fep] \n\t" + "jz 0f \n\t" + KVM_FEP + "0: mov %[reg], (%[addr]) \n\t" "jmp done \n\t" "2: call *%[addr] \n\t" "done: \n" @@ -843,6 +863,7 @@ static int ac_test_do_access(ac_test_t *at) [write]"r"(F(AC_ACCESS_WRITE)), [user]"r"(F(AC_ACCESS_USER)), [fetch]"r"(F(AC_ACCESS_FETCH)), + [fep]"r"(F(AC_FEP)), [user_ds]"i"(USER_DS), [user_cs]"i"(USER_CS), [user_stack_top]"r"(user_stack + sizeof user_stack), @@ -1228,6 +1249,12 @@ int ac_test_run(int pt_levels) invalid_mask |= AC_PTE_BIT36_MASK; } + fep_available = is_fep_available(); + if (!fep_available) { + printf("FEP not available, skipping emulation tests\n"); + invalid_mask |= AC_FEP_MASK; + } + ac_env_int(&pt_env, pt_levels); ac_test_init(&at, 0xffff923400000000ul, &pt_env);
Add support to enforce access tests to be handled by the emulator, if supported by KVM. Exclude it from the ac_test_exec() test, though, to not slow it down too much. Signed-off-by: Mathias Krause <minipli@grsecurity.net> --- x86/access.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-)