@@ -575,9 +575,10 @@ fault:
at->expected_error &= ~PFERR_FETCH_MASK;
}
-static void ac_set_expected_status(ac_test_t *at)
+static void __ac_set_expected_status(ac_test_t *at, bool flush)
{
- invlpg(at->virt);
+ if (flush)
+ invlpg(at->virt);
if (at->ptep)
at->expected_pte = *at->ptep;
@@ -599,6 +600,11 @@ static void ac_set_expected_status(ac_test_t *at)
ac_emulate_access(at, at->flags);
}
+static void ac_set_expected_status(ac_test_t *at)
+{
+ __ac_set_expected_status(at, true);
+}
+
static pt_element_t ac_get_pt(ac_test_t *at, int i, pt_element_t *ptep)
{
pt_element_t pte;
@@ -1061,6 +1067,41 @@ err:
return 0;
}
+static int check_write_cr0wp(ac_pt_env_t *pt_env)
+{
+ ac_test_t at1;
+
+ ac_test_init(&at1, 0xffff923042007000ul, pt_env);
+
+ at1.flags = AC_PDE_PRESENT_MASK | AC_PTE_PRESENT_MASK |
+ AC_PDE_ACCESSED_MASK | AC_PTE_ACCESSED_MASK |
+ AC_CPU_CR0_WP_MASK |
+ AC_ACCESS_WRITE_MASK;
+ ac_test_setup_ptes(&at1);
+
+ /*
+ * Write to r/o page with cr0.wp=0, then try again
+ * with cr0.wp=1 and expect a page fault to happen.
+ */
+ if (!ac_test_do_access(&at1)) {
+ printf("%s: CR0.WP=0 r/o write fail\n", __FUNCTION__);
+ goto err;
+ }
+
+ at1.flags &= ~AC_CPU_CR0_WP_MASK;
+ __ac_set_expected_status(&at1, false);
+
+ if (!ac_test_do_access(&at1)) {
+ printf("%s: CR0.WP=1 r/o write deny fail\n", __FUNCTION__);
+ goto err;
+ }
+
+ return 1;
+
+err:
+ return 0;
+}
+
static int check_effective_sp_permissions(ac_pt_env_t *pt_env)
{
unsigned long ptr1 = 0xffff923480000000;
@@ -1150,6 +1191,7 @@ const ac_test_fn ac_test_cases[] =
check_pfec_on_prefetch_pte,
check_large_pte_dirty_for_nowp,
check_smep_andnot_wp,
+ check_write_cr0wp,
check_effective_sp_permissions,
};
We already have tests that verify a write access to an r/o page is successful when CR0.WP=0, but we lack a test that explicitly verifies that the same access will fail after we set CR0.WP=1 without flushing any associated TLB entries either explicitly (INVLPG) or implicitly (write to CR3). Add such a test. Signed-off-by: Mathias Krause <minipli@grsecurity.net> --- x86/access.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-)