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