22// Copyright (C) 2020 ARM Limited
33
44#include <sys/auxv.h>
5+ #include <sys/types.h>
6+ #include <sys/wait.h>
57#include <signal.h>
68#include <setjmp.h>
79
@@ -28,6 +30,117 @@ do { \
2830 ASSERT_NE (0 , hwcaps & HWCAP_PACG ) TH_LOG ("Generic PAUTH not enabled" ); \
2931} while (0 )
3032
33+ void sign_specific (struct signatures * sign , size_t val )
34+ {
35+ sign -> keyia = keyia_sign (val );
36+ sign -> keyib = keyib_sign (val );
37+ sign -> keyda = keyda_sign (val );
38+ sign -> keydb = keydb_sign (val );
39+ }
40+
41+ void sign_all (struct signatures * sign , size_t val )
42+ {
43+ sign -> keyia = keyia_sign (val );
44+ sign -> keyib = keyib_sign (val );
45+ sign -> keyda = keyda_sign (val );
46+ sign -> keydb = keydb_sign (val );
47+ sign -> keyg = keyg_sign (val );
48+ }
49+
50+ int n_same (struct signatures * old , struct signatures * new , int nkeys )
51+ {
52+ int res = 0 ;
53+
54+ res += old -> keyia == new -> keyia ;
55+ res += old -> keyib == new -> keyib ;
56+ res += old -> keyda == new -> keyda ;
57+ res += old -> keydb == new -> keydb ;
58+ if (nkeys == NKEYS )
59+ res += old -> keyg == new -> keyg ;
60+
61+ return res ;
62+ }
63+
64+ int exec_sign_all (struct signatures * signed_vals , size_t val )
65+ {
66+ int new_stdin [2 ];
67+ int new_stdout [2 ];
68+ int status ;
69+ ssize_t ret ;
70+ pid_t pid ;
71+
72+ ret = pipe (new_stdin );
73+ if (ret == -1 ) {
74+ perror ("pipe returned error" );
75+ return -1 ;
76+ }
77+
78+ ret = pipe (new_stdout );
79+ if (ret == -1 ) {
80+ perror ("pipe returned error" );
81+ return -1 ;
82+ }
83+
84+ pid = fork ();
85+ // child
86+ if (pid == 0 ) {
87+ dup2 (new_stdin [0 ], STDIN_FILENO );
88+ if (ret == -1 ) {
89+ perror ("dup2 returned error" );
90+ exit (1 );
91+ }
92+
93+ dup2 (new_stdout [1 ], STDOUT_FILENO );
94+ if (ret == -1 ) {
95+ perror ("dup2 returned error" );
96+ exit (1 );
97+ }
98+
99+ close (new_stdin [0 ]);
100+ close (new_stdin [1 ]);
101+ close (new_stdout [0 ]);
102+ close (new_stdout [1 ]);
103+
104+ ret = execl ("exec_target" , "exec_target" , (char * )NULL );
105+ if (ret == -1 ) {
106+ perror ("exec returned error" );
107+ exit (1 );
108+ }
109+ }
110+
111+ close (new_stdin [0 ]);
112+ close (new_stdout [1 ]);
113+
114+ ret = write (new_stdin [1 ], & val , sizeof (size_t ));
115+ if (ret == -1 ) {
116+ perror ("write returned error" );
117+ return -1 ;
118+ }
119+
120+ /*
121+ * wait for the worker to finish, so that read() reads all data
122+ * will also context switch with worker so that this function can be used
123+ * for context switch tests
124+ */
125+ waitpid (pid , & status , 0 );
126+ if (WIFEXITED (status ) == 0 ) {
127+ fprintf (stderr , "worker exited unexpectedly\n" );
128+ return -1 ;
129+ }
130+ if (WEXITSTATUS (status ) != 0 ) {
131+ fprintf (stderr , "worker exited with error\n" );
132+ return -1 ;
133+ }
134+
135+ ret = read (new_stdout [0 ], signed_vals , sizeof (struct signatures ));
136+ if (ret == -1 ) {
137+ perror ("read returned error" );
138+ return -1 ;
139+ }
140+
141+ return 0 ;
142+ }
143+
31144sigjmp_buf jmpbuf ;
32145void pac_signal_handler (int signum , siginfo_t * si , void * uc )
33146{
@@ -92,4 +205,41 @@ TEST(pac_instructions_not_nop_generic)
92205 ASSERT_NE (0 , keyg ) TH_LOG ("keyg instructions did nothing" );
93206}
94207
208+ /*
209+ * fork() does not change keys. Only exec() does so call a worker program.
210+ * Its only job is to sign a value and report back the resutls
211+ */
212+ TEST (exec_changed_keys )
213+ {
214+ struct signatures new_keys ;
215+ struct signatures old_keys ;
216+ int ret ;
217+ int same = 10 ;
218+ int nkeys = NKEYS ;
219+ unsigned long hwcaps = getauxval (AT_HWCAP );
220+
221+ /* generic and data key instructions are not in NOP space. This prevents a SIGILL */
222+ ASSERT_NE (0 , hwcaps & HWCAP_PACA ) TH_LOG ("PAUTH not enabled" );
223+ if (!(hwcaps & HWCAP_PACG )) {
224+ TH_LOG ("WARNING: Generic PAUTH not enabled. Skipping generic key checks" );
225+ nkeys = NKEYS - 1 ;
226+ }
227+
228+ for (int i = 0 ; i < PAC_COLLISION_ATTEMPTS ; i ++ ) {
229+ ret = exec_sign_all (& new_keys , i );
230+ ASSERT_EQ (0 , ret ) TH_LOG ("failed to run worker" );
231+
232+ if (nkeys == NKEYS )
233+ sign_all (& old_keys , i );
234+ else
235+ sign_specific (& old_keys , i );
236+
237+ ret = n_same (& old_keys , & new_keys , nkeys );
238+ if (ret < same )
239+ same = ret ;
240+ }
241+
242+ ASSERT_EQ (0 , same ) TH_LOG ("exec() did not change %d keys" , same );
243+ }
244+
95245TEST_HARNESS_MAIN
0 commit comments