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 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 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 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 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 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 */ 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