0001
0002
0003
0004
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
0101
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
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
0161 printf("\tVerify that unsharing the bitmap worked\n");
0162 expect_ok(0x80);
0163
0164
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 }