After CR0/CR4/EFER changes a stale TLB entry can be observed, because MOV to CR4 only invalidates TLB entries if CR4.SMEP is changed from 0 to 1. The TLB is already flushed in ac_set_expected_status, but if kvm-unit-tests is migrated to another CPU and CR4 is changed after the flush, a stale entry can be used. Reported-by: Yang Weijiang <weijiang.yang@xxxxxxxxx> Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx> --- x86/access.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/x86/access.c b/x86/access.c index 66bd466..e5d5c00 100644 --- a/x86/access.c +++ b/x86/access.c @@ -448,8 +448,6 @@ fault: static void ac_set_expected_status(ac_test_t *at) { - invlpg(at->virt); - if (at->ptep) at->expected_pte = *at->ptep; at->expected_pde = *at->pdep; @@ -561,6 +559,18 @@ static void __ac_setup_specific_pages(ac_test_t *at, ac_pool_t *pool, root = vroot[index]; } ac_set_expected_status(at); + + set_cr0_wp(F(AC_CPU_CR0_WP)); + set_efer_nx(F(AC_CPU_EFER_NX)); + set_cr4_pke(F(AC_CPU_CR4_PKE)); + if (F(AC_CPU_CR4_PKE)) { + /* WD2=AD2=1, WD1=F(AC_PKU_WD), AD1=F(AC_PKU_AD) */ + write_pkru(0x30 | (F(AC_PKU_WD) ? 8 : 0) | + (F(AC_PKU_AD) ? 4 : 0)); + } + + set_cr4_smep(F(AC_CPU_CR4_SMEP)); + invlpg(at->virt); } static void ac_test_setup_pte(ac_test_t *at, ac_pool_t *pool) @@ -644,17 +654,6 @@ static int ac_test_do_access(ac_test_t *at) *((unsigned char *)at->phys) = 0xc3; /* ret */ unsigned r = unique; - set_cr0_wp(F(AC_CPU_CR0_WP)); - set_efer_nx(F(AC_CPU_EFER_NX)); - set_cr4_pke(F(AC_CPU_CR4_PKE)); - if (F(AC_CPU_CR4_PKE)) { - /* WD2=AD2=1, WD1=F(AC_PKU_WD), AD1=F(AC_PKU_AD) */ - write_pkru(0x30 | (F(AC_PKU_WD) ? 8 : 0) | - (F(AC_PKU_AD) ? 4 : 0)); - } - - set_cr4_smep(F(AC_CPU_CR4_SMEP)); - if (F(AC_ACCESS_TWICE)) { asm volatile ( "mov $fixed2, %%rsi \n\t" -- 2.30.1