1 /* 2 * iopl.c - Test case for a Linux on Xen 64-bit bug 3 * Copyright (c) 2015 Andrew Lutomirski 4 */ 5 6 #define _GNU_SOURCE 7 #include <err.h> 8 #include <stdio.h> 9 #include <stdint.h> 10 #include <signal.h> 11 #include <setjmp.h> 12 #include <stdlib.h> 13 #include <string.h> 14 #include <errno.h> 15 #include <unistd.h> 16 #include <sys/types.h> 17 #include <sys/wait.h> 18 #include <stdbool.h> 19 #include <sched.h> 20 #include <sys/io.h> 21 22 static int nerrs = 0; 23 24 static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), 25 int flags) 26 { 27 struct sigaction sa; 28 memset(&sa, 0, sizeof(sa)); 29 sa.sa_sigaction = handler; 30 sa.sa_flags = SA_SIGINFO | flags; 31 sigemptyset(&sa.sa_mask); 32 if (sigaction(sig, &sa, 0)) 33 err(1, "sigaction"); 34 35 } 36 37 static jmp_buf jmpbuf; 38 39 static void sigsegv(int sig, siginfo_t *si, void *ctx_void) 40 { 41 siglongjmp(jmpbuf, 1); 42 } 43 44 int main(void) 45 { 46 cpu_set_t cpuset; 47 CPU_ZERO(&cpuset); 48 CPU_SET(0, &cpuset); 49 if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) 50 err(1, "sched_setaffinity to CPU 0"); 51 52 /* Probe for iopl support. Note that iopl(0) works even as nonroot. */ 53 if (iopl(3) != 0) { 54 printf("[OK]\tiopl(3) failed (%d) -- try running as root\n", 55 errno); 56 return 0; 57 } 58 59 /* Restore our original state prior to starting the test. */ 60 if (iopl(0) != 0) 61 err(1, "iopl(0)"); 62 63 pid_t child = fork(); 64 if (child == -1) 65 err(1, "fork"); 66 67 if (child == 0) { 68 printf("\tchild: set IOPL to 3\n"); 69 if (iopl(3) != 0) 70 err(1, "iopl"); 71 72 printf("[RUN]\tchild: write to 0x80\n"); 73 asm volatile ("outb %%al, $0x80" : : "a" (0)); 74 75 return 0; 76 } else { 77 int status; 78 if (waitpid(child, &status, 0) != child || 79 !WIFEXITED(status)) { 80 printf("[FAIL]\tChild died\n"); 81 nerrs++; 82 } else if (WEXITSTATUS(status) != 0) { 83 printf("[FAIL]\tChild failed\n"); 84 nerrs++; 85 } else { 86 printf("[OK]\tChild succeeded\n"); 87 } 88 } 89 90 printf("[RUN]\tparent: write to 0x80 (should fail)\n"); 91 92 sethandler(SIGSEGV, sigsegv, 0); 93 if (sigsetjmp(jmpbuf, 1) != 0) { 94 printf("[OK]\twrite was denied\n"); 95 } else { 96 asm volatile ("outb %%al, $0x80" : : "a" (0)); 97 printf("[FAIL]\twrite was allowed\n"); 98 nerrs++; 99 } 100 101 /* Test the capability checks. */ 102 printf("\tiopl(3)\n"); 103 if (iopl(3) != 0) 104 err(1, "iopl(3)"); 105 106 printf("\tDrop privileges\n"); 107 if (setresuid(1, 1, 1) != 0) { 108 printf("[WARN]\tDropping privileges failed\n"); 109 goto done; 110 } 111 112 printf("[RUN]\tiopl(3) unprivileged but with IOPL==3\n"); 113 if (iopl(3) != 0) { 114 printf("[FAIL]\tiopl(3) should work if iopl is already 3 even if unprivileged\n"); 115 nerrs++; 116 } 117 118 printf("[RUN]\tiopl(0) unprivileged\n"); 119 if (iopl(0) != 0) { 120 printf("[FAIL]\tiopl(0) should work if iopl is already 3 even if unprivileged\n"); 121 nerrs++; 122 } 123 124 printf("[RUN]\tiopl(3) unprivileged\n"); 125 if (iopl(3) == 0) { 126 printf("[FAIL]\tiopl(3) should fail if when unprivileged if iopl==0\n"); 127 nerrs++; 128 } else { 129 printf("[OK]\tFailed as expected\n"); 130 } 131 132 done: 133 return nerrs ? 1 : 0; 134 } 135 136