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 */
dexcr_prctl_onexec_test_child(unsigned long which,const char * status)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 */
dexcr_prctl_aspect_test(unsigned long which)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
dexcr_prctl_ibrtpd_test(void)171 static int dexcr_prctl_ibrtpd_test(void)
172 {
173 return dexcr_prctl_aspect_test(PR_PPC_DEXCR_IBRTPD);
174 }
175
dexcr_prctl_srapd_test(void)176 static int dexcr_prctl_srapd_test(void)
177 {
178 return dexcr_prctl_aspect_test(PR_PPC_DEXCR_SRAPD);
179 }
180
dexcr_prctl_nphie_test(void)181 static int dexcr_prctl_nphie_test(void)
182 {
183 return dexcr_prctl_aspect_test(PR_PPC_DEXCR_NPHIE);
184 }
185
main(int argc,char * argv[])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