Skip to content

Commit e638ad0

Browse files
committed
selftests/x86/iopl: Extend test to cover IOPL emulation
Add tests that the now emulated iopl() functionality: - does not longer allow user space to disable interrupts. - does restore a I/O bitmap when IOPL is dropped Signed-off-by: Thomas Gleixner <[email protected]>
1 parent 111e7b1 commit e638ad0

File tree

1 file changed

+118
-11
lines changed
  • tools/testing/selftests/x86

1 file changed

+118
-11
lines changed

tools/testing/selftests/x86/iopl.c

Lines changed: 118 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,32 +35,145 @@ static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
3535

3636
}
3737

38+
static void clearhandler(int sig)
39+
{
40+
struct sigaction sa;
41+
memset(&sa, 0, sizeof(sa));
42+
sa.sa_handler = SIG_DFL;
43+
sigemptyset(&sa.sa_mask);
44+
if (sigaction(sig, &sa, 0))
45+
err(1, "sigaction");
46+
}
47+
3848
static jmp_buf jmpbuf;
3949

4050
static void sigsegv(int sig, siginfo_t *si, void *ctx_void)
4151
{
4252
siglongjmp(jmpbuf, 1);
4353
}
4454

55+
static bool try_outb(unsigned short port)
56+
{
57+
sethandler(SIGSEGV, sigsegv, SA_RESETHAND);
58+
if (sigsetjmp(jmpbuf, 1) != 0) {
59+
return false;
60+
} else {
61+
asm volatile ("outb %%al, %w[port]"
62+
: : [port] "Nd" (port), "a" (0));
63+
return true;
64+
}
65+
clearhandler(SIGSEGV);
66+
}
67+
68+
static void expect_ok_outb(unsigned short port)
69+
{
70+
if (!try_outb(port)) {
71+
printf("[FAIL]\toutb to 0x%02hx failed\n", port);
72+
exit(1);
73+
}
74+
75+
printf("[OK]\toutb to 0x%02hx worked\n", port);
76+
}
77+
78+
static void expect_gp_outb(unsigned short port)
79+
{
80+
if (try_outb(port)) {
81+
printf("[FAIL]\toutb to 0x%02hx worked\n", port);
82+
nerrs++;
83+
}
84+
85+
printf("[OK]\toutb to 0x%02hx failed\n", port);
86+
}
87+
88+
static bool try_cli(void)
89+
{
90+
sethandler(SIGSEGV, sigsegv, SA_RESETHAND);
91+
if (sigsetjmp(jmpbuf, 1) != 0) {
92+
return false;
93+
} else {
94+
asm volatile ("cli");
95+
return true;
96+
}
97+
clearhandler(SIGSEGV);
98+
}
99+
100+
static bool try_sti(void)
101+
{
102+
sethandler(SIGSEGV, sigsegv, SA_RESETHAND);
103+
if (sigsetjmp(jmpbuf, 1) != 0) {
104+
return false;
105+
} else {
106+
asm volatile ("sti");
107+
return true;
108+
}
109+
clearhandler(SIGSEGV);
110+
}
111+
112+
static void expect_gp_sti(void)
113+
{
114+
if (try_sti()) {
115+
printf("[FAIL]\tSTI worked\n");
116+
nerrs++;
117+
} else {
118+
printf("[OK]\tSTI faulted\n");
119+
}
120+
}
121+
122+
static void expect_gp_cli(void)
123+
{
124+
if (try_cli()) {
125+
printf("[FAIL]\tCLI worked\n");
126+
nerrs++;
127+
} else {
128+
printf("[OK]\tCLI faulted\n");
129+
}
130+
}
131+
45132
int main(void)
46133
{
47134
cpu_set_t cpuset;
135+
48136
CPU_ZERO(&cpuset);
49137
CPU_SET(0, &cpuset);
50138
if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0)
51139
err(1, "sched_setaffinity to CPU 0");
52140

53141
/* Probe for iopl support. Note that iopl(0) works even as nonroot. */
54-
if (iopl(3) != 0) {
142+
switch(iopl(3)) {
143+
case 0:
144+
break;
145+
case -ENOSYS:
146+
printf("[OK]\tiopl() nor supported\n");
147+
return 0;
148+
default:
55149
printf("[OK]\tiopl(3) failed (%d) -- try running as root\n",
56150
errno);
57151
return 0;
58152
}
59153

60-
/* Restore our original state prior to starting the test. */
154+
/* Make sure that CLI/STI are blocked even with IOPL level 3 */
155+
expect_gp_cli();
156+
expect_gp_sti();
157+
expect_ok_outb(0x80);
158+
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");
162+
163+
/* Restore our original state prior to starting the fork test. */
61164
if (iopl(0) != 0)
62165
err(1, "iopl(0)");
63166

167+
/*
168+
* Verify that IOPL emulation is disabled and the I/O bitmap still
169+
* works.
170+
*/
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");
176+
64177
pid_t child = fork();
65178
if (child == -1)
66179
err(1, "fork");
@@ -90,14 +203,9 @@ int main(void)
90203

91204
printf("[RUN]\tparent: write to 0x80 (should fail)\n");
92205

93-
sethandler(SIGSEGV, sigsegv, 0);
94-
if (sigsetjmp(jmpbuf, 1) != 0) {
95-
printf("[OK]\twrite was denied\n");
96-
} else {
97-
asm volatile ("outb %%al, $0x80" : : "a" (0));
98-
printf("[FAIL]\twrite was allowed\n");
99-
nerrs++;
100-
}
206+
expect_gp_outb(0x80);
207+
expect_gp_cli();
208+
expect_gp_sti();
101209

102210
/* Test the capability checks. */
103211
printf("\tiopl(3)\n");
@@ -133,4 +241,3 @@ int main(void)
133241
done:
134242
return nerrs ? 1 : 0;
135243
}
136-

0 commit comments

Comments
 (0)