1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* Copyright (C) 2019 ARM Limited */
3*4882a593Smuzhiyun #include "testcases.h"
4*4882a593Smuzhiyun
get_header(struct _aarch64_ctx * head,uint32_t magic,size_t resv_sz,size_t * offset)5*4882a593Smuzhiyun struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
6*4882a593Smuzhiyun size_t resv_sz, size_t *offset)
7*4882a593Smuzhiyun {
8*4882a593Smuzhiyun size_t offs = 0;
9*4882a593Smuzhiyun struct _aarch64_ctx *found = NULL;
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun if (!head || resv_sz < HDR_SZ)
12*4882a593Smuzhiyun return found;
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun while (offs <= resv_sz - HDR_SZ &&
15*4882a593Smuzhiyun head->magic != magic && head->magic) {
16*4882a593Smuzhiyun offs += head->size;
17*4882a593Smuzhiyun head = GET_RESV_NEXT_HEAD(head);
18*4882a593Smuzhiyun }
19*4882a593Smuzhiyun if (head->magic == magic) {
20*4882a593Smuzhiyun found = head;
21*4882a593Smuzhiyun if (offset)
22*4882a593Smuzhiyun *offset = offs;
23*4882a593Smuzhiyun }
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun return found;
26*4882a593Smuzhiyun }
27*4882a593Smuzhiyun
validate_extra_context(struct extra_context * extra,char ** err)28*4882a593Smuzhiyun bool validate_extra_context(struct extra_context *extra, char **err)
29*4882a593Smuzhiyun {
30*4882a593Smuzhiyun struct _aarch64_ctx *term;
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun if (!extra || !err)
33*4882a593Smuzhiyun return false;
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun fprintf(stderr, "Validating EXTRA...\n");
36*4882a593Smuzhiyun term = GET_RESV_NEXT_HEAD(&extra->head);
37*4882a593Smuzhiyun if (!term || term->magic || term->size) {
38*4882a593Smuzhiyun *err = "Missing terminator after EXTRA context";
39*4882a593Smuzhiyun return false;
40*4882a593Smuzhiyun }
41*4882a593Smuzhiyun if (extra->datap & 0x0fUL)
42*4882a593Smuzhiyun *err = "Extra DATAP misaligned";
43*4882a593Smuzhiyun else if (extra->size & 0x0fUL)
44*4882a593Smuzhiyun *err = "Extra SIZE misaligned";
45*4882a593Smuzhiyun else if (extra->datap != (uint64_t)term + sizeof(*term))
46*4882a593Smuzhiyun *err = "Extra DATAP misplaced (not contiguous)";
47*4882a593Smuzhiyun if (*err)
48*4882a593Smuzhiyun return false;
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun return true;
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun
validate_reserved(ucontext_t * uc,size_t resv_sz,char ** err)53*4882a593Smuzhiyun bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun bool terminated = false;
56*4882a593Smuzhiyun size_t offs = 0;
57*4882a593Smuzhiyun int flags = 0;
58*4882a593Smuzhiyun struct extra_context *extra = NULL;
59*4882a593Smuzhiyun struct _aarch64_ctx *head =
60*4882a593Smuzhiyun (struct _aarch64_ctx *)uc->uc_mcontext.__reserved;
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun if (!err)
63*4882a593Smuzhiyun return false;
64*4882a593Smuzhiyun /* Walk till the end terminator verifying __reserved contents */
65*4882a593Smuzhiyun while (head && !terminated && offs < resv_sz) {
66*4882a593Smuzhiyun if ((uint64_t)head & 0x0fUL) {
67*4882a593Smuzhiyun *err = "Misaligned HEAD";
68*4882a593Smuzhiyun return false;
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun switch (head->magic) {
72*4882a593Smuzhiyun case 0:
73*4882a593Smuzhiyun if (head->size)
74*4882a593Smuzhiyun *err = "Bad size for terminator";
75*4882a593Smuzhiyun else
76*4882a593Smuzhiyun terminated = true;
77*4882a593Smuzhiyun break;
78*4882a593Smuzhiyun case FPSIMD_MAGIC:
79*4882a593Smuzhiyun if (flags & FPSIMD_CTX)
80*4882a593Smuzhiyun *err = "Multiple FPSIMD_MAGIC";
81*4882a593Smuzhiyun else if (head->size !=
82*4882a593Smuzhiyun sizeof(struct fpsimd_context))
83*4882a593Smuzhiyun *err = "Bad size for fpsimd_context";
84*4882a593Smuzhiyun flags |= FPSIMD_CTX;
85*4882a593Smuzhiyun break;
86*4882a593Smuzhiyun case ESR_MAGIC:
87*4882a593Smuzhiyun if (head->size != sizeof(struct esr_context))
88*4882a593Smuzhiyun *err = "Bad size for esr_context";
89*4882a593Smuzhiyun break;
90*4882a593Smuzhiyun case SVE_MAGIC:
91*4882a593Smuzhiyun if (flags & SVE_CTX)
92*4882a593Smuzhiyun *err = "Multiple SVE_MAGIC";
93*4882a593Smuzhiyun else if (head->size !=
94*4882a593Smuzhiyun sizeof(struct sve_context))
95*4882a593Smuzhiyun *err = "Bad size for sve_context";
96*4882a593Smuzhiyun flags |= SVE_CTX;
97*4882a593Smuzhiyun break;
98*4882a593Smuzhiyun case EXTRA_MAGIC:
99*4882a593Smuzhiyun if (flags & EXTRA_CTX)
100*4882a593Smuzhiyun *err = "Multiple EXTRA_MAGIC";
101*4882a593Smuzhiyun else if (head->size !=
102*4882a593Smuzhiyun sizeof(struct extra_context))
103*4882a593Smuzhiyun *err = "Bad size for extra_context";
104*4882a593Smuzhiyun flags |= EXTRA_CTX;
105*4882a593Smuzhiyun extra = (struct extra_context *)head;
106*4882a593Smuzhiyun break;
107*4882a593Smuzhiyun case KSFT_BAD_MAGIC:
108*4882a593Smuzhiyun /*
109*4882a593Smuzhiyun * This is a BAD magic header defined
110*4882a593Smuzhiyun * artificially by a testcase and surely
111*4882a593Smuzhiyun * unknown to the Kernel parse_user_sigframe().
112*4882a593Smuzhiyun * It MUST cause a Kernel induced SEGV
113*4882a593Smuzhiyun */
114*4882a593Smuzhiyun *err = "BAD MAGIC !";
115*4882a593Smuzhiyun break;
116*4882a593Smuzhiyun default:
117*4882a593Smuzhiyun /*
118*4882a593Smuzhiyun * A still unknown Magic: potentially freshly added
119*4882a593Smuzhiyun * to the Kernel code and still unknown to the
120*4882a593Smuzhiyun * tests.
121*4882a593Smuzhiyun */
122*4882a593Smuzhiyun fprintf(stdout,
123*4882a593Smuzhiyun "SKIP Unknown MAGIC: 0x%X - Is KSFT arm64/signal up to date ?\n",
124*4882a593Smuzhiyun head->magic);
125*4882a593Smuzhiyun break;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun if (*err)
129*4882a593Smuzhiyun return false;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun offs += head->size;
132*4882a593Smuzhiyun if (resv_sz < offs + sizeof(*head)) {
133*4882a593Smuzhiyun *err = "HEAD Overrun";
134*4882a593Smuzhiyun return false;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun if (flags & EXTRA_CTX)
138*4882a593Smuzhiyun if (!validate_extra_context(extra, err))
139*4882a593Smuzhiyun return false;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun head = GET_RESV_NEXT_HEAD(head);
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun if (terminated && !(flags & FPSIMD_CTX)) {
145*4882a593Smuzhiyun *err = "Missing FPSIMD";
146*4882a593Smuzhiyun return false;
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun return true;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun /*
153*4882a593Smuzhiyun * This function walks through the records inside the provided reserved area
154*4882a593Smuzhiyun * trying to find enough space to fit @need_sz bytes: if not enough space is
155*4882a593Smuzhiyun * available and an extra_context record is present, it throws away the
156*4882a593Smuzhiyun * extra_context record.
157*4882a593Smuzhiyun *
158*4882a593Smuzhiyun * It returns a pointer to a new header where it is possible to start storing
159*4882a593Smuzhiyun * our need_sz bytes.
160*4882a593Smuzhiyun *
161*4882a593Smuzhiyun * @shead: points to the start of reserved area
162*4882a593Smuzhiyun * @need_sz: needed bytes
163*4882a593Smuzhiyun * @resv_sz: reserved area size in bytes
164*4882a593Smuzhiyun * @offset: if not null, this will be filled with the offset of the return
165*4882a593Smuzhiyun * head pointer from @shead
166*4882a593Smuzhiyun *
167*4882a593Smuzhiyun * @return: pointer to a new head where to start storing need_sz bytes, or
168*4882a593Smuzhiyun * NULL if space could not be made available.
169*4882a593Smuzhiyun */
get_starting_head(struct _aarch64_ctx * shead,size_t need_sz,size_t resv_sz,size_t * offset)170*4882a593Smuzhiyun struct _aarch64_ctx *get_starting_head(struct _aarch64_ctx *shead,
171*4882a593Smuzhiyun size_t need_sz, size_t resv_sz,
172*4882a593Smuzhiyun size_t *offset)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun size_t offs = 0;
175*4882a593Smuzhiyun struct _aarch64_ctx *head;
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun head = get_terminator(shead, resv_sz, &offs);
178*4882a593Smuzhiyun /* not found a terminator...no need to update offset if any */
179*4882a593Smuzhiyun if (!head)
180*4882a593Smuzhiyun return head;
181*4882a593Smuzhiyun if (resv_sz - offs < need_sz) {
182*4882a593Smuzhiyun fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
183*4882a593Smuzhiyun resv_sz - offs);
184*4882a593Smuzhiyun head = get_header(shead, EXTRA_MAGIC, resv_sz, &offs);
185*4882a593Smuzhiyun if (!head || resv_sz - offs < need_sz) {
186*4882a593Smuzhiyun fprintf(stderr,
187*4882a593Smuzhiyun "Failed to reclaim space on sigframe.\n");
188*4882a593Smuzhiyun return NULL;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun fprintf(stderr, "Available space:%zd\n", resv_sz - offs);
193*4882a593Smuzhiyun if (offset)
194*4882a593Smuzhiyun *offset = offs;
195*4882a593Smuzhiyun return head;
196*4882a593Smuzhiyun }
197