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