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

Configure Feed

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

at v5.4 171 lines 3.6 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * ioperm.c - Test case for ioperm(2) 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 23static int nerrs = 0; 24 25static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), 26 int flags) 27{ 28 struct sigaction sa; 29 memset(&sa, 0, sizeof(sa)); 30 sa.sa_sigaction = handler; 31 sa.sa_flags = SA_SIGINFO | flags; 32 sigemptyset(&sa.sa_mask); 33 if (sigaction(sig, &sa, 0)) 34 err(1, "sigaction"); 35 36} 37 38static 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 48static jmp_buf jmpbuf; 49 50static void sigsegv(int sig, siginfo_t *si, void *ctx_void) 51{ 52 siglongjmp(jmpbuf, 1); 53} 54 55static bool try_outb(unsigned short port) 56{ 57 sethandler(SIGSEGV, sigsegv, SA_RESETHAND); 58 if (sigsetjmp(jmpbuf, 1) != 0) { 59 return false; 60 } else { 61 asm volatile ("outb %%al, %w[port]" 62 : : [port] "Nd" (port), "a" (0)); 63 return true; 64 } 65 clearhandler(SIGSEGV); 66} 67 68static void expect_ok(unsigned short port) 69{ 70 if (!try_outb(port)) { 71 printf("[FAIL]\toutb to 0x%02hx failed\n", port); 72 exit(1); 73 } 74 75 printf("[OK]\toutb to 0x%02hx worked\n", port); 76} 77 78static void expect_gp(unsigned short port) 79{ 80 if (try_outb(port)) { 81 printf("[FAIL]\toutb to 0x%02hx worked\n", port); 82 exit(1); 83 } 84 85 printf("[OK]\toutb to 0x%02hx failed\n", port); 86} 87 88int main(void) 89{ 90 cpu_set_t cpuset; 91 CPU_ZERO(&cpuset); 92 CPU_SET(0, &cpuset); 93 if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) 94 err(1, "sched_setaffinity to CPU 0"); 95 96 expect_gp(0x80); 97 expect_gp(0xed); 98 99 /* 100 * Probe for ioperm support. Note that clearing ioperm bits 101 * works even as nonroot. 102 */ 103 printf("[RUN]\tenable 0x80\n"); 104 if (ioperm(0x80, 1, 1) != 0) { 105 printf("[OK]\tioperm(0x80, 1, 1) failed (%d) -- try running as root\n", 106 errno); 107 return 0; 108 } 109 expect_ok(0x80); 110 expect_gp(0xed); 111 112 printf("[RUN]\tdisable 0x80\n"); 113 if (ioperm(0x80, 1, 0) != 0) { 114 printf("[FAIL]\tioperm(0x80, 1, 0) failed (%d)", errno); 115 return 1; 116 } 117 expect_gp(0x80); 118 expect_gp(0xed); 119 120 /* Make sure that fork() preserves ioperm. */ 121 if (ioperm(0x80, 1, 1) != 0) { 122 printf("[FAIL]\tioperm(0x80, 1, 0) failed (%d)", errno); 123 return 1; 124 } 125 126 pid_t child = fork(); 127 if (child == -1) 128 err(1, "fork"); 129 130 if (child == 0) { 131 printf("[RUN]\tchild: check that we inherited permissions\n"); 132 expect_ok(0x80); 133 expect_gp(0xed); 134 return 0; 135 } else { 136 int status; 137 if (waitpid(child, &status, 0) != child || 138 !WIFEXITED(status)) { 139 printf("[FAIL]\tChild died\n"); 140 nerrs++; 141 } else if (WEXITSTATUS(status) != 0) { 142 printf("[FAIL]\tChild failed\n"); 143 nerrs++; 144 } else { 145 printf("[OK]\tChild succeeded\n"); 146 } 147 } 148 149 /* Test the capability checks. */ 150 151 printf("\tDrop privileges\n"); 152 if (setresuid(1, 1, 1) != 0) { 153 printf("[WARN]\tDropping privileges failed\n"); 154 return 0; 155 } 156 157 printf("[RUN]\tdisable 0x80\n"); 158 if (ioperm(0x80, 1, 0) != 0) { 159 printf("[FAIL]\tioperm(0x80, 1, 0) failed (%d)", errno); 160 return 1; 161 } 162 printf("[OK]\tit worked\n"); 163 164 printf("[RUN]\tenable 0x80 again\n"); 165 if (ioperm(0x80, 1, 1) == 0) { 166 printf("[FAIL]\tit succeeded but should have failed.\n"); 167 return 1; 168 } 169 printf("[OK]\tit failed\n"); 170 return 0; 171}