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 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 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 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 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 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 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 FPMR_MAGIC: 213 if (flags & FPMR_CTX) 214 *err = "Multiple FPMR_MAGIC"; 215 else if (head->size != 216 sizeof(struct fpmr_context)) 217 *err = "Bad size for fpmr_context"; 218 new_flags |= FPMR_CTX; 219 break; 220 case EXTRA_MAGIC: 221 if (flags & EXTRA_CTX) 222 *err = "Multiple EXTRA_MAGIC"; 223 else if (head->size != 224 sizeof(struct extra_context)) 225 *err = "Bad size for extra_context"; 226 new_flags |= EXTRA_CTX; 227 extra = (struct extra_context *)head; 228 break; 229 case KSFT_BAD_MAGIC: 230 /* 231 * This is a BAD magic header defined 232 * artificially by a testcase and surely 233 * unknown to the Kernel parse_user_sigframe(). 234 * It MUST cause a Kernel induced SEGV 235 */ 236 *err = "BAD MAGIC !"; 237 break; 238 default: 239 /* 240 * A still unknown Magic: potentially freshly added 241 * to the Kernel code and still unknown to the 242 * tests. Magic numbers are supposed to be allocated 243 * as somewhat meaningful ASCII strings so try to 244 * print as such as well as the raw number. 245 */ 246 memcpy(magic, &head->magic, sizeof(magic)); 247 for (i = 0; i < sizeof(magic); i++) 248 if (!isalnum(magic[i])) 249 magic[i] = '?'; 250 251 fprintf(stdout, 252 "SKIP Unknown MAGIC: 0x%X (%c%c%c%c) - Is KSFT arm64/signal up to date ?\n", 253 head->magic, 254 magic[3], magic[2], magic[1], magic[0]); 255 break; 256 } 257 258 if (*err) 259 return false; 260 261 offs += head->size; 262 if (resv_sz < offs + sizeof(*head)) { 263 *err = "HEAD Overrun"; 264 return false; 265 } 266 267 if (new_flags & EXTRA_CTX) 268 if (!validate_extra_context(extra, err, 269 &extra_data, &extra_sz)) 270 return false; 271 if (new_flags & SVE_CTX) 272 if (!validate_sve_context(sve, err)) 273 return false; 274 if (new_flags & ZA_CTX) 275 if (!validate_za_context(za, err)) 276 return false; 277 if (new_flags & ZT_CTX) 278 if (!validate_zt_context(zt, err)) 279 return false; 280 281 flags |= new_flags; 282 283 head = GET_RESV_NEXT_HEAD(head); 284 } 285 286 if (terminated && !(flags & FPSIMD_CTX)) { 287 *err = "Missing FPSIMD"; 288 return false; 289 } 290 291 if (terminated && (flags & ZT_CTX) && !(flags & ZA_CTX)) { 292 *err = "ZT context but no ZA context"; 293 return false; 294 } 295 296 return true; 297 } 298 299 /* 300 * This function walks through the records inside the provided reserved area 301 * trying to find enough space to fit @need_sz bytes: if not enough space is 302 * available and an extra_context record is present, it throws away the 303 * extra_context record. 304 * 305 * It returns a pointer to a new header where it is possible to start storing 306 * our need_sz bytes. 307 * 308 * @shead: points to the start of reserved area 309 * @need_sz: needed bytes 310 * @resv_sz: reserved area size in bytes 311 * @offset: if not null, this will be filled with the offset of the return 312 * head pointer from @shead 313 * 314 * @return: pointer to a new head where to start storing need_sz bytes, or 315 * NULL if space could not be made available. 316 */ 317 struct _aarch64_ctx *get_starting_head(struct _aarch64_ctx *shead, 318 size_t need_sz, size_t resv_sz, 319 size_t *offset) 320 { 321 size_t offs = 0; 322 struct _aarch64_ctx *head; 323 324 head = get_terminator(shead, resv_sz, &offs); 325 /* not found a terminator...no need to update offset if any */ 326 if (!head) 327 return head; 328 if (resv_sz - offs < need_sz) { 329 fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n", 330 resv_sz - offs); 331 head = get_header(shead, EXTRA_MAGIC, resv_sz, &offs); 332 if (!head || resv_sz - offs < need_sz) { 333 fprintf(stderr, 334 "Failed to reclaim space on sigframe.\n"); 335 return NULL; 336 } 337 } 338 339 fprintf(stderr, "Available space:%zd\n", resv_sz - offs); 340 if (offset) 341 *offset = offs; 342 return head; 343 } 344