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 } 216