1 // SPDX-License-Identifier: GPL-2.0
3 * iopl.c - Test case for a Linux on Xen 64-bit bug
4 * Copyright (c) 2015 Andrew Lutomirski
17 #include <sys/types.h>
25 static void sethandler(int sig
, void (*handler
)(int, siginfo_t
*, void *),
29 memset(&sa
, 0, sizeof(sa
));
30 sa
.sa_sigaction
= handler
;
31 sa
.sa_flags
= SA_SIGINFO
| flags
;
32 sigemptyset(&sa
.sa_mask
);
33 if (sigaction(sig
, &sa
, 0))
38 static void clearhandler(int sig
)
41 memset(&sa
, 0, sizeof(sa
));
42 sa
.sa_handler
= SIG_DFL
;
43 sigemptyset(&sa
.sa_mask
);
44 if (sigaction(sig
, &sa
, 0))
48 static jmp_buf jmpbuf
;
50 static void sigsegv(int sig
, siginfo_t
*si
, void *ctx_void
)
52 siglongjmp(jmpbuf
, 1);
55 static bool try_outb(unsigned short port
)
57 sethandler(SIGSEGV
, sigsegv
, SA_RESETHAND
);
58 if (sigsetjmp(jmpbuf
, 1) != 0) {
61 asm volatile ("outb %%al, %w[port]"
62 : : [port
] "Nd" (port
), "a" (0));
65 clearhandler(SIGSEGV
);
68 static void expect_ok_outb(unsigned short port
)
70 if (!try_outb(port
)) {
71 printf("[FAIL]\toutb to 0x%02hx failed\n", port
);
75 printf("[OK]\toutb to 0x%02hx worked\n", port
);
78 static void expect_gp_outb(unsigned short port
)
81 printf("[FAIL]\toutb to 0x%02hx worked\n", port
);
85 printf("[OK]\toutb to 0x%02hx failed\n", port
);
88 static bool try_cli(void)
90 sethandler(SIGSEGV
, sigsegv
, SA_RESETHAND
);
91 if (sigsetjmp(jmpbuf
, 1) != 0) {
97 clearhandler(SIGSEGV
);
100 static bool try_sti(void)
102 sethandler(SIGSEGV
, sigsegv
, SA_RESETHAND
);
103 if (sigsetjmp(jmpbuf
, 1) != 0) {
106 asm volatile ("sti");
109 clearhandler(SIGSEGV
);
112 static void expect_gp_sti(void)
115 printf("[FAIL]\tSTI worked\n");
118 printf("[OK]\tSTI faulted\n");
122 static void expect_gp_cli(void)
125 printf("[FAIL]\tCLI worked\n");
128 printf("[OK]\tCLI faulted\n");
138 if (sched_setaffinity(0, sizeof(cpuset
), &cpuset
) != 0)
139 err(1, "sched_setaffinity to CPU 0");
141 /* Probe for iopl support. Note that iopl(0) works even as nonroot. */
146 printf("[OK]\tiopl() nor supported\n");
149 printf("[OK]\tiopl(3) failed (%d) -- try running as root\n",
154 /* Make sure that CLI/STI are blocked even with IOPL level 3 */
157 expect_ok_outb(0x80);
159 /* Establish an I/O bitmap to test the restore */
160 if (ioperm(0x80, 1, 1) != 0)
161 err(1, "ioperm(0x80, 1, 1) failed\n");
163 /* Restore our original state prior to starting the fork test. */
168 * Verify that IOPL emulation is disabled and the I/O bitmap still
171 expect_ok_outb(0x80);
172 expect_gp_outb(0xed);
173 /* Drop the I/O bitmap */
174 if (ioperm(0x80, 1, 0) != 0)
175 err(1, "ioperm(0x80, 1, 0) failed\n");
177 pid_t child
= fork();
182 printf("\tchild: set IOPL to 3\n");
186 printf("[RUN]\tchild: write to 0x80\n");
187 asm volatile ("outb %%al, $0x80" : : "a" (0));
192 if (waitpid(child
, &status
, 0) != child
||
193 !WIFEXITED(status
)) {
194 printf("[FAIL]\tChild died\n");
196 } else if (WEXITSTATUS(status
) != 0) {
197 printf("[FAIL]\tChild failed\n");
200 printf("[OK]\tChild succeeded\n");
204 printf("[RUN]\tparent: write to 0x80 (should fail)\n");
206 expect_gp_outb(0x80);
210 /* Test the capability checks. */
211 printf("\tiopl(3)\n");
215 printf("\tDrop privileges\n");
216 if (setresuid(1, 1, 1) != 0) {
217 printf("[WARN]\tDropping privileges failed\n");
221 printf("[RUN]\tiopl(3) unprivileged but with IOPL==3\n");
223 printf("[FAIL]\tiopl(3) should work if iopl is already 3 even if unprivileged\n");
227 printf("[RUN]\tiopl(0) unprivileged\n");
229 printf("[FAIL]\tiopl(0) should work if iopl is already 3 even if unprivileged\n");
233 printf("[RUN]\tiopl(3) unprivileged\n");
235 printf("[FAIL]\tiopl(3) should fail if when unprivileged if iopl==0\n");
238 printf("[OK]\tFailed as expected\n");
242 return nerrs
? 1 : 0;