root/tools/testing/selftests/x86/ioperm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sethandler
  2. clearhandler
  3. sigsegv
  4. try_outb
  5. expect_ok
  6. expect_gp
  7. main

   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 
  23 static int nerrs = 0;
  24 
  25 static 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 
  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 
  48 static jmp_buf jmpbuf;
  49 
  50 static void sigsegv(int sig, siginfo_t *si, void *ctx_void)
  51 {
  52         siglongjmp(jmpbuf, 1);
  53 }
  54 
  55 static 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 
  68 static 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 
  78 static 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 
  88 int 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 }

/* [<][>][^][v][top][bottom][index][help] */