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

selftests/x86: Add an iopl test

This exercises two cases that are known to be buggy on Xen PV right
now.

Signed-off-by: Andy Lutomirski <luto@kernel.org>
Cc: Andrew Cooper <andrew.cooper3@citrix.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: David Vrabel <david.vrabel@citrix.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Jan Beulich <JBeulich@suse.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/61afe904c95c92abb29cd075b51e10e7feb0f774.1458162709.git.luto@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Andy Lutomirski and committed by
Ingo Molnar
b0898301 00f52685

+136 -1
+1 -1
tools/testing/selftests/x86/Makefile
··· 5 5 .PHONY: all all_32 all_64 warn_32bit_failure clean 6 6 7 7 TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall \ 8 - check_initial_reg_state sigreturn ldt_gdt 8 + check_initial_reg_state sigreturn ldt_gdt iopl 9 9 TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \ 10 10 test_FCMOV test_FCOMI test_FISTTP \ 11 11 vdso_restorer
+135
tools/testing/selftests/x86/iopl.c
··· 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 +