Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * ioperm.c - Test case for ioperm(2)
0004  * Copyright (c) 2015 Andrew Lutomirski
0005  */
0006 
0007 #define _GNU_SOURCE
0008 #include <err.h>
0009 #include <stdio.h>
0010 #include <stdint.h>
0011 #include <signal.h>
0012 #include <setjmp.h>
0013 #include <stdlib.h>
0014 #include <string.h>
0015 #include <errno.h>
0016 #include <unistd.h>
0017 #include <sys/types.h>
0018 #include <sys/wait.h>
0019 #include <stdbool.h>
0020 #include <sched.h>
0021 #include <sys/io.h>
0022 
0023 static int nerrs = 0;
0024 
0025 static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
0026                int flags)
0027 {
0028     struct sigaction sa;
0029     memset(&sa, 0, sizeof(sa));
0030     sa.sa_sigaction = handler;
0031     sa.sa_flags = SA_SIGINFO | flags;
0032     sigemptyset(&sa.sa_mask);
0033     if (sigaction(sig, &sa, 0))
0034         err(1, "sigaction");
0035 
0036 }
0037 
0038 static void clearhandler(int sig)
0039 {
0040     struct sigaction sa;
0041     memset(&sa, 0, sizeof(sa));
0042     sa.sa_handler = SIG_DFL;
0043     sigemptyset(&sa.sa_mask);
0044     if (sigaction(sig, &sa, 0))
0045         err(1, "sigaction");
0046 }
0047 
0048 static jmp_buf jmpbuf;
0049 
0050 static void sigsegv(int sig, siginfo_t *si, void *ctx_void)
0051 {
0052     siglongjmp(jmpbuf, 1);
0053 }
0054 
0055 static bool try_outb(unsigned short port)
0056 {
0057     sethandler(SIGSEGV, sigsegv, SA_RESETHAND);
0058     if (sigsetjmp(jmpbuf, 1) != 0) {
0059         return false;
0060     } else {
0061         asm volatile ("outb %%al, %w[port]"
0062                   : : [port] "Nd" (port), "a" (0));
0063         return true;
0064     }
0065     clearhandler(SIGSEGV);
0066 }
0067 
0068 static void expect_ok(unsigned short port)
0069 {
0070     if (!try_outb(port)) {
0071         printf("[FAIL]\toutb to 0x%02hx failed\n", port);
0072         exit(1);
0073     }
0074 
0075     printf("[OK]\toutb to 0x%02hx worked\n", port);
0076 }
0077 
0078 static void expect_gp(unsigned short port)
0079 {
0080     if (try_outb(port)) {
0081         printf("[FAIL]\toutb to 0x%02hx worked\n", port);
0082         exit(1);
0083     }
0084 
0085     printf("[OK]\toutb to 0x%02hx failed\n", port);
0086 }
0087 
0088 int main(void)
0089 {
0090     cpu_set_t cpuset;
0091     CPU_ZERO(&cpuset);
0092     CPU_SET(0, &cpuset);
0093     if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0)
0094         err(1, "sched_setaffinity to CPU 0");
0095 
0096     expect_gp(0x80);
0097     expect_gp(0xed);
0098 
0099     /*
0100      * Probe for ioperm support.  Note that clearing ioperm bits
0101      * works even as nonroot.
0102      */
0103     printf("[RUN]\tenable 0x80\n");
0104     if (ioperm(0x80, 1, 1) != 0) {
0105         printf("[OK]\tioperm(0x80, 1, 1) failed (%d) -- try running as root\n",
0106                errno);
0107         return 0;
0108     }
0109     expect_ok(0x80);
0110     expect_gp(0xed);
0111 
0112     printf("[RUN]\tdisable 0x80\n");
0113     if (ioperm(0x80, 1, 0) != 0) {
0114         printf("[FAIL]\tioperm(0x80, 1, 0) failed (%d)", errno);
0115         return 1;
0116     }
0117     expect_gp(0x80);
0118     expect_gp(0xed);
0119 
0120     /* Make sure that fork() preserves ioperm. */
0121     if (ioperm(0x80, 1, 1) != 0) {
0122         printf("[FAIL]\tioperm(0x80, 1, 0) failed (%d)", errno);
0123         return 1;
0124     }
0125 
0126     pid_t child = fork();
0127     if (child == -1)
0128         err(1, "fork");
0129 
0130     if (child == 0) {
0131         printf("[RUN]\tchild: check that we inherited permissions\n");
0132         expect_ok(0x80);
0133         expect_gp(0xed);
0134         printf("[RUN]\tchild: Extend permissions to 0x81\n");
0135         if (ioperm(0x81, 1, 1) != 0) {
0136             printf("[FAIL]\tioperm(0x81, 1, 1) failed (%d)", errno);
0137             return 1;
0138         }
0139         printf("[RUN]\tchild: Drop permissions to 0x80\n");
0140         if (ioperm(0x80, 1, 0) != 0) {
0141             printf("[FAIL]\tioperm(0x80, 1, 0) failed (%d)", errno);
0142             return 1;
0143         }
0144         expect_gp(0x80);
0145         return 0;
0146     } else {
0147         int status;
0148         if (waitpid(child, &status, 0) != child ||
0149             !WIFEXITED(status)) {
0150             printf("[FAIL]\tChild died\n");
0151             nerrs++;
0152         } else if (WEXITSTATUS(status) != 0) {
0153             printf("[FAIL]\tChild failed\n");
0154             nerrs++;
0155         } else {
0156             printf("[OK]\tChild succeeded\n");
0157         }
0158     }
0159 
0160     /* Verify that the child dropping 0x80 did not affect the parent */
0161     printf("\tVerify that unsharing the bitmap worked\n");
0162     expect_ok(0x80);
0163 
0164     /* Test the capability checks. */
0165     printf("\tDrop privileges\n");
0166     if (setresuid(1, 1, 1) != 0) {
0167         printf("[WARN]\tDropping privileges failed\n");
0168         return 0;
0169     }
0170 
0171     printf("[RUN]\tdisable 0x80\n");
0172     if (ioperm(0x80, 1, 0) != 0) {
0173         printf("[FAIL]\tioperm(0x80, 1, 0) failed (%d)", errno);
0174         return 1;
0175     }
0176     printf("[OK]\tit worked\n");
0177 
0178     printf("[RUN]\tenable 0x80 again\n");
0179     if (ioperm(0x80, 1, 1) == 0) {
0180         printf("[FAIL]\tit succeeded but should have failed.\n");
0181         return 1;
0182     }
0183     printf("[OK]\tit failed\n");
0184     return 0;
0185 }