1
2
3
4
5
6#define _GNU_SOURCE
7#include <err.h>
8#include <stdio.h>
9#include <stdint.h>
10#include <signal.h>
11#include <setjmp.h>
12#include <stdlib.h>
13#include <string.h>
14#include <errno.h>
15#include <unistd.h>
16#include <sys/types.h>
17#include <sys/wait.h>
18#include <stdbool.h>
19#include <sched.h>
20#include <sys/io.h>
21
22static int nerrs = 0;
23
24static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
25 int flags)
26{
27 struct sigaction sa;
28 memset(&sa, 0, sizeof(sa));
29 sa.sa_sigaction = handler;
30 sa.sa_flags = SA_SIGINFO | flags;
31 sigemptyset(&sa.sa_mask);
32 if (sigaction(sig, &sa, 0))
33 err(1, "sigaction");
34
35}
36
37static jmp_buf jmpbuf;
38
39static void sigsegv(int sig, siginfo_t *si, void *ctx_void)
40{
41 siglongjmp(jmpbuf, 1);
42}
43
44int main(void)
45{
46 cpu_set_t cpuset;
47 CPU_ZERO(&cpuset);
48 CPU_SET(0, &cpuset);
49 if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0)
50 err(1, "sched_setaffinity to CPU 0");
51
52
53 if (iopl(3) != 0) {
54 printf("[OK]\tiopl(3) failed (%d) -- try running as root\n",
55 errno);
56 return 0;
57 }
58
59
60 if (iopl(0) != 0)
61 err(1, "iopl(0)");
62
63 pid_t child = fork();
64 if (child == -1)
65 err(1, "fork");
66
67 if (child == 0) {
68 printf("\tchild: set IOPL to 3\n");
69 if (iopl(3) != 0)
70 err(1, "iopl");
71
72 printf("[RUN]\tchild: write to 0x80\n");
73 asm volatile ("outb %%al, $0x80" : : "a" (0));
74
75 return 0;
76 } else {
77 int status;
78 if (waitpid(child, &status, 0) != child ||
79 !WIFEXITED(status)) {
80 printf("[FAIL]\tChild died\n");
81 nerrs++;
82 } else if (WEXITSTATUS(status) != 0) {
83 printf("[FAIL]\tChild failed\n");
84 nerrs++;
85 } else {
86 printf("[OK]\tChild succeeded\n");
87 }
88 }
89
90 printf("[RUN]\tparent: write to 0x80 (should fail)\n");
91
92 sethandler(SIGSEGV, sigsegv, 0);
93 if (sigsetjmp(jmpbuf, 1) != 0) {
94 printf("[OK]\twrite was denied\n");
95 } else {
96 asm volatile ("outb %%al, $0x80" : : "a" (0));
97 printf("[FAIL]\twrite was allowed\n");
98 nerrs++;
99 }
100
101
102 printf("\tiopl(3)\n");
103 if (iopl(3) != 0)
104 err(1, "iopl(3)");
105
106 printf("\tDrop privileges\n");
107 if (setresuid(1, 1, 1) != 0) {
108 printf("[WARN]\tDropping privileges failed\n");
109 goto done;
110 }
111
112 printf("[RUN]\tiopl(3) unprivileged but with IOPL==3\n");
113 if (iopl(3) != 0) {
114 printf("[FAIL]\tiopl(3) should work if iopl is already 3 even if unprivileged\n");
115 nerrs++;
116 }
117
118 printf("[RUN]\tiopl(0) unprivileged\n");
119 if (iopl(0) != 0) {
120 printf("[FAIL]\tiopl(0) should work if iopl is already 3 even if unprivileged\n");
121 nerrs++;
122 }
123
124 printf("[RUN]\tiopl(3) unprivileged\n");
125 if (iopl(3) == 0) {
126 printf("[FAIL]\tiopl(3) should fail if when unprivileged if iopl==0\n");
127 nerrs++;
128 } else {
129 printf("[OK]\tFailed as expected\n");
130 }
131
132done:
133 return nerrs ? 1 : 0;
134}
135
136