Print this page
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/test/os-tests/tests/xsave/xsave_baducontext.c
+++ new/usr/src/test/os-tests/tests/xsave/xsave_baducontext.c
1 1 /*
2 2 * This file and its contents are supplied under the terms of the
3 3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 4 * You may only use this file in accordance with the terms of version
5 5 * 1.0 of the CDDL.
6 6 *
7 7 * A full copy of the text of the CDDL should have accompanied this
8 8 * source. A copy of the CDDL is also available via the Internet at
9 9 * http://www.illumos.org/license/CDDL.
10 10 */
11 11
12 12 /*
13 13 * Copyright 2023 Oxide Computer Company
14 14 */
15 15
16 16 /*
17 17 * The purpose of this test is to go through and construct ucontext_t xsave
18 18 * states that we expect to be invalid and therefore cause setcontext(2) to
19 19 * fail. We only assume that %ymm state is present here with respect to writing
20 20 * invalid tests. As if this test runs at all, that will be present.
21 21 *
22 22 * This is structured a little differently as we expect this program to fail to
23 23 * execute and that libc will cause us to abort() if we don't correctly return
24 24 * from setcontext..
25 25 */
26 26
27 27 #include <ucontext.h>
28 28 #include <err.h>
29 29 #include <stdlib.h>
30 30 #include <strings.h>
31 31 #include <errno.h>
32 32 #include <sys/sysmacros.h>
33 33 #include <sys/debug.h>
34 34 #include <sys/x86_archext.h>
35 35 #include <sys/mman.h>
36 36 #include <unistd.h>
37 37
38 38 #include "xsave_util.h"
39 39
40 40 static void *xsave_buf;
41 41 static const char *curtest;
42 42
43 43 static void
44 44 bad_success(void)
45 45 {
46 46 errx(EXIT_FAILURE, "TEST FAILED: %s setcontext, took us to success",
47 47 curtest);
48 48 }
49 49
50 50 static void
51 51 test_bad_version(ucontext_t *ctx)
52 52 {
53 53 uc_xsave_t *xc = (uc_xsave_t *)ctx->uc_xsave;
54 54 xc->ucx_vers = 23;
55 55 }
56 56
57 57 static void
58 58 test_bad_length_small(ucontext_t *ctx)
59 59 {
60 60 uc_xsave_t *xc = (uc_xsave_t *)ctx->uc_xsave;
61 61 xc->ucx_len = 0;
62 62 }
63 63
64 64 static void
65 65 test_bad_length_large(ucontext_t *ctx)
66 66 {
67 67 uc_xsave_t *xc = (uc_xsave_t *)ctx->uc_xsave;
68 68 xc->ucx_len = INT32_MAX;
69 69 }
70 70
71 71 /*
72 72 * As this can run on multiple different systems, we explicitly use bit 8 which
73 73 * is reserved for a supervisor feature and so should never be valid in this
74 74 * context.
75 75 */
76 76 static void
77 77 test_bad_vector(ucontext_t *ctx)
78 78 {
79 79 uc_xsave_t *xc = (uc_xsave_t *)ctx->uc_xsave;
80 80 xc->ucx_bv |= (1 << 8);
81 81 }
82 82
83 83 static void
84 84 test_context_too_short(ucontext_t *ctx)
85 85 {
86 86 uc_xsave_t *xc = (uc_xsave_t *)ctx->uc_xsave;
87 87
88 88 bcopy(xc, xsave_buf, xc->ucx_len);
89 89 ctx->uc_xsave = (long)(uintptr_t)xsave_buf;
90 90 xc = (uc_xsave_t *)ctx->uc_xsave;
91 91 xc->ucx_bv |= XFEATURE_AVX;
92 92 xc->ucx_len = sizeof (uc_xsave_t) + 0x10;
93 93 }
94 94
95 95 static void
96 96 test_context_badptr0(ucontext_t *ctx)
97 97 {
98 98 ctx->uc_xsave = 0;
99 99 }
100 100
101 101 static void
102 102 test_context_badptr1(ucontext_t *ctx)
103 103 {
104 104 void *addr = mmap(NULL, sysconf(_SC_PAGESIZE), PROT_NONE,
105 105 MAP_PRIVATE | MAP_ANON, -1, 0);
106 106 if (addr == NULL) {
107 107 err(EXIT_FAILURE, "failed to get unmapped page");
108 108 }
109 109
110 110 ctx->uc_xsave = (long)(uintptr_t)addr;
111 111 }
112 112
113 113 static void
114 114 test_context_badptr2(ucontext_t *ctx)
115 115 {
116 116 long pgsz = sysconf(_SC_PAGESIZE);
117 117 void *addr = mmap(NULL, pgsz * 2, PROT_NONE, MAP_PRIVATE | MAP_ANON,
118 118 -1, 0);
119 119 if (addr == NULL) {
120 120 errx(EXIT_FAILURE, "failed to get unmapped page");
121 121 }
122 122
123 123 if (mprotect((void *)((uintptr_t)addr + pgsz), pgsz, PROT_NONE) != 0) {
124 124 err(EXIT_FAILURE, "failed to mprotect second page");
125 125 }
126 126
127 127 ctx->uc_xsave = (uintptr_t)addr;
128 128 ctx->uc_xsave += pgsz - sizeof (uint64_t);
129 129 }
130 130
131 131 static ucontext_t *
132 132 setup_context(void)
133 133 {
134 134 ucontext_t *ctx = ucontext_alloc(0);
135 135 if (ctx == NULL) {
136 136 errx(EXIT_FAILURE, "failed to get allocate ucontext_t");
137 137 }
138 138
139 139 if (getcontext_extd(ctx, 0) != 0) {
140 140 err(EXIT_FAILURE, "failed to get extended context");
141 141 }
142 142 makecontext(ctx, bad_success, 0);
143 143
144 144 return (ctx);
145 145 }
146 146
147 147 typedef struct {
148 148 void (*bct_func)(ucontext_t *);
149 149 const char *bct_test;
150 150 int bct_errno;
151 151 } bad_ucontext_test_t;
152 152
153 153 /*
154 154 * Do not use single quote characters in tests below, that'll break the shell
155 155 * wrapper.
156 156 */
157 157 static const bad_ucontext_test_t tests[] = {
158 158 { test_bad_version, "invalid version", EINVAL },
159 159 { test_bad_length_small, "invalid length (small)", EINVAL },
160 160 { test_bad_length_large, "invalid length (large)", EINVAL },
161 161 { test_bad_vector, "invalid xbv", EINVAL },
162 162 { test_context_too_short, "length does not cover AVX", EOVERFLOW },
163 163 { test_context_badptr0, "invalid uc_xsave pointer (NULL)", EINVAL },
164 164 { test_context_badptr1, "invalid uc_xsave pointer (unmapped page)",
165 165 EFAULT },
166 166 { test_context_badptr2, "partially invalid uc_xsave (hit "
167 167 "unmapped page)", EFAULT },
168 168 };
169 169
170 170 int
171 171 main(int argc, char *argv[])
172 172 {
173 173 int c;
174 174 char *eptr;
175 175 unsigned long l;
176 176 const char *testno = NULL;
177 177 boolean_t do_info = B_FALSE, do_run = B_FALSE;
178 178
179 179 if (argc < 2) {
180 180 (void) fprintf(stderr, "Usage: %s [-c] [-i testno] "
181 181 "[-r testno]\n", argv[0]);
182 182 }
183 183
184 184 while ((c = getopt(argc, argv, ":ci:r:")) != -1) {
185 185 switch (c) {
186 186 case 'c':
187 187 (void) printf("%zu\n", ARRAY_SIZE(tests));
188 188 return (0);
189 189 case 'i':
190 190 testno = optarg;
191 191 do_info = B_TRUE;
192 192 break;
193 193 case 'r':
194 194 testno = optarg;
195 195 do_run = B_TRUE;
196 196 break;
197 197 case ':':
198 198 errx(EXIT_FAILURE, "Option -%c requires an operand\n",
199 199 optopt);
200 200 break;
201 201 case '?':
202 202 errx(EXIT_FAILURE, "Unknown option: -%c\n", optopt);
203 203 break;
204 204 }
205 205 }
206 206
207 207 if (testno == NULL) {
208 208 errx(EXIT_FAILURE, "one of -r and -i must be specified");
209 209 }
210 210
211 211 if (do_run && do_info) {
212 212 errx(EXIT_FAILURE, "only one of -r and -i may be specified");
213 213 }
214 214
215 215 errno = 0;
216 216 l = strtoul(testno, &eptr, 0);
217 217 if (*eptr != 0 || errno != 0) {
218 218 errx(EXIT_FAILURE, "failed to parse test number: %s", argv[1]);
219 219 }
220 220
221 221 if (l >= ARRAY_SIZE(tests)) {
222 222 errx(EXIT_FAILURE, "test number %lu is too large\n", l);
223 223 }
224 224
225 225 if (do_info) {
226 226 /*
227 227 * Output info for our wrapper shell script in a way that's not
228 228 * too bad to eval.
229 229 */
230 230 (void) printf("errno=%u\ndesc='%s'\n", tests[l].bct_errno,
231 231 tests[l].bct_test);
232 232 return (0);
233 233 }
234 234
235 235 /*
236 236 * This is a little gross, but we know right now that the extended
237 237 * context is going to be the approximate size that we need for
238 238 * operations on the system.
239 239 */
240 240 xsave_buf = ucontext_alloc(0);
241 241 if (xsave_buf == NULL) {
242 242 err(EXIT_FAILURE, "failed to alternative xsave buf");
243 243 }
244 244
245 245 ucontext_t *ctx = setup_context();
246 246 VERIFY3U(ctx->uc_xsave, !=, 0);
247 247 tests[l].bct_func(ctx);
248 248 (void) setcontext(ctx);
249 249 errx(EXIT_FAILURE, "TEST FAILED: setcontext returned despite us "
250 250 "expecting a core");
251 251 }
|
↓ open down ↓ |
251 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX