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

Configure Feed

Select the types of activity you want to include in your feed.

at v6.16-rc1 260 lines 5.2 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * iopl.c - Test case for a Linux on Xen 64-bit bug 4 * Copyright (c) 2015 Andrew Lutomirski 5 */ 6 7#define _GNU_SOURCE 8#include <err.h> 9#include <stdio.h> 10#include <stdint.h> 11#include <signal.h> 12#include <setjmp.h> 13#include <stdlib.h> 14#include <string.h> 15#include <errno.h> 16#include <unistd.h> 17#include <sys/types.h> 18#include <sys/wait.h> 19#include <stdbool.h> 20#include <sched.h> 21#include <sys/io.h> 22 23#include "helpers.h" 24 25static int nerrs = 0; 26 27static jmp_buf jmpbuf; 28 29static void sigsegv(int sig, siginfo_t *si, void *ctx_void) 30{ 31 siglongjmp(jmpbuf, 1); 32} 33 34static bool try_outb(unsigned short port) 35{ 36 sethandler(SIGSEGV, sigsegv, SA_RESETHAND); 37 if (sigsetjmp(jmpbuf, 1) != 0) { 38 return false; 39 } else { 40 asm volatile ("outb %%al, %w[port]" 41 : : [port] "Nd" (port), "a" (0)); 42 return true; 43 } 44 clearhandler(SIGSEGV); 45} 46 47static void expect_ok_outb(unsigned short port) 48{ 49 if (!try_outb(port)) { 50 printf("[FAIL]\toutb to 0x%02hx failed\n", port); 51 exit(1); 52 } 53 54 printf("[OK]\toutb to 0x%02hx worked\n", port); 55} 56 57static void expect_gp_outb(unsigned short port) 58{ 59 if (try_outb(port)) { 60 printf("[FAIL]\toutb to 0x%02hx worked\n", port); 61 nerrs++; 62 } 63 64 printf("[OK]\toutb to 0x%02hx failed\n", port); 65} 66 67#define RET_FAULTED 0 68#define RET_FAIL 1 69#define RET_EMUL 2 70 71static int try_cli(void) 72{ 73 unsigned long flags; 74 75 sethandler(SIGSEGV, sigsegv, SA_RESETHAND); 76 if (sigsetjmp(jmpbuf, 1) != 0) { 77 return RET_FAULTED; 78 } else { 79 asm volatile("cli; pushf; pop %[flags]" 80 : [flags] "=rm" (flags)); 81 82 /* X86_FLAGS_IF */ 83 if (!(flags & (1 << 9))) 84 return RET_FAIL; 85 else 86 return RET_EMUL; 87 } 88 clearhandler(SIGSEGV); 89} 90 91static int try_sti(bool irqs_off) 92{ 93 unsigned long flags; 94 95 sethandler(SIGSEGV, sigsegv, SA_RESETHAND); 96 if (sigsetjmp(jmpbuf, 1) != 0) { 97 return RET_FAULTED; 98 } else { 99 asm volatile("sti; pushf; pop %[flags]" 100 : [flags] "=rm" (flags)); 101 102 /* X86_FLAGS_IF */ 103 if (irqs_off && (flags & (1 << 9))) 104 return RET_FAIL; 105 else 106 return RET_EMUL; 107 } 108 clearhandler(SIGSEGV); 109} 110 111static void expect_gp_sti(bool irqs_off) 112{ 113 int ret = try_sti(irqs_off); 114 115 switch (ret) { 116 case RET_FAULTED: 117 printf("[OK]\tSTI faulted\n"); 118 break; 119 case RET_EMUL: 120 printf("[OK]\tSTI NOPped\n"); 121 break; 122 default: 123 printf("[FAIL]\tSTI worked\n"); 124 nerrs++; 125 } 126} 127 128/* 129 * Returns whether it managed to disable interrupts. 130 */ 131static bool test_cli(void) 132{ 133 int ret = try_cli(); 134 135 switch (ret) { 136 case RET_FAULTED: 137 printf("[OK]\tCLI faulted\n"); 138 break; 139 case RET_EMUL: 140 printf("[OK]\tCLI NOPped\n"); 141 break; 142 default: 143 printf("[FAIL]\tCLI worked\n"); 144 nerrs++; 145 return true; 146 } 147 148 return false; 149} 150 151int main(void) 152{ 153 cpu_set_t cpuset; 154 155 CPU_ZERO(&cpuset); 156 CPU_SET(0, &cpuset); 157 if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) 158 err(1, "sched_setaffinity to CPU 0"); 159 160 /* Probe for iopl support. Note that iopl(0) works even as nonroot. */ 161 switch(iopl(3)) { 162 case 0: 163 break; 164 case -ENOSYS: 165 printf("[OK]\tiopl() nor supported\n"); 166 return 0; 167 default: 168 printf("[OK]\tiopl(3) failed (%d) -- try running as root\n", 169 errno); 170 return 0; 171 } 172 173 /* Make sure that CLI/STI are blocked even with IOPL level 3 */ 174 expect_gp_sti(test_cli()); 175 expect_ok_outb(0x80); 176 177 /* Establish an I/O bitmap to test the restore */ 178 if (ioperm(0x80, 1, 1) != 0) 179 err(1, "ioperm(0x80, 1, 1) failed\n"); 180 181 /* Restore our original state prior to starting the fork test. */ 182 if (iopl(0) != 0) 183 err(1, "iopl(0)"); 184 185 /* 186 * Verify that IOPL emulation is disabled and the I/O bitmap still 187 * works. 188 */ 189 expect_ok_outb(0x80); 190 expect_gp_outb(0xed); 191 /* Drop the I/O bitmap */ 192 if (ioperm(0x80, 1, 0) != 0) 193 err(1, "ioperm(0x80, 1, 0) failed\n"); 194 195 pid_t child = fork(); 196 if (child == -1) 197 err(1, "fork"); 198 199 if (child == 0) { 200 printf("\tchild: set IOPL to 3\n"); 201 if (iopl(3) != 0) 202 err(1, "iopl"); 203 204 printf("[RUN]\tchild: write to 0x80\n"); 205 asm volatile ("outb %%al, $0x80" : : "a" (0)); 206 207 return 0; 208 } else { 209 int status; 210 if (waitpid(child, &status, 0) != child || 211 !WIFEXITED(status)) { 212 printf("[FAIL]\tChild died\n"); 213 nerrs++; 214 } else if (WEXITSTATUS(status) != 0) { 215 printf("[FAIL]\tChild failed\n"); 216 nerrs++; 217 } else { 218 printf("[OK]\tChild succeeded\n"); 219 } 220 } 221 222 printf("[RUN]\tparent: write to 0x80 (should fail)\n"); 223 224 expect_gp_outb(0x80); 225 expect_gp_sti(test_cli()); 226 227 /* Test the capability checks. */ 228 printf("\tiopl(3)\n"); 229 if (iopl(3) != 0) 230 err(1, "iopl(3)"); 231 232 printf("\tDrop privileges\n"); 233 if (setresuid(1, 1, 1) != 0) { 234 printf("[WARN]\tDropping privileges failed\n"); 235 goto done; 236 } 237 238 printf("[RUN]\tiopl(3) unprivileged but with IOPL==3\n"); 239 if (iopl(3) != 0) { 240 printf("[FAIL]\tiopl(3) should work if iopl is already 3 even if unprivileged\n"); 241 nerrs++; 242 } 243 244 printf("[RUN]\tiopl(0) unprivileged\n"); 245 if (iopl(0) != 0) { 246 printf("[FAIL]\tiopl(0) should work if iopl is already 3 even if unprivileged\n"); 247 nerrs++; 248 } 249 250 printf("[RUN]\tiopl(3) unprivileged\n"); 251 if (iopl(3) == 0) { 252 printf("[FAIL]\tiopl(3) should fail if when unprivileged if iopl==0\n"); 253 nerrs++; 254 } else { 255 printf("[OK]\tFailed as expected\n"); 256 } 257 258done: 259 return nerrs ? 1 : 0; 260}