Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>


+118 -11
+118 -11
tools/testing/selftests/x86/iopl.c
··· 35 35 36 36 } 37 37 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 + 38 48 static jmp_buf jmpbuf; 39 49 40 50 static void sigsegv(int sig, siginfo_t *si, void *ctx_void) ··· 52 42 siglongjmp(jmpbuf, 1); 53 43 } 54 44 45 + static bool try_outb(unsigned short port) 46 + { 47 + sethandler(SIGSEGV, sigsegv, SA_RESETHAND); 48 + if (sigsetjmp(jmpbuf, 1) != 0) { 49 + return false; 50 + } else { 51 + asm volatile ("outb %%al, %w[port]" 52 + : : [port] "Nd" (port), "a" (0)); 53 + return true; 54 + } 55 + clearhandler(SIGSEGV); 56 + } 57 + 58 + static void expect_ok_outb(unsigned short port) 59 + { 60 + if (!try_outb(port)) { 61 + printf("[FAIL]\toutb to 0x%02hx failed\n", port); 62 + exit(1); 63 + } 64 + 65 + printf("[OK]\toutb to 0x%02hx worked\n", port); 66 + } 67 + 68 + static void expect_gp_outb(unsigned short port) 69 + { 70 + if (try_outb(port)) { 71 + printf("[FAIL]\toutb to 0x%02hx worked\n", port); 72 + nerrs++; 73 + } 74 + 75 + printf("[OK]\toutb to 0x%02hx failed\n", port); 76 + } 77 + 78 + static bool try_cli(void) 79 + { 80 + sethandler(SIGSEGV, sigsegv, SA_RESETHAND); 81 + if (sigsetjmp(jmpbuf, 1) != 0) { 82 + return false; 83 + } else { 84 + asm volatile ("cli"); 85 + return true; 86 + } 87 + clearhandler(SIGSEGV); 88 + } 89 + 90 + static bool try_sti(void) 91 + { 92 + sethandler(SIGSEGV, sigsegv, SA_RESETHAND); 93 + if (sigsetjmp(jmpbuf, 1) != 0) { 94 + return false; 95 + } else { 96 + asm volatile ("sti"); 97 + return true; 98 + } 99 + clearhandler(SIGSEGV); 100 + } 101 + 102 + static void expect_gp_sti(void) 103 + { 104 + if (try_sti()) { 105 + printf("[FAIL]\tSTI worked\n"); 106 + nerrs++; 107 + } else { 108 + printf("[OK]\tSTI faulted\n"); 109 + } 110 + } 111 + 112 + static void expect_gp_cli(void) 113 + { 114 + if (try_cli()) { 115 + printf("[FAIL]\tCLI worked\n"); 116 + nerrs++; 117 + } else { 118 + printf("[OK]\tCLI faulted\n"); 119 + } 120 + } 121 + 55 122 int main(void) 56 123 { 57 124 cpu_set_t cpuset; 125 + 58 126 CPU_ZERO(&cpuset); 59 127 CPU_SET(0, &cpuset); 60 128 if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) 61 129 err(1, "sched_setaffinity to CPU 0"); 62 130 63 131 /* Probe for iopl support. Note that iopl(0) works even as nonroot. */ 64 - if (iopl(3) != 0) { 132 + switch(iopl(3)) { 133 + case 0: 134 + break; 135 + case -ENOSYS: 136 + printf("[OK]\tiopl() nor supported\n"); 137 + return 0; 138 + default: 65 139 printf("[OK]\tiopl(3) failed (%d) -- try running as root\n", 66 140 errno); 67 141 return 0; 68 142 } 69 143 70 - /* Restore our original state prior to starting the test. */ 144 + /* Make sure that CLI/STI are blocked even with IOPL level 3 */ 145 + expect_gp_cli(); 146 + expect_gp_sti(); 147 + expect_ok_outb(0x80); 148 + 149 + /* Establish an I/O bitmap to test the restore */ 150 + if (ioperm(0x80, 1, 1) != 0) 151 + err(1, "ioperm(0x80, 1, 1) failed\n"); 152 + 153 + /* Restore our original state prior to starting the fork test. */ 71 154 if (iopl(0) != 0) 72 155 err(1, "iopl(0)"); 156 + 157 + /* 158 + * Verify that IOPL emulation is disabled and the I/O bitmap still 159 + * works. 160 + */ 161 + expect_ok_outb(0x80); 162 + expect_gp_outb(0xed); 163 + /* Drop the I/O bitmap */ 164 + if (ioperm(0x80, 1, 0) != 0) 165 + err(1, "ioperm(0x80, 1, 0) failed\n"); 73 166 74 167 pid_t child = fork(); 75 168 if (child == -1) ··· 203 90 204 91 printf("[RUN]\tparent: write to 0x80 (should fail)\n"); 205 92 206 - sethandler(SIGSEGV, sigsegv, 0); 207 - if (sigsetjmp(jmpbuf, 1) != 0) { 208 - printf("[OK]\twrite was denied\n"); 209 - } else { 210 - asm volatile ("outb %%al, $0x80" : : "a" (0)); 211 - printf("[FAIL]\twrite was allowed\n"); 212 - nerrs++; 213 - } 93 + expect_gp_outb(0x80); 94 + expect_gp_cli(); 95 + expect_gp_sti(); 214 96 215 97 /* Test the capability checks. */ 216 98 printf("\tiopl(3)\n"); ··· 241 133 done: 242 134 return nerrs ? 1 : 0; 243 135 } 244 -