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 <tglx@linutronix.de>
This commit is contained in:
parent
111e7b15cf
commit
e638ad0080
@ -35,6 +35,16 @@ static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
|
||||
|
||||
}
|
||||
|
||||
static void clearhandler(int sig)
|
||||
{
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = SIG_DFL;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
if (sigaction(sig, &sa, 0))
|
||||
err(1, "sigaction");
|
||||
}
|
||||
|
||||
static jmp_buf jmpbuf;
|
||||
|
||||
static void sigsegv(int sig, siginfo_t *si, void *ctx_void)
|
||||
@ -42,25 +52,128 @@ static void sigsegv(int sig, siginfo_t *si, void *ctx_void)
|
||||
siglongjmp(jmpbuf, 1);
|
||||
}
|
||||
|
||||
static bool try_outb(unsigned short port)
|
||||
{
|
||||
sethandler(SIGSEGV, sigsegv, SA_RESETHAND);
|
||||
if (sigsetjmp(jmpbuf, 1) != 0) {
|
||||
return false;
|
||||
} else {
|
||||
asm volatile ("outb %%al, %w[port]"
|
||||
: : [port] "Nd" (port), "a" (0));
|
||||
return true;
|
||||
}
|
||||
clearhandler(SIGSEGV);
|
||||
}
|
||||
|
||||
static void expect_ok_outb(unsigned short port)
|
||||
{
|
||||
if (!try_outb(port)) {
|
||||
printf("[FAIL]\toutb to 0x%02hx failed\n", port);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("[OK]\toutb to 0x%02hx worked\n", port);
|
||||
}
|
||||
|
||||
static void expect_gp_outb(unsigned short port)
|
||||
{
|
||||
if (try_outb(port)) {
|
||||
printf("[FAIL]\toutb to 0x%02hx worked\n", port);
|
||||
nerrs++;
|
||||
}
|
||||
|
||||
printf("[OK]\toutb to 0x%02hx failed\n", port);
|
||||
}
|
||||
|
||||
static bool try_cli(void)
|
||||
{
|
||||
sethandler(SIGSEGV, sigsegv, SA_RESETHAND);
|
||||
if (sigsetjmp(jmpbuf, 1) != 0) {
|
||||
return false;
|
||||
} else {
|
||||
asm volatile ("cli");
|
||||
return true;
|
||||
}
|
||||
clearhandler(SIGSEGV);
|
||||
}
|
||||
|
||||
static bool try_sti(void)
|
||||
{
|
||||
sethandler(SIGSEGV, sigsegv, SA_RESETHAND);
|
||||
if (sigsetjmp(jmpbuf, 1) != 0) {
|
||||
return false;
|
||||
} else {
|
||||
asm volatile ("sti");
|
||||
return true;
|
||||
}
|
||||
clearhandler(SIGSEGV);
|
||||
}
|
||||
|
||||
static void expect_gp_sti(void)
|
||||
{
|
||||
if (try_sti()) {
|
||||
printf("[FAIL]\tSTI worked\n");
|
||||
nerrs++;
|
||||
} else {
|
||||
printf("[OK]\tSTI faulted\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void expect_gp_cli(void)
|
||||
{
|
||||
if (try_cli()) {
|
||||
printf("[FAIL]\tCLI worked\n");
|
||||
nerrs++;
|
||||
} else {
|
||||
printf("[OK]\tCLI faulted\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
cpu_set_t cpuset;
|
||||
|
||||
CPU_ZERO(&cpuset);
|
||||
CPU_SET(0, &cpuset);
|
||||
if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0)
|
||||
err(1, "sched_setaffinity to CPU 0");
|
||||
|
||||
/* Probe for iopl support. Note that iopl(0) works even as nonroot. */
|
||||
if (iopl(3) != 0) {
|
||||
switch(iopl(3)) {
|
||||
case 0:
|
||||
break;
|
||||
case -ENOSYS:
|
||||
printf("[OK]\tiopl() nor supported\n");
|
||||
return 0;
|
||||
default:
|
||||
printf("[OK]\tiopl(3) failed (%d) -- try running as root\n",
|
||||
errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Restore our original state prior to starting the test. */
|
||||
/* Make sure that CLI/STI are blocked even with IOPL level 3 */
|
||||
expect_gp_cli();
|
||||
expect_gp_sti();
|
||||
expect_ok_outb(0x80);
|
||||
|
||||
/* Establish an I/O bitmap to test the restore */
|
||||
if (ioperm(0x80, 1, 1) != 0)
|
||||
err(1, "ioperm(0x80, 1, 1) failed\n");
|
||||
|
||||
/* Restore our original state prior to starting the fork test. */
|
||||
if (iopl(0) != 0)
|
||||
err(1, "iopl(0)");
|
||||
|
||||
/*
|
||||
* Verify that IOPL emulation is disabled and the I/O bitmap still
|
||||
* works.
|
||||
*/
|
||||
expect_ok_outb(0x80);
|
||||
expect_gp_outb(0xed);
|
||||
/* Drop the I/O bitmap */
|
||||
if (ioperm(0x80, 1, 0) != 0)
|
||||
err(1, "ioperm(0x80, 1, 0) failed\n");
|
||||
|
||||
pid_t child = fork();
|
||||
if (child == -1)
|
||||
err(1, "fork");
|
||||
@ -90,14 +203,9 @@ int main(void)
|
||||
|
||||
printf("[RUN]\tparent: write to 0x80 (should fail)\n");
|
||||
|
||||
sethandler(SIGSEGV, sigsegv, 0);
|
||||
if (sigsetjmp(jmpbuf, 1) != 0) {
|
||||
printf("[OK]\twrite was denied\n");
|
||||
} else {
|
||||
asm volatile ("outb %%al, $0x80" : : "a" (0));
|
||||
printf("[FAIL]\twrite was allowed\n");
|
||||
nerrs++;
|
||||
}
|
||||
expect_gp_outb(0x80);
|
||||
expect_gp_cli();
|
||||
expect_gp_sti();
|
||||
|
||||
/* Test the capability checks. */
|
||||
printf("\tiopl(3)\n");
|
||||
@ -133,4 +241,3 @@ int main(void)
|
||||
done:
|
||||
return nerrs ? 1 : 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user