1e74e1d55SBoyan Karatotev // SPDX-License-Identifier: GPL-2.0
2e74e1d55SBoyan Karatotev // Copyright (C) 2020 ARM Limited
3e74e1d55SBoyan Karatotev
4d21435e9SBoyan Karatotev #define _GNU_SOURCE
5d21435e9SBoyan Karatotev
6e74e1d55SBoyan Karatotev #include <sys/auxv.h>
7806a15b2SBoyan Karatotev #include <sys/types.h>
8806a15b2SBoyan Karatotev #include <sys/wait.h>
9e74e1d55SBoyan Karatotev #include <signal.h>
10e74e1d55SBoyan Karatotev #include <setjmp.h>
11d21435e9SBoyan Karatotev #include <sched.h>
12e74e1d55SBoyan Karatotev
13e74e1d55SBoyan Karatotev #include "../../kselftest_harness.h"
14e74e1d55SBoyan Karatotev #include "helper.h"
15e74e1d55SBoyan Karatotev
16766d95b1SBoyan Karatotev #define PAC_COLLISION_ATTEMPTS 10
17766d95b1SBoyan Karatotev /*
18766d95b1SBoyan Karatotev * The kernel sets TBID by default. So bits 55 and above should remain
19766d95b1SBoyan Karatotev * untouched no matter what.
20766d95b1SBoyan Karatotev * The VA space size is 48 bits. Bigger is opt-in.
21766d95b1SBoyan Karatotev */
22766d95b1SBoyan Karatotev #define PAC_MASK (~0xff80ffffffffffff)
23d21435e9SBoyan Karatotev #define ARBITRARY_VALUE (0x1234)
24e74e1d55SBoyan Karatotev #define ASSERT_PAUTH_ENABLED() \
25e74e1d55SBoyan Karatotev do { \
26e74e1d55SBoyan Karatotev unsigned long hwcaps = getauxval(AT_HWCAP); \
27e74e1d55SBoyan Karatotev /* data key instructions are not in NOP space. This prevents a SIGILL */ \
280c69bd2cSMark Brown if (!(hwcaps & HWCAP_PACA)) \
290c69bd2cSMark Brown SKIP(return, "PAUTH not enabled"); \
30e74e1d55SBoyan Karatotev } while (0)
31766d95b1SBoyan Karatotev #define ASSERT_GENERIC_PAUTH_ENABLED() \
32766d95b1SBoyan Karatotev do { \
33766d95b1SBoyan Karatotev unsigned long hwcaps = getauxval(AT_HWCAP); \
34766d95b1SBoyan Karatotev /* generic key instructions are not in NOP space. This prevents a SIGILL */ \
350c69bd2cSMark Brown if (!(hwcaps & HWCAP_PACG)) \
360c69bd2cSMark Brown SKIP(return, "Generic PAUTH not enabled"); \
37766d95b1SBoyan Karatotev } while (0)
38e74e1d55SBoyan Karatotev
sign_specific(struct signatures * sign,size_t val)39806a15b2SBoyan Karatotev void sign_specific(struct signatures *sign, size_t val)
40806a15b2SBoyan Karatotev {
41806a15b2SBoyan Karatotev sign->keyia = keyia_sign(val);
42806a15b2SBoyan Karatotev sign->keyib = keyib_sign(val);
43806a15b2SBoyan Karatotev sign->keyda = keyda_sign(val);
44806a15b2SBoyan Karatotev sign->keydb = keydb_sign(val);
45806a15b2SBoyan Karatotev }
46806a15b2SBoyan Karatotev
sign_all(struct signatures * sign,size_t val)47806a15b2SBoyan Karatotev void sign_all(struct signatures *sign, size_t val)
48806a15b2SBoyan Karatotev {
49806a15b2SBoyan Karatotev sign->keyia = keyia_sign(val);
50806a15b2SBoyan Karatotev sign->keyib = keyib_sign(val);
51806a15b2SBoyan Karatotev sign->keyda = keyda_sign(val);
52806a15b2SBoyan Karatotev sign->keydb = keydb_sign(val);
53806a15b2SBoyan Karatotev sign->keyg = keyg_sign(val);
54806a15b2SBoyan Karatotev }
55806a15b2SBoyan Karatotev
n_same(struct signatures * old,struct signatures * new,int nkeys)56806a15b2SBoyan Karatotev int n_same(struct signatures *old, struct signatures *new, int nkeys)
57806a15b2SBoyan Karatotev {
58806a15b2SBoyan Karatotev int res = 0;
59806a15b2SBoyan Karatotev
60806a15b2SBoyan Karatotev res += old->keyia == new->keyia;
61806a15b2SBoyan Karatotev res += old->keyib == new->keyib;
62806a15b2SBoyan Karatotev res += old->keyda == new->keyda;
63806a15b2SBoyan Karatotev res += old->keydb == new->keydb;
64806a15b2SBoyan Karatotev if (nkeys == NKEYS)
65806a15b2SBoyan Karatotev res += old->keyg == new->keyg;
66806a15b2SBoyan Karatotev
67806a15b2SBoyan Karatotev return res;
68806a15b2SBoyan Karatotev }
69806a15b2SBoyan Karatotev
n_same_single_set(struct signatures * sign,int nkeys)70d21435e9SBoyan Karatotev int n_same_single_set(struct signatures *sign, int nkeys)
71d21435e9SBoyan Karatotev {
72d21435e9SBoyan Karatotev size_t vals[nkeys];
73d21435e9SBoyan Karatotev int same = 0;
74d21435e9SBoyan Karatotev
75d21435e9SBoyan Karatotev vals[0] = sign->keyia & PAC_MASK;
76d21435e9SBoyan Karatotev vals[1] = sign->keyib & PAC_MASK;
77d21435e9SBoyan Karatotev vals[2] = sign->keyda & PAC_MASK;
78d21435e9SBoyan Karatotev vals[3] = sign->keydb & PAC_MASK;
79d21435e9SBoyan Karatotev
80d21435e9SBoyan Karatotev if (nkeys >= 4)
81d21435e9SBoyan Karatotev vals[4] = sign->keyg & PAC_MASK;
82d21435e9SBoyan Karatotev
83d21435e9SBoyan Karatotev for (int i = 0; i < nkeys - 1; i++) {
84d21435e9SBoyan Karatotev for (int j = i + 1; j < nkeys; j++) {
85d21435e9SBoyan Karatotev if (vals[i] == vals[j])
86d21435e9SBoyan Karatotev same += 1;
87d21435e9SBoyan Karatotev }
88d21435e9SBoyan Karatotev }
89d21435e9SBoyan Karatotev return same;
90d21435e9SBoyan Karatotev }
91d21435e9SBoyan Karatotev
exec_sign_all(struct signatures * signed_vals,size_t val)92806a15b2SBoyan Karatotev int exec_sign_all(struct signatures *signed_vals, size_t val)
93806a15b2SBoyan Karatotev {
94806a15b2SBoyan Karatotev int new_stdin[2];
95806a15b2SBoyan Karatotev int new_stdout[2];
96806a15b2SBoyan Karatotev int status;
97d21435e9SBoyan Karatotev int i;
98806a15b2SBoyan Karatotev ssize_t ret;
99806a15b2SBoyan Karatotev pid_t pid;
100d21435e9SBoyan Karatotev cpu_set_t mask;
101806a15b2SBoyan Karatotev
102806a15b2SBoyan Karatotev ret = pipe(new_stdin);
103806a15b2SBoyan Karatotev if (ret == -1) {
104806a15b2SBoyan Karatotev perror("pipe returned error");
105806a15b2SBoyan Karatotev return -1;
106806a15b2SBoyan Karatotev }
107806a15b2SBoyan Karatotev
108806a15b2SBoyan Karatotev ret = pipe(new_stdout);
109806a15b2SBoyan Karatotev if (ret == -1) {
110806a15b2SBoyan Karatotev perror("pipe returned error");
111806a15b2SBoyan Karatotev return -1;
112806a15b2SBoyan Karatotev }
113806a15b2SBoyan Karatotev
114d21435e9SBoyan Karatotev /*
115d21435e9SBoyan Karatotev * pin this process and all its children to a single CPU, so it can also
116d21435e9SBoyan Karatotev * guarantee a context switch with its child
117d21435e9SBoyan Karatotev */
118d21435e9SBoyan Karatotev sched_getaffinity(0, sizeof(mask), &mask);
119d21435e9SBoyan Karatotev
120d21435e9SBoyan Karatotev for (i = 0; i < sizeof(cpu_set_t); i++)
121d21435e9SBoyan Karatotev if (CPU_ISSET(i, &mask))
122d21435e9SBoyan Karatotev break;
123d21435e9SBoyan Karatotev
124d21435e9SBoyan Karatotev CPU_ZERO(&mask);
125d21435e9SBoyan Karatotev CPU_SET(i, &mask);
126d21435e9SBoyan Karatotev sched_setaffinity(0, sizeof(mask), &mask);
127d21435e9SBoyan Karatotev
128806a15b2SBoyan Karatotev pid = fork();
129806a15b2SBoyan Karatotev // child
130806a15b2SBoyan Karatotev if (pid == 0) {
131806a15b2SBoyan Karatotev dup2(new_stdin[0], STDIN_FILENO);
132806a15b2SBoyan Karatotev if (ret == -1) {
133806a15b2SBoyan Karatotev perror("dup2 returned error");
134806a15b2SBoyan Karatotev exit(1);
135806a15b2SBoyan Karatotev }
136806a15b2SBoyan Karatotev
137806a15b2SBoyan Karatotev dup2(new_stdout[1], STDOUT_FILENO);
138806a15b2SBoyan Karatotev if (ret == -1) {
139806a15b2SBoyan Karatotev perror("dup2 returned error");
140806a15b2SBoyan Karatotev exit(1);
141806a15b2SBoyan Karatotev }
142806a15b2SBoyan Karatotev
143806a15b2SBoyan Karatotev close(new_stdin[0]);
144806a15b2SBoyan Karatotev close(new_stdin[1]);
145806a15b2SBoyan Karatotev close(new_stdout[0]);
146806a15b2SBoyan Karatotev close(new_stdout[1]);
147806a15b2SBoyan Karatotev
148806a15b2SBoyan Karatotev ret = execl("exec_target", "exec_target", (char *)NULL);
149806a15b2SBoyan Karatotev if (ret == -1) {
150806a15b2SBoyan Karatotev perror("exec returned error");
151806a15b2SBoyan Karatotev exit(1);
152806a15b2SBoyan Karatotev }
153806a15b2SBoyan Karatotev }
154806a15b2SBoyan Karatotev
155806a15b2SBoyan Karatotev close(new_stdin[0]);
156806a15b2SBoyan Karatotev close(new_stdout[1]);
157806a15b2SBoyan Karatotev
158806a15b2SBoyan Karatotev ret = write(new_stdin[1], &val, sizeof(size_t));
159806a15b2SBoyan Karatotev if (ret == -1) {
160806a15b2SBoyan Karatotev perror("write returned error");
161806a15b2SBoyan Karatotev return -1;
162806a15b2SBoyan Karatotev }
163806a15b2SBoyan Karatotev
164806a15b2SBoyan Karatotev /*
165806a15b2SBoyan Karatotev * wait for the worker to finish, so that read() reads all data
166806a15b2SBoyan Karatotev * will also context switch with worker so that this function can be used
167806a15b2SBoyan Karatotev * for context switch tests
168806a15b2SBoyan Karatotev */
169806a15b2SBoyan Karatotev waitpid(pid, &status, 0);
170806a15b2SBoyan Karatotev if (WIFEXITED(status) == 0) {
171806a15b2SBoyan Karatotev fprintf(stderr, "worker exited unexpectedly\n");
172806a15b2SBoyan Karatotev return -1;
173806a15b2SBoyan Karatotev }
174806a15b2SBoyan Karatotev if (WEXITSTATUS(status) != 0) {
175806a15b2SBoyan Karatotev fprintf(stderr, "worker exited with error\n");
176806a15b2SBoyan Karatotev return -1;
177806a15b2SBoyan Karatotev }
178806a15b2SBoyan Karatotev
179806a15b2SBoyan Karatotev ret = read(new_stdout[0], signed_vals, sizeof(struct signatures));
180806a15b2SBoyan Karatotev if (ret == -1) {
181806a15b2SBoyan Karatotev perror("read returned error");
182806a15b2SBoyan Karatotev return -1;
183806a15b2SBoyan Karatotev }
184806a15b2SBoyan Karatotev
185*e8483ae1SMark Brown close(new_stdin[1]);
186*e8483ae1SMark Brown close(new_stdout[0]);
187*e8483ae1SMark Brown
188806a15b2SBoyan Karatotev return 0;
189806a15b2SBoyan Karatotev }
190806a15b2SBoyan Karatotev
191e74e1d55SBoyan Karatotev sigjmp_buf jmpbuf;
pac_signal_handler(int signum,siginfo_t * si,void * uc)192e74e1d55SBoyan Karatotev void pac_signal_handler(int signum, siginfo_t *si, void *uc)
193e74e1d55SBoyan Karatotev {
194e74e1d55SBoyan Karatotev if (signum == SIGSEGV || signum == SIGILL)
195e74e1d55SBoyan Karatotev siglongjmp(jmpbuf, 1);
196e74e1d55SBoyan Karatotev }
197e74e1d55SBoyan Karatotev
198e74e1d55SBoyan Karatotev /* check that a corrupted PAC results in SIGSEGV or SIGILL */
TEST(corrupt_pac)199e74e1d55SBoyan Karatotev TEST(corrupt_pac)
200e74e1d55SBoyan Karatotev {
201e74e1d55SBoyan Karatotev struct sigaction sa;
202e74e1d55SBoyan Karatotev
203e74e1d55SBoyan Karatotev ASSERT_PAUTH_ENABLED();
204e74e1d55SBoyan Karatotev if (sigsetjmp(jmpbuf, 1) == 0) {
205e74e1d55SBoyan Karatotev sa.sa_sigaction = pac_signal_handler;
206e74e1d55SBoyan Karatotev sa.sa_flags = SA_SIGINFO | SA_RESETHAND;
207e74e1d55SBoyan Karatotev sigemptyset(&sa.sa_mask);
208e74e1d55SBoyan Karatotev
209e74e1d55SBoyan Karatotev sigaction(SIGSEGV, &sa, NULL);
210e74e1d55SBoyan Karatotev sigaction(SIGILL, &sa, NULL);
211e74e1d55SBoyan Karatotev
212e74e1d55SBoyan Karatotev pac_corruptor();
213e74e1d55SBoyan Karatotev ASSERT_TRUE(0) TH_LOG("SIGSEGV/SIGILL signal did not occur");
214e74e1d55SBoyan Karatotev }
215e74e1d55SBoyan Karatotev }
216e74e1d55SBoyan Karatotev
217766d95b1SBoyan Karatotev /*
218766d95b1SBoyan Karatotev * There are no separate pac* and aut* controls so checking only the pac*
219766d95b1SBoyan Karatotev * instructions is sufficient
220766d95b1SBoyan Karatotev */
TEST(pac_instructions_not_nop)221766d95b1SBoyan Karatotev TEST(pac_instructions_not_nop)
222766d95b1SBoyan Karatotev {
223766d95b1SBoyan Karatotev size_t keyia = 0;
224766d95b1SBoyan Karatotev size_t keyib = 0;
225766d95b1SBoyan Karatotev size_t keyda = 0;
226766d95b1SBoyan Karatotev size_t keydb = 0;
227766d95b1SBoyan Karatotev
228766d95b1SBoyan Karatotev ASSERT_PAUTH_ENABLED();
229766d95b1SBoyan Karatotev
230766d95b1SBoyan Karatotev for (int i = 0; i < PAC_COLLISION_ATTEMPTS; i++) {
231766d95b1SBoyan Karatotev keyia |= keyia_sign(i) & PAC_MASK;
232766d95b1SBoyan Karatotev keyib |= keyib_sign(i) & PAC_MASK;
233766d95b1SBoyan Karatotev keyda |= keyda_sign(i) & PAC_MASK;
234766d95b1SBoyan Karatotev keydb |= keydb_sign(i) & PAC_MASK;
235766d95b1SBoyan Karatotev }
236766d95b1SBoyan Karatotev
237766d95b1SBoyan Karatotev ASSERT_NE(0, keyia) TH_LOG("keyia instructions did nothing");
238766d95b1SBoyan Karatotev ASSERT_NE(0, keyib) TH_LOG("keyib instructions did nothing");
239766d95b1SBoyan Karatotev ASSERT_NE(0, keyda) TH_LOG("keyda instructions did nothing");
240766d95b1SBoyan Karatotev ASSERT_NE(0, keydb) TH_LOG("keydb instructions did nothing");
241766d95b1SBoyan Karatotev }
242766d95b1SBoyan Karatotev
TEST(pac_instructions_not_nop_generic)243766d95b1SBoyan Karatotev TEST(pac_instructions_not_nop_generic)
244766d95b1SBoyan Karatotev {
245766d95b1SBoyan Karatotev size_t keyg = 0;
246766d95b1SBoyan Karatotev
247766d95b1SBoyan Karatotev ASSERT_GENERIC_PAUTH_ENABLED();
248766d95b1SBoyan Karatotev
249766d95b1SBoyan Karatotev for (int i = 0; i < PAC_COLLISION_ATTEMPTS; i++)
250766d95b1SBoyan Karatotev keyg |= keyg_sign(i) & PAC_MASK;
251766d95b1SBoyan Karatotev
252766d95b1SBoyan Karatotev ASSERT_NE(0, keyg) TH_LOG("keyg instructions did nothing");
253766d95b1SBoyan Karatotev }
254766d95b1SBoyan Karatotev
TEST(single_thread_different_keys)255d21435e9SBoyan Karatotev TEST(single_thread_different_keys)
256d21435e9SBoyan Karatotev {
257d21435e9SBoyan Karatotev int same = 10;
258d21435e9SBoyan Karatotev int nkeys = NKEYS;
259d21435e9SBoyan Karatotev int tmp;
260d21435e9SBoyan Karatotev struct signatures signed_vals;
261d21435e9SBoyan Karatotev unsigned long hwcaps = getauxval(AT_HWCAP);
262d21435e9SBoyan Karatotev
263d21435e9SBoyan Karatotev /* generic and data key instructions are not in NOP space. This prevents a SIGILL */
2640c69bd2cSMark Brown ASSERT_PAUTH_ENABLED();
265d21435e9SBoyan Karatotev if (!(hwcaps & HWCAP_PACG)) {
266d21435e9SBoyan Karatotev TH_LOG("WARNING: Generic PAUTH not enabled. Skipping generic key checks");
267d21435e9SBoyan Karatotev nkeys = NKEYS - 1;
268d21435e9SBoyan Karatotev }
269d21435e9SBoyan Karatotev
270d21435e9SBoyan Karatotev /*
271d21435e9SBoyan Karatotev * In Linux the PAC field can be up to 7 bits wide. Even if keys are
272d21435e9SBoyan Karatotev * different, there is about 5% chance for PACs to collide with
273d21435e9SBoyan Karatotev * different addresses. This chance rapidly increases with fewer bits
274d21435e9SBoyan Karatotev * allocated for the PAC (e.g. wider address). A comparison of the keys
275d21435e9SBoyan Karatotev * directly will be more reliable.
276d21435e9SBoyan Karatotev * All signed values need to be different at least once out of n
277d21435e9SBoyan Karatotev * attempts to be certain that the keys are different
278d21435e9SBoyan Karatotev */
279d21435e9SBoyan Karatotev for (int i = 0; i < PAC_COLLISION_ATTEMPTS; i++) {
280d21435e9SBoyan Karatotev if (nkeys == NKEYS)
281d21435e9SBoyan Karatotev sign_all(&signed_vals, i);
282d21435e9SBoyan Karatotev else
283d21435e9SBoyan Karatotev sign_specific(&signed_vals, i);
284d21435e9SBoyan Karatotev
285d21435e9SBoyan Karatotev tmp = n_same_single_set(&signed_vals, nkeys);
286d21435e9SBoyan Karatotev if (tmp < same)
287d21435e9SBoyan Karatotev same = tmp;
288d21435e9SBoyan Karatotev }
289d21435e9SBoyan Karatotev
290d21435e9SBoyan Karatotev ASSERT_EQ(0, same) TH_LOG("%d keys clashed every time", same);
291d21435e9SBoyan Karatotev }
292d21435e9SBoyan Karatotev
293806a15b2SBoyan Karatotev /*
294806a15b2SBoyan Karatotev * fork() does not change keys. Only exec() does so call a worker program.
295806a15b2SBoyan Karatotev * Its only job is to sign a value and report back the resutls
296806a15b2SBoyan Karatotev */
TEST(exec_changed_keys)297806a15b2SBoyan Karatotev TEST(exec_changed_keys)
298806a15b2SBoyan Karatotev {
299806a15b2SBoyan Karatotev struct signatures new_keys;
300806a15b2SBoyan Karatotev struct signatures old_keys;
301806a15b2SBoyan Karatotev int ret;
302806a15b2SBoyan Karatotev int same = 10;
303806a15b2SBoyan Karatotev int nkeys = NKEYS;
304806a15b2SBoyan Karatotev unsigned long hwcaps = getauxval(AT_HWCAP);
305806a15b2SBoyan Karatotev
306806a15b2SBoyan Karatotev /* generic and data key instructions are not in NOP space. This prevents a SIGILL */
3070c69bd2cSMark Brown ASSERT_PAUTH_ENABLED();
308806a15b2SBoyan Karatotev if (!(hwcaps & HWCAP_PACG)) {
309806a15b2SBoyan Karatotev TH_LOG("WARNING: Generic PAUTH not enabled. Skipping generic key checks");
310806a15b2SBoyan Karatotev nkeys = NKEYS - 1;
311806a15b2SBoyan Karatotev }
312806a15b2SBoyan Karatotev
313806a15b2SBoyan Karatotev for (int i = 0; i < PAC_COLLISION_ATTEMPTS; i++) {
314806a15b2SBoyan Karatotev ret = exec_sign_all(&new_keys, i);
315806a15b2SBoyan Karatotev ASSERT_EQ(0, ret) TH_LOG("failed to run worker");
316806a15b2SBoyan Karatotev
317806a15b2SBoyan Karatotev if (nkeys == NKEYS)
318806a15b2SBoyan Karatotev sign_all(&old_keys, i);
319806a15b2SBoyan Karatotev else
320806a15b2SBoyan Karatotev sign_specific(&old_keys, i);
321806a15b2SBoyan Karatotev
322806a15b2SBoyan Karatotev ret = n_same(&old_keys, &new_keys, nkeys);
323806a15b2SBoyan Karatotev if (ret < same)
324806a15b2SBoyan Karatotev same = ret;
325806a15b2SBoyan Karatotev }
326806a15b2SBoyan Karatotev
327806a15b2SBoyan Karatotev ASSERT_EQ(0, same) TH_LOG("exec() did not change %d keys", same);
328806a15b2SBoyan Karatotev }
329806a15b2SBoyan Karatotev
TEST(context_switch_keep_keys)330d21435e9SBoyan Karatotev TEST(context_switch_keep_keys)
331d21435e9SBoyan Karatotev {
332d21435e9SBoyan Karatotev int ret;
333d21435e9SBoyan Karatotev struct signatures trash;
334d21435e9SBoyan Karatotev struct signatures before;
335d21435e9SBoyan Karatotev struct signatures after;
336d21435e9SBoyan Karatotev
337d21435e9SBoyan Karatotev ASSERT_PAUTH_ENABLED();
338d21435e9SBoyan Karatotev
339d21435e9SBoyan Karatotev sign_specific(&before, ARBITRARY_VALUE);
340d21435e9SBoyan Karatotev
341d21435e9SBoyan Karatotev /* will context switch with a process with different keys at least once */
342d21435e9SBoyan Karatotev ret = exec_sign_all(&trash, ARBITRARY_VALUE);
343d21435e9SBoyan Karatotev ASSERT_EQ(0, ret) TH_LOG("failed to run worker");
344d21435e9SBoyan Karatotev
345d21435e9SBoyan Karatotev sign_specific(&after, ARBITRARY_VALUE);
346d21435e9SBoyan Karatotev
347d21435e9SBoyan Karatotev ASSERT_EQ(before.keyia, after.keyia) TH_LOG("keyia changed after context switching");
348d21435e9SBoyan Karatotev ASSERT_EQ(before.keyib, after.keyib) TH_LOG("keyib changed after context switching");
349d21435e9SBoyan Karatotev ASSERT_EQ(before.keyda, after.keyda) TH_LOG("keyda changed after context switching");
350d21435e9SBoyan Karatotev ASSERT_EQ(before.keydb, after.keydb) TH_LOG("keydb changed after context switching");
351d21435e9SBoyan Karatotev }
352d21435e9SBoyan Karatotev
TEST(context_switch_keep_keys_generic)353d21435e9SBoyan Karatotev TEST(context_switch_keep_keys_generic)
354d21435e9SBoyan Karatotev {
355d21435e9SBoyan Karatotev int ret;
356d21435e9SBoyan Karatotev struct signatures trash;
357d21435e9SBoyan Karatotev size_t before;
358d21435e9SBoyan Karatotev size_t after;
359d21435e9SBoyan Karatotev
360d21435e9SBoyan Karatotev ASSERT_GENERIC_PAUTH_ENABLED();
361d21435e9SBoyan Karatotev
362d21435e9SBoyan Karatotev before = keyg_sign(ARBITRARY_VALUE);
363d21435e9SBoyan Karatotev
364d21435e9SBoyan Karatotev /* will context switch with a process with different keys at least once */
365d21435e9SBoyan Karatotev ret = exec_sign_all(&trash, ARBITRARY_VALUE);
366d21435e9SBoyan Karatotev ASSERT_EQ(0, ret) TH_LOG("failed to run worker");
367d21435e9SBoyan Karatotev
368d21435e9SBoyan Karatotev after = keyg_sign(ARBITRARY_VALUE);
369d21435e9SBoyan Karatotev
370d21435e9SBoyan Karatotev ASSERT_EQ(before, after) TH_LOG("keyg changed after context switching");
371d21435e9SBoyan Karatotev }
372d21435e9SBoyan Karatotev
373e74e1d55SBoyan Karatotev TEST_HARNESS_MAIN
374