186 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * ioperm.c - Test case for ioperm(2)4 * Copyright (c) 2015 Andrew Lutomirski5 */6 7#define _GNU_SOURCE8#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 bits101 * 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 printf("[RUN]\tchild: Extend permissions to 0x81\n");135 if (ioperm(0x81, 1, 1) != 0) {136 printf("[FAIL]\tioperm(0x81, 1, 1) failed (%d)", errno);137 return 1;138 }139 printf("[RUN]\tchild: Drop permissions to 0x80\n");140 if (ioperm(0x80, 1, 0) != 0) {141 printf("[FAIL]\tioperm(0x80, 1, 0) failed (%d)", errno);142 return 1;143 }144 expect_gp(0x80);145 return 0;146 } else {147 int status;148 if (waitpid(child, &status, 0) != child ||149 !WIFEXITED(status)) {150 printf("[FAIL]\tChild died\n");151 nerrs++;152 } else if (WEXITSTATUS(status) != 0) {153 printf("[FAIL]\tChild failed\n");154 nerrs++;155 } else {156 printf("[OK]\tChild succeeded\n");157 }158 }159 160 /* Verify that the child dropping 0x80 did not affect the parent */161 printf("\tVerify that unsharing the bitmap worked\n");162 expect_ok(0x80);163 164 /* Test the capability checks. */165 printf("\tDrop privileges\n");166 if (setresuid(1, 1, 1) != 0) {167 printf("[WARN]\tDropping privileges failed\n");168 return 0;169 }170 171 printf("[RUN]\tdisable 0x80\n");172 if (ioperm(0x80, 1, 0) != 0) {173 printf("[FAIL]\tioperm(0x80, 1, 0) failed (%d)", errno);174 return 1;175 }176 printf("[OK]\tit worked\n");177 178 printf("[RUN]\tenable 0x80 again\n");179 if (ioperm(0x80, 1, 1) == 0) {180 printf("[FAIL]\tit succeeded but should have failed.\n");181 return 1;182 }183 printf("[OK]\tit failed\n");184 return 0;185}186