1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2019 ARM Limited */
3
4 #include <ctype.h>
5 #include <string.h>
6
7 #include "testcases.h"
8
validate_extra_context(struct extra_context * extra,char ** err,void ** extra_data,size_t * extra_size)9 bool validate_extra_context(struct extra_context *extra, char **err,
10 void **extra_data, size_t *extra_size)
11 {
12 struct _aarch64_ctx *term;
13
14 if (!extra || !err)
15 return false;
16
17 fprintf(stderr, "Validating EXTRA...\n");
18 term = GET_RESV_NEXT_HEAD(&extra->head);
19 if (!term || term->magic || term->size) {
20 *err = "Missing terminator after EXTRA context";
21 return false;
22 }
23 if (extra->datap & 0x0fUL)
24 *err = "Extra DATAP misaligned";
25 else if (extra->size & 0x0fUL)
26 *err = "Extra SIZE misaligned";
27 else if (extra->datap != (uint64_t)term + 0x10UL)
28 *err = "Extra DATAP misplaced (not contiguous)";
29 if (*err)
30 return false;
31
32 *extra_data = (void *)extra->datap;
33 *extra_size = extra->size;
34
35 return true;
36 }
37
validate_sve_context(struct sve_context * sve,char ** err)38 bool validate_sve_context(struct sve_context *sve, char **err)
39 {
40 /* Size will be rounded up to a multiple of 16 bytes */
41 size_t regs_size
42 = ((SVE_SIG_CONTEXT_SIZE(sve_vq_from_vl(sve->vl)) + 15) / 16) * 16;
43
44 if (!sve || !err)
45 return false;
46
47 /* Either a bare sve_context or a sve_context followed by regs data */
48 if ((sve->head.size != sizeof(struct sve_context)) &&
49 (sve->head.size != regs_size)) {
50 *err = "bad size for SVE context";
51 return false;
52 }
53
54 if (!sve_vl_valid(sve->vl)) {
55 *err = "SVE VL invalid";
56
57 return false;
58 }
59
60 return true;
61 }
62
validate_za_context(struct za_context * za,char ** err)63 bool validate_za_context(struct za_context *za, char **err)
64 {
65 /* Size will be rounded up to a multiple of 16 bytes */
66 size_t regs_size
67 = ((ZA_SIG_CONTEXT_SIZE(sve_vq_from_vl(za->vl)) + 15) / 16) * 16;
68
69 if (!za || !err)
70 return false;
71
72 /* Either a bare za_context or a za_context followed by regs data */
73 if ((za->head.size != sizeof(struct za_context)) &&
74 (za->head.size != regs_size)) {
75 *err = "bad size for ZA context";
76 return false;
77 }
78
79 if (!sve_vl_valid(za->vl)) {
80 *err = "SME VL in ZA context invalid";
81
82 return false;
83 }
84
85 return true;
86 }
87
validate_zt_context(struct zt_context * zt,char ** err)88 bool validate_zt_context(struct zt_context *zt, char **err)
89 {
90 if (!zt || !err)
91 return false;
92
93 /* If the context is present there should be at least one register */
94 if (zt->nregs == 0) {
95 *err = "no registers";
96 return false;
97 }
98
99 /* Size should agree with the number of registers */
100 if (zt->head.size != ZT_SIG_CONTEXT_SIZE(zt->nregs)) {
101 *err = "register count does not match size";
102 return false;
103 }
104
105 return true;
106 }
107
validate_reserved(ucontext_t * uc,size_t resv_sz,char ** err)108 bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
109 {
110 bool terminated = false;
111 size_t offs = 0;
112 int flags = 0;
113 int new_flags, i;
114 struct extra_context *extra = NULL;
115 struct sve_context *sve = NULL;
116 struct za_context *za = NULL;
117 struct zt_context *zt = NULL;
118 struct _aarch64_ctx *head =
119 (struct _aarch64_ctx *)uc->uc_mcontext.__reserved;
120 void *extra_data = NULL;
121 size_t extra_sz = 0;
122 char magic[4];
123
124 if (!err)
125 return false;
126 /* Walk till the end terminator verifying __reserved contents */
127 while (head && !terminated && offs < resv_sz) {
128 if ((uint64_t)head & 0x0fUL) {
129 *err = "Misaligned HEAD";
130 return false;
131 }
132
133 new_flags = 0;
134
135 switch (head->magic) {
136 case 0:
137 if (head->size) {
138 *err = "Bad size for terminator";
139 } else if (extra_data) {
140 /* End of main data, walking the extra data */
141 head = extra_data;
142 resv_sz = extra_sz;
143 offs = 0;
144
145 extra_data = NULL;
146 extra_sz = 0;
147 continue;
148 } else {
149 terminated = true;
150 }
151 break;
152 case FPSIMD_MAGIC:
153 if (flags & FPSIMD_CTX)
154 *err = "Multiple FPSIMD_MAGIC";
155 else if (head->size !=
156 sizeof(struct fpsimd_context))
157 *err = "Bad size for fpsimd_context";
158 new_flags |= FPSIMD_CTX;
159 break;
160 case ESR_MAGIC:
161 if (head->size != sizeof(struct esr_context))
162 *err = "Bad size for esr_context";
163 break;
164 case POE_MAGIC:
165 if (head->size != sizeof(struct poe_context))
166 *err = "Bad size for poe_context";
167 break;
168 case TPIDR2_MAGIC:
169 if (head->size != sizeof(struct tpidr2_context))
170 *err = "Bad size for tpidr2_context";
171 break;
172 case SVE_MAGIC:
173 if (flags & SVE_CTX)
174 *err = "Multiple SVE_MAGIC";
175 /* Size is validated in validate_sve_context() */
176 sve = (struct sve_context *)head;
177 new_flags |= SVE_CTX;
178 break;
179 case ZA_MAGIC:
180 if (flags & ZA_CTX)
181 *err = "Multiple ZA_MAGIC";
182 /* Size is validated in validate_za_context() */
183 za = (struct za_context *)head;
184 new_flags |= ZA_CTX;
185 break;
186 case ZT_MAGIC:
187 if (flags & ZT_CTX)
188 *err = "Multiple ZT_MAGIC";
189 /* Size is validated in validate_za_context() */
190 zt = (struct zt_context *)head;
191 new_flags |= ZT_CTX;
192 break;
193 case FPMR_MAGIC:
194 if (flags & FPMR_CTX)
195 *err = "Multiple FPMR_MAGIC";
196 else if (head->size !=
197 sizeof(struct fpmr_context))
198 *err = "Bad size for fpmr_context";
199 new_flags |= FPMR_CTX;
200 break;
201 case EXTRA_MAGIC:
202 if (flags & EXTRA_CTX)
203 *err = "Multiple EXTRA_MAGIC";
204 else if (head->size !=
205 sizeof(struct extra_context))
206 *err = "Bad size for extra_context";
207 new_flags |= EXTRA_CTX;
208 extra = (struct extra_context *)head;
209 break;
210 case KSFT_BAD_MAGIC:
211 /*
212 * This is a BAD magic header defined
213 * artificially by a testcase and surely
214 * unknown to the Kernel parse_user_sigframe().
215 * It MUST cause a Kernel induced SEGV
216 */
217 *err = "BAD MAGIC !";
218 break;
219 default:
220 /*
221 * A still unknown Magic: potentially freshly added
222 * to the Kernel code and still unknown to the
223 * tests. Magic numbers are supposed to be allocated
224 * as somewhat meaningful ASCII strings so try to
225 * print as such as well as the raw number.
226 */
227 memcpy(magic, &head->magic, sizeof(magic));
228 for (i = 0; i < sizeof(magic); i++)
229 if (!isalnum(magic[i]))
230 magic[i] = '?';
231
232 fprintf(stdout,
233 "SKIP Unknown MAGIC: 0x%X (%c%c%c%c) - Is KSFT arm64/signal up to date ?\n",
234 head->magic,
235 magic[3], magic[2], magic[1], magic[0]);
236 break;
237 }
238
239 if (*err)
240 return false;
241
242 offs += head->size;
243 if (resv_sz < offs + sizeof(*head)) {
244 *err = "HEAD Overrun";
245 return false;
246 }
247
248 if (new_flags & EXTRA_CTX)
249 if (!validate_extra_context(extra, err,
250 &extra_data, &extra_sz))
251 return false;
252 if (new_flags & SVE_CTX)
253 if (!validate_sve_context(sve, err))
254 return false;
255 if (new_flags & ZA_CTX)
256 if (!validate_za_context(za, err))
257 return false;
258 if (new_flags & ZT_CTX)
259 if (!validate_zt_context(zt, err))
260 return false;
261
262 flags |= new_flags;
263
264 head = GET_RESV_NEXT_HEAD(head);
265 }
266
267 if (terminated && !(flags & FPSIMD_CTX)) {
268 *err = "Missing FPSIMD";
269 return false;
270 }
271
272 if (terminated && (flags & ZT_CTX) && !(flags & ZA_CTX)) {
273 *err = "ZT context but no ZA context";
274 return false;
275 }
276
277 return true;
278 }
279
280 /*
281 * This function walks through the records inside the provided reserved area
282 * trying to find enough space to fit @need_sz bytes: if not enough space is
283 * available and an extra_context record is present, it throws away the
284 * extra_context record.
285 *
286 * It returns a pointer to a new header where it is possible to start storing
287 * our need_sz bytes.
288 *
289 * @shead: points to the start of reserved area
290 * @need_sz: needed bytes
291 * @resv_sz: reserved area size in bytes
292 * @offset: if not null, this will be filled with the offset of the return
293 * head pointer from @shead
294 *
295 * @return: pointer to a new head where to start storing need_sz bytes, or
296 * NULL if space could not be made available.
297 */
get_starting_head(struct _aarch64_ctx * shead,size_t need_sz,size_t resv_sz,size_t * offset)298 struct _aarch64_ctx *get_starting_head(struct _aarch64_ctx *shead,
299 size_t need_sz, size_t resv_sz,
300 size_t *offset)
301 {
302 size_t offs = 0;
303 struct _aarch64_ctx *head;
304
305 head = get_terminator(shead, resv_sz, &offs);
306 /* not found a terminator...no need to update offset if any */
307 if (!head)
308 return head;
309 if (resv_sz - offs < need_sz) {
310 fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
311 resv_sz - offs);
312 head = get_header(shead, EXTRA_MAGIC, resv_sz, &offs);
313 if (!head || resv_sz - offs < need_sz) {
314 fprintf(stderr,
315 "Failed to reclaim space on sigframe.\n");
316 return NULL;
317 }
318 }
319
320 fprintf(stderr, "Available space:%zd\n", resv_sz - offs);
321 if (offset)
322 *offset = offs;
323 return head;
324 }
325