summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSandipan Das <sandipan@linux.ibm.com>2020-07-27 09:30:37 +0530
committerMichael Ellerman <mpe@ellerman.id.au>2020-07-29 21:02:10 +1000
commit03634bbf5d8a6f2d97e6150a1b8ff03675badac3 (patch)
treec00a058714c9903a6780917a30a96b01a9eb1980
parent264d7fccc4711328a19f07e6bd57aee4c68803aa (diff)
selftests/powerpc: Harden test for execute-disabled pkeys
Commit 192b6a7805989 ("powerpc/book3s64/pkeys: Fix pkey_access_permitted() for execute disable pkey") fixed a bug that caused repetitive faults for pkeys with no execute rights alongside some combination of read and write rights. This removes the last two cases of the test, which check the behaviour of pkeys with read, write but no execute rights and all the rights, in favour of checking all the possible combinations of read, write and execute rights to be able to detect bugs like the one mentioned above. Signed-off-by: Sandipan Das <sandipan@linux.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/db467500f8af47727bba6b35796e8974a78b71e5.1595821792.git.sandipan@linux.ibm.com
-rw-r--r--tools/testing/selftests/powerpc/mm/pkey_exec_prot.c84
1 files changed, 41 insertions, 43 deletions
diff --git a/tools/testing/selftests/powerpc/mm/pkey_exec_prot.c b/tools/testing/selftests/powerpc/mm/pkey_exec_prot.c
index 18ebfe6bae1c..9e5c7f3f498a 100644
--- a/tools/testing/selftests/powerpc/mm/pkey_exec_prot.c
+++ b/tools/testing/selftests/powerpc/mm/pkey_exec_prot.c
@@ -237,55 +237,53 @@ static int test(void)
*fault_addr = PPC_INST_NOP;
FAIL_IF(remaining_faults != 0 || fault_code != SEGV_ACCERR);
- /*
- * Jump to the executable region when AMR bits are set i.e.
- * the pkey permits neither read nor write access.
- *
- * This should generate a pkey fault based on IAMR bits which
- * are set to not permit execution. AMR bits should not affect
- * execution.
- *
- * This also checks if the overwrite of the first instruction
- * word from a trap to a no-op succeeded.
- */
- fault_addr = insns;
- fault_type = PKEY_DISABLE_EXECUTE;
- fault_pkey = pkey;
- remaining_faults = 1;
- FAIL_IF(sys_pkey_mprotect(insns, pgsize, PROT_EXEC, pkey) != 0);
- pkey_set_rights(pkey, PKEY_DISABLE_ACCESS);
- printf("execute at %p, pkey permissions are %s\n", fault_addr,
- pkey_rights(rights));
- asm volatile("mtctr %0; bctrl" : : "r"(insns));
- FAIL_IF(remaining_faults != 0 || fault_code != SEGV_PKUERR);
-
- /*
- * Free the current pkey and allocate a new one that is
- * fully permissive.
- */
+ /* Free the current pkey */
sys_pkey_free(pkey);
+
rights = 0;
- pkey = sys_pkey_alloc(0, rights);
+ do {
+ /*
+ * Allocate pkeys with all valid combinations of read,
+ * write and execute restrictions.
+ */
+ pkey = sys_pkey_alloc(0, rights);
+ FAIL_IF(pkey < 0);
+
+ /*
+ * Jump to the executable region. AMR bits may or may not
+ * be set but they should not affect execution.
+ *
+ * This should generate pkey faults based on IAMR bits which
+ * may be set to restrict execution.
+ *
+ * The first iteration also checks if the overwrite of the
+ * first instruction word from a trap to a no-op succeeded.
+ */
+ fault_pkey = pkey;
+ fault_type = -1;
+ remaining_faults = 0;
+ if (rights & PKEY_DISABLE_EXECUTE) {
+ fault_type = PKEY_DISABLE_EXECUTE;
+ remaining_faults = 1;
+ }
- /*
- * Jump to the executable region when AMR bits are not set
- * i.e. the pkey permits read and write access.
- *
- * This should not generate any faults as the IAMR bits are
- * also not set and hence will the pkey will not restrict
- * execution.
- */
- fault_pkey = pkey;
- remaining_faults = 0;
- FAIL_IF(sys_pkey_mprotect(insns, pgsize, PROT_EXEC, pkey) != 0);
- printf("execute at %p, pkey permissions are %s\n", fault_addr,
- pkey_rights(rights));
- asm volatile("mtctr %0; bctrl" : : "r"(insns));
- FAIL_IF(remaining_faults != 0);
+ FAIL_IF(sys_pkey_mprotect(insns, pgsize, PROT_EXEC, pkey) != 0);
+ printf("execute at %p, pkey permissions are %s\n", fault_addr,
+ pkey_rights(rights));
+ asm volatile("mtctr %0; bctrl" : : "r"(insns));
+ FAIL_IF(remaining_faults != 0);
+ if (rights & PKEY_DISABLE_EXECUTE)
+ FAIL_IF(fault_code != SEGV_PKUERR);
+
+ /* Free the current pkey */
+ sys_pkey_free(pkey);
+
+ /* Find next valid combination of pkey rights */
+ rights = next_pkey_rights(rights);
+ } while (rights);
/* Cleanup */
munmap((void *) insns, pgsize);
- sys_pkey_free(pkey);
return 0;
}