2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
13 * Copyright 2023 Oxide Computer Company
17 * The purpose of this test is to go through and construct ucontext_t xsave
18 * states that we expect to be invalid and therefore cause setcontext(2) to
19 * fail. We only assume that %ymm state is present here with respect to writing
20 * invalid tests. As if this test runs at all, that will be present.
22 * This is structured a little differently as we expect this program to fail to
23 * execute and that libc will cause us to abort() if we don't correctly return
32 #include <sys/sysmacros.h>
33 #include <sys/debug.h>
34 #include <sys/x86_archext.h>
38 #include "xsave_util.h"
40 static void *xsave_buf
;
41 static volatile const char *curtest
;
46 errx(EXIT_FAILURE
, "TEST FAILED: %s setcontext, took us to success",
51 test_bad_version(ucontext_t
*ctx
)
53 uc_xsave_t
*xc
= (uc_xsave_t
*)ctx
->uc_xsave
;
58 test_bad_length_small(ucontext_t
*ctx
)
60 uc_xsave_t
*xc
= (uc_xsave_t
*)ctx
->uc_xsave
;
65 test_bad_length_large(ucontext_t
*ctx
)
67 uc_xsave_t
*xc
= (uc_xsave_t
*)ctx
->uc_xsave
;
68 xc
->ucx_len
= INT32_MAX
;
72 * As this can run on multiple different systems, we explicitly use bit 8 which
73 * is reserved for a supervisor feature and so should never be valid in this
77 test_bad_vector(ucontext_t
*ctx
)
79 uc_xsave_t
*xc
= (uc_xsave_t
*)ctx
->uc_xsave
;
80 xc
->ucx_bv
|= (1 << 8);
84 test_context_too_short(ucontext_t
*ctx
)
86 uc_xsave_t
*xc
= (uc_xsave_t
*)ctx
->uc_xsave
;
88 bcopy(xc
, xsave_buf
, xc
->ucx_len
);
89 ctx
->uc_xsave
= (long)(uintptr_t)xsave_buf
;
90 xc
= (uc_xsave_t
*)ctx
->uc_xsave
;
91 xc
->ucx_bv
|= XFEATURE_AVX
;
92 xc
->ucx_len
= sizeof (uc_xsave_t
) + 0x10;
96 test_context_badptr0(ucontext_t
*ctx
)
102 test_context_badptr1(ucontext_t
*ctx
)
104 void *addr
= mmap(NULL
, sysconf(_SC_PAGESIZE
), PROT_NONE
,
105 MAP_PRIVATE
| MAP_ANON
, -1, 0);
107 err(EXIT_FAILURE
, "failed to get unmapped page");
110 ctx
->uc_xsave
= (long)(uintptr_t)addr
;
114 test_context_badptr2(ucontext_t
*ctx
)
116 long pgsz
= sysconf(_SC_PAGESIZE
);
117 void *addr
= mmap(NULL
, pgsz
* 2, PROT_NONE
, MAP_PRIVATE
| MAP_ANON
,
120 errx(EXIT_FAILURE
, "failed to get unmapped page");
123 if (mprotect((void *)((uintptr_t)addr
+ pgsz
), pgsz
, PROT_NONE
) != 0) {
124 err(EXIT_FAILURE
, "failed to mprotect second page");
127 ctx
->uc_xsave
= (uintptr_t)addr
;
128 ctx
->uc_xsave
+= pgsz
- sizeof (uint64_t);
134 ucontext_t
*ctx
= ucontext_alloc(0);
136 errx(EXIT_FAILURE
, "failed to get allocate ucontext_t");
139 if (getcontext_extd(ctx
, 0) != 0) {
140 err(EXIT_FAILURE
, "failed to get extended context");
142 xsu_ustack_alloc(ctx
);
143 makecontext(ctx
, bad_success
, 0);
149 void (*bct_func
)(ucontext_t
*);
150 const char *bct_test
;
152 } bad_ucontext_test_t
;
155 * Do not use single quote characters in tests below, that'll break the shell
158 static const bad_ucontext_test_t tests
[] = {
159 { test_bad_version
, "invalid version", EINVAL
},
160 { test_bad_length_small
, "invalid length (small)", EINVAL
},
161 { test_bad_length_large
, "invalid length (large)", EINVAL
},
162 { test_bad_vector
, "invalid xbv", EINVAL
},
163 { test_context_too_short
, "length does not cover AVX", EOVERFLOW
},
164 { test_context_badptr0
, "invalid uc_xsave pointer (NULL)", EINVAL
},
165 { test_context_badptr1
, "invalid uc_xsave pointer (unmapped page)",
167 { test_context_badptr2
, "partially invalid uc_xsave (hit "
168 "unmapped page)", EFAULT
},
172 main(int argc
, char *argv
[])
177 const char *testno
= NULL
;
178 boolean_t do_info
= B_FALSE
, do_run
= B_FALSE
;
181 (void) fprintf(stderr
, "Usage: %s [-c] [-i testno] "
182 "[-r testno]\n", argv
[0]);
185 while ((c
= getopt(argc
, argv
, ":ci:r:")) != -1) {
188 (void) printf("%zu\n", ARRAY_SIZE(tests
));
199 errx(EXIT_FAILURE
, "Option -%c requires an operand\n",
203 errx(EXIT_FAILURE
, "Unknown option: -%c\n", optopt
);
208 if (testno
== NULL
) {
209 errx(EXIT_FAILURE
, "one of -r and -i must be specified");
212 if (do_run
&& do_info
) {
213 errx(EXIT_FAILURE
, "only one of -r and -i may be specified");
217 l
= strtoul(testno
, &eptr
, 0);
218 if (*eptr
!= 0 || errno
!= 0) {
219 errx(EXIT_FAILURE
, "failed to parse test number: %s", argv
[1]);
222 if (l
>= ARRAY_SIZE(tests
)) {
223 errx(EXIT_FAILURE
, "test number %lu is too large\n", l
);
228 * Output info for our wrapper shell script in a way that's not
231 (void) printf("errno=%u\ndesc='%s'\n", tests
[l
].bct_errno
,
237 * This is a little gross, but we know right now that the extended
238 * context is going to be the approximate size that we need for
239 * operations on the system.
241 xsave_buf
= ucontext_alloc(0);
242 if (xsave_buf
== NULL
) {
243 err(EXIT_FAILURE
, "failed to alternative xsave buf");
246 ucontext_t
*ctx
= setup_context();
247 VERIFY3U(ctx
->uc_xsave
, !=, 0);
248 curtest
= tests
[l
].bct_test
;
249 tests
[l
].bct_func(ctx
);
250 (void) setcontext(ctx
);
251 errx(EXIT_FAILURE
, "TEST FAILED: setcontext returned despite us "