@@ -1107,27 +1107,43 @@ static int check_write_cr0wp(ac_pt_env_t *pt_env)
* We load CR0.WP with the inverse value of what would be used during
* the access test and toggle EFER.NX to flush and rebuild the current
* MMU context based on that value.
+ *
+ * This used to trigger a bug in the emulator we try to test via FEP.
*/
+ for (;;) {
+ const char *fep = (at.flags & AC_FEP_MASK) ? "FEP " : "";
- set_cr0_wp(1);
- set_efer_nx(1);
- set_efer_nx(0);
+ set_cr0_wp(1);
+ set_efer_nx(1);
+ set_efer_nx(0);
- if (!ac_test_do_access(&at)) {
- printf("%s: CR0.WP=0 r/o write fail\n", __FUNCTION__);
- err++;
- }
+ if (!ac_test_do_access(&at)) {
+ printf("%s: %sCR0.WP=0 r/o write fail\n", __FUNCTION__, fep);
+ err++;
+ }
- at.flags |= AC_CPU_CR0_WP_MASK;
- __ac_set_expected_status(&at, false);
+ at.flags |= AC_CPU_CR0_WP_MASK;
+ __ac_set_expected_status(&at, false);
- set_cr0_wp(0);
- set_efer_nx(1);
- set_efer_nx(0);
+ set_cr0_wp(0);
+ set_efer_nx(1);
+ set_efer_nx(0);
- if (!ac_test_do_access(&at)) {
- printf("%s: CR0.WP=1 r/o write deny fail\n", __FUNCTION__);
- err++;
+ if (!ac_test_do_access(&at)) {
+ printf("%s: %sCR0.WP=1 r/o write deny fail\n", __FUNCTION__, fep);
+ err++;
+ }
+
+ if (!fep_available)
+ break;
+
+ if (at.flags & AC_FEP_MASK)
+ break;
+
+ /* Re-test via the emulator */
+ at.flags |= AC_FEP_MASK;
+ at.flags ^= AC_CPU_CR0_WP_MASK;
+ __ac_set_expected_status(&at, false);
}
return err == 0;
Enhance the CR.WP toggling test to do additional tests via the emulator as these used to trigger bugs when CR0.WP is guest owned. Link: https://lore.kernel.org/kvm/ea3a8fbc-2bf8-7442-e498-3e5818384c83@grsecurity.net/ Signed-off-by: Mathias Krause <minipli@grsecurity.net> --- x86/access.c | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-)