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