Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/powerpc/dexcr: Add DEXCR prctl interface test

Some basic tests of the prctl interface of the DEXCR.

Signed-off-by: Benjamin Gray <bgray@linux.ibm.com>
[mpe: Add missing SPDX tag]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20240417112325.728010-6-bgray@linux.ibm.com

authored by

Benjamin Gray and committed by
Michael Ellerman
5bfa66bf 628d701f

+269 -1
+1
tools/testing/selftests/powerpc/dexcr/.gitignore
··· 1 + dexcr_test 1 2 hashchk_test 2 3 lsdexcr
+3 -1
tools/testing/selftests/powerpc/dexcr/Makefile
··· 1 - TEST_GEN_PROGS := hashchk_test 1 + TEST_GEN_PROGS := dexcr_test hashchk_test 2 2 TEST_GEN_FILES := lsdexcr 3 3 4 4 include ../../lib.mk 5 5 include ../flags.mk 6 + 7 + CFLAGS += $(KHDR_INCLUDES) 6 8 7 9 $(OUTPUT)/hashchk_test: CFLAGS += -fno-pie -no-pie $(call cc-option,-mno-rop-protect) 8 10
+40
tools/testing/selftests/powerpc/dexcr/dexcr.c
··· 3 3 #include <errno.h> 4 4 #include <setjmp.h> 5 5 #include <signal.h> 6 + #include <sys/prctl.h> 6 7 #include <sys/types.h> 7 8 #include <sys/wait.h> 8 9 ··· 42 41 out: 43 42 pop_signal_handler(SIGILL, old); 44 43 return exists; 44 + } 45 + 46 + unsigned int pr_which_to_aspect(unsigned long which) 47 + { 48 + switch (which) { 49 + case PR_PPC_DEXCR_SBHE: 50 + return DEXCR_PR_SBHE; 51 + case PR_PPC_DEXCR_IBRTPD: 52 + return DEXCR_PR_IBRTPD; 53 + case PR_PPC_DEXCR_SRAPD: 54 + return DEXCR_PR_SRAPD; 55 + case PR_PPC_DEXCR_NPHIE: 56 + return DEXCR_PR_NPHIE; 57 + default: 58 + FAIL_IF_EXIT_MSG(true, "unknown PR aspect"); 59 + } 60 + } 61 + 62 + int pr_get_dexcr(unsigned long which) 63 + { 64 + return prctl(PR_PPC_GET_DEXCR, which, 0UL, 0UL, 0UL); 65 + } 66 + 67 + int pr_set_dexcr(unsigned long which, unsigned long ctrl) 68 + { 69 + return prctl(PR_PPC_SET_DEXCR, which, ctrl, 0UL, 0UL); 70 + } 71 + 72 + bool pr_dexcr_aspect_supported(unsigned long which) 73 + { 74 + if (pr_get_dexcr(which) == -1) 75 + return errno == ENODEV; 76 + 77 + return true; 78 + } 79 + 80 + bool pr_dexcr_aspect_editable(unsigned long which) 81 + { 82 + return pr_get_dexcr(which) & PR_PPC_DEXCR_CTRL_EDITABLE; 45 83 } 46 84 47 85 /*
+10
tools/testing/selftests/powerpc/dexcr/dexcr.h
··· 28 28 29 29 bool dexcr_exists(void); 30 30 31 + bool pr_dexcr_aspect_supported(unsigned long which); 32 + 33 + bool pr_dexcr_aspect_editable(unsigned long which); 34 + 35 + int pr_get_dexcr(unsigned long pr_aspect); 36 + 37 + int pr_set_dexcr(unsigned long pr_aspect, unsigned long ctrl); 38 + 39 + unsigned int pr_which_to_aspect(unsigned long which); 40 + 31 41 bool hashchk_triggers(void); 32 42 33 43 enum dexcr_source {
+215
tools/testing/selftests/powerpc/dexcr/dexcr_test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + 3 + #include <errno.h> 4 + #include <fcntl.h> 5 + #include <stdlib.h> 6 + #include <string.h> 7 + #include <sys/prctl.h> 8 + #include <unistd.h> 9 + 10 + #include "dexcr.h" 11 + #include "utils.h" 12 + 13 + /* 14 + * Helper function for testing the behaviour of a newly exec-ed process 15 + */ 16 + static int dexcr_prctl_onexec_test_child(unsigned long which, const char *status) 17 + { 18 + unsigned long dexcr = mfspr(SPRN_DEXCR_RO); 19 + unsigned long aspect = pr_which_to_aspect(which); 20 + int ctrl = pr_get_dexcr(which); 21 + 22 + if (!strcmp(status, "set")) { 23 + FAIL_IF_EXIT_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_SET), 24 + "setting aspect across exec not applied"); 25 + 26 + FAIL_IF_EXIT_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_SET_ONEXEC), 27 + "setting aspect across exec not inherited"); 28 + 29 + FAIL_IF_EXIT_MSG(!(aspect & dexcr), "setting aspect across exec did not take effect"); 30 + } else if (!strcmp(status, "clear")) { 31 + FAIL_IF_EXIT_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR), 32 + "clearing aspect across exec not applied"); 33 + 34 + FAIL_IF_EXIT_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC), 35 + "clearing aspect across exec not inherited"); 36 + 37 + FAIL_IF_EXIT_MSG(aspect & dexcr, "clearing aspect across exec did not take effect"); 38 + } else { 39 + FAIL_IF_EXIT_MSG(true, "unknown expected status"); 40 + } 41 + 42 + return 0; 43 + } 44 + 45 + /* 46 + * Test that the given prctl value can be manipulated freely 47 + */ 48 + static int dexcr_prctl_aspect_test(unsigned long which) 49 + { 50 + unsigned long aspect = pr_which_to_aspect(which); 51 + pid_t pid; 52 + int ctrl; 53 + int err; 54 + int errno_save; 55 + 56 + SKIP_IF_MSG(!dexcr_exists(), "DEXCR not supported"); 57 + SKIP_IF_MSG(!pr_dexcr_aspect_supported(which), "DEXCR aspect not supported"); 58 + SKIP_IF_MSG(!pr_dexcr_aspect_editable(which), "DEXCR aspect not editable with prctl"); 59 + 60 + /* We reject invalid combinations of arguments */ 61 + err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_SET | PR_PPC_DEXCR_CTRL_CLEAR); 62 + errno_save = errno; 63 + FAIL_IF_MSG(err != -1, "simultaneous set and clear should be rejected"); 64 + FAIL_IF_MSG(errno_save != EINVAL, "simultaneous set and clear should be rejected with EINVAL"); 65 + 66 + err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_SET_ONEXEC | PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC); 67 + errno_save = errno; 68 + FAIL_IF_MSG(err != -1, "simultaneous set and clear on exec should be rejected"); 69 + FAIL_IF_MSG(errno_save != EINVAL, "simultaneous set and clear on exec should be rejected with EINVAL"); 70 + 71 + /* We set the aspect */ 72 + err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_SET); 73 + FAIL_IF_MSG(err, "PR_PPC_DEXCR_CTRL_SET failed"); 74 + 75 + ctrl = pr_get_dexcr(which); 76 + FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_SET), "config value not PR_PPC_DEXCR_CTRL_SET"); 77 + FAIL_IF_MSG(ctrl & PR_PPC_DEXCR_CTRL_CLEAR, "config value unexpected clear flag"); 78 + FAIL_IF_MSG(!(aspect & mfspr(SPRN_DEXCR_RO)), "setting aspect did not take effect"); 79 + 80 + /* We clear the aspect */ 81 + err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_CLEAR); 82 + FAIL_IF_MSG(err, "PR_PPC_DEXCR_CTRL_CLEAR failed"); 83 + 84 + ctrl = pr_get_dexcr(which); 85 + FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR), "config value not PR_PPC_DEXCR_CTRL_CLEAR"); 86 + FAIL_IF_MSG(ctrl & PR_PPC_DEXCR_CTRL_SET, "config value unexpected set flag"); 87 + FAIL_IF_MSG(aspect & mfspr(SPRN_DEXCR_RO), "clearing aspect did not take effect"); 88 + 89 + /* We make it set on exec (doesn't change our current value) */ 90 + err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_SET_ONEXEC); 91 + FAIL_IF_MSG(err, "PR_PPC_DEXCR_CTRL_SET_ONEXEC failed"); 92 + 93 + ctrl = pr_get_dexcr(which); 94 + FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR), "process aspect should still be cleared"); 95 + FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_SET_ONEXEC), "config value not PR_PPC_DEXCR_CTRL_SET_ONEXEC"); 96 + FAIL_IF_MSG(ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC, "config value unexpected clear on exec flag"); 97 + FAIL_IF_MSG(aspect & mfspr(SPRN_DEXCR_RO), "scheduling aspect to set on exec should not change it now"); 98 + 99 + /* We make it clear on exec (doesn't change our current value) */ 100 + err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC); 101 + FAIL_IF_MSG(err, "PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC failed"); 102 + 103 + ctrl = pr_get_dexcr(which); 104 + FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR), "process aspect config should still be cleared"); 105 + FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC), "config value not PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC"); 106 + FAIL_IF_MSG(ctrl & PR_PPC_DEXCR_CTRL_SET_ONEXEC, "config value unexpected set on exec flag"); 107 + FAIL_IF_MSG(aspect & mfspr(SPRN_DEXCR_RO), "process aspect should still be cleared"); 108 + 109 + /* We allow setting the current and on-exec value in a single call */ 110 + err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_SET | PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC); 111 + FAIL_IF_MSG(err, "PR_PPC_DEXCR_CTRL_SET | PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC failed"); 112 + 113 + ctrl = pr_get_dexcr(which); 114 + FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_SET), "config value not PR_PPC_DEXCR_CTRL_SET"); 115 + FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC), "config value not PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC"); 116 + FAIL_IF_MSG(!(aspect & mfspr(SPRN_DEXCR_RO)), "process aspect should be set"); 117 + 118 + err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_CLEAR | PR_PPC_DEXCR_CTRL_SET_ONEXEC); 119 + FAIL_IF_MSG(err, "PR_PPC_DEXCR_CTRL_CLEAR | PR_PPC_DEXCR_CTRL_SET_ONEXEC failed"); 120 + 121 + ctrl = pr_get_dexcr(which); 122 + FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR), "config value not PR_PPC_DEXCR_CTRL_CLEAR"); 123 + FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_SET_ONEXEC), "config value not PR_PPC_DEXCR_CTRL_SET_ONEXEC"); 124 + FAIL_IF_MSG(aspect & mfspr(SPRN_DEXCR_RO), "process aspect should be clear"); 125 + 126 + /* Verify the onexec value is applied across exec */ 127 + pid = fork(); 128 + if (!pid) { 129 + char which_str[32] = {}; 130 + char *args[] = { "dexcr_prctl_onexec_test_child", which_str, "set", NULL }; 131 + unsigned int ctrl = pr_get_dexcr(which); 132 + 133 + sprintf(which_str, "%lu", which); 134 + 135 + FAIL_IF_EXIT_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_SET_ONEXEC), 136 + "setting aspect on exec not copied across fork"); 137 + 138 + FAIL_IF_EXIT_MSG(mfspr(SPRN_DEXCR_RO) & aspect, 139 + "setting aspect on exec wrongly applied to fork"); 140 + 141 + execve("/proc/self/exe", args, NULL); 142 + _exit(errno); 143 + } 144 + await_child_success(pid); 145 + 146 + err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_SET | PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC); 147 + FAIL_IF_MSG(err, "PR_PPC_DEXCR_CTRL_SET | PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC failed"); 148 + 149 + pid = fork(); 150 + if (!pid) { 151 + char which_str[32] = {}; 152 + char *args[] = { "dexcr_prctl_onexec_test_child", which_str, "clear", NULL }; 153 + unsigned int ctrl = pr_get_dexcr(which); 154 + 155 + sprintf(which_str, "%lu", which); 156 + 157 + FAIL_IF_EXIT_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC), 158 + "clearing aspect on exec not copied across fork"); 159 + 160 + FAIL_IF_EXIT_MSG(!(mfspr(SPRN_DEXCR_RO) & aspect), 161 + "clearing aspect on exec wrongly applied to fork"); 162 + 163 + execve("/proc/self/exe", args, NULL); 164 + _exit(errno); 165 + } 166 + await_child_success(pid); 167 + 168 + return 0; 169 + } 170 + 171 + static int dexcr_prctl_ibrtpd_test(void) 172 + { 173 + return dexcr_prctl_aspect_test(PR_PPC_DEXCR_IBRTPD); 174 + } 175 + 176 + static int dexcr_prctl_srapd_test(void) 177 + { 178 + return dexcr_prctl_aspect_test(PR_PPC_DEXCR_SRAPD); 179 + } 180 + 181 + static int dexcr_prctl_nphie_test(void) 182 + { 183 + return dexcr_prctl_aspect_test(PR_PPC_DEXCR_NPHIE); 184 + } 185 + 186 + int main(int argc, char *argv[]) 187 + { 188 + int err = 0; 189 + 190 + /* 191 + * Some tests require checking what happens across exec, so we may be 192 + * invoked as the child of a particular test 193 + */ 194 + if (argc > 1) { 195 + if (argc == 3 && !strcmp(argv[0], "dexcr_prctl_onexec_test_child")) { 196 + unsigned long which; 197 + 198 + err = parse_ulong(argv[1], strlen(argv[1]), &which, 10); 199 + FAIL_IF_MSG(err, "failed to parse which value for child"); 200 + 201 + return dexcr_prctl_onexec_test_child(which, argv[2]); 202 + } 203 + 204 + FAIL_IF_MSG(true, "unknown test case"); 205 + } 206 + 207 + /* 208 + * Otherwise we are the main test invocation and run the full suite 209 + */ 210 + err |= test_harness(dexcr_prctl_ibrtpd_test, "dexcr_prctl_ibrtpd"); 211 + err |= test_harness(dexcr_prctl_srapd_test, "dexcr_prctl_srapd"); 212 + err |= test_harness(dexcr_prctl_nphie_test, "dexcr_prctl_nphie"); 213 + 214 + return err; 215 + }