1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
20eb1d0faSAndy Lutomirski /*
30eb1d0faSAndy Lutomirski * ioperm.c - Test case for ioperm(2)
40eb1d0faSAndy Lutomirski * Copyright (c) 2015 Andrew Lutomirski
50eb1d0faSAndy Lutomirski */
60eb1d0faSAndy Lutomirski
70eb1d0faSAndy Lutomirski #define _GNU_SOURCE
80eb1d0faSAndy Lutomirski #include <err.h>
90eb1d0faSAndy Lutomirski #include <stdio.h>
100eb1d0faSAndy Lutomirski #include <stdint.h>
110eb1d0faSAndy Lutomirski #include <signal.h>
120eb1d0faSAndy Lutomirski #include <setjmp.h>
130eb1d0faSAndy Lutomirski #include <stdlib.h>
140eb1d0faSAndy Lutomirski #include <string.h>
150eb1d0faSAndy Lutomirski #include <errno.h>
160eb1d0faSAndy Lutomirski #include <unistd.h>
170eb1d0faSAndy Lutomirski #include <sys/types.h>
180eb1d0faSAndy Lutomirski #include <sys/wait.h>
190eb1d0faSAndy Lutomirski #include <stdbool.h>
200eb1d0faSAndy Lutomirski #include <sched.h>
210eb1d0faSAndy Lutomirski #include <sys/io.h>
220eb1d0faSAndy Lutomirski
230eb1d0faSAndy Lutomirski static int nerrs = 0;
240eb1d0faSAndy Lutomirski
sethandler(int sig,void (* handler)(int,siginfo_t *,void *),int flags)250eb1d0faSAndy Lutomirski static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
260eb1d0faSAndy Lutomirski int flags)
270eb1d0faSAndy Lutomirski {
280eb1d0faSAndy Lutomirski struct sigaction sa;
290eb1d0faSAndy Lutomirski memset(&sa, 0, sizeof(sa));
300eb1d0faSAndy Lutomirski sa.sa_sigaction = handler;
310eb1d0faSAndy Lutomirski sa.sa_flags = SA_SIGINFO | flags;
320eb1d0faSAndy Lutomirski sigemptyset(&sa.sa_mask);
330eb1d0faSAndy Lutomirski if (sigaction(sig, &sa, 0))
340eb1d0faSAndy Lutomirski err(1, "sigaction");
350eb1d0faSAndy Lutomirski
360eb1d0faSAndy Lutomirski }
370eb1d0faSAndy Lutomirski
clearhandler(int sig)380eb1d0faSAndy Lutomirski static void clearhandler(int sig)
390eb1d0faSAndy Lutomirski {
400eb1d0faSAndy Lutomirski struct sigaction sa;
410eb1d0faSAndy Lutomirski memset(&sa, 0, sizeof(sa));
420eb1d0faSAndy Lutomirski sa.sa_handler = SIG_DFL;
430eb1d0faSAndy Lutomirski sigemptyset(&sa.sa_mask);
440eb1d0faSAndy Lutomirski if (sigaction(sig, &sa, 0))
450eb1d0faSAndy Lutomirski err(1, "sigaction");
460eb1d0faSAndy Lutomirski }
470eb1d0faSAndy Lutomirski
480eb1d0faSAndy Lutomirski static jmp_buf jmpbuf;
490eb1d0faSAndy Lutomirski
sigsegv(int sig,siginfo_t * si,void * ctx_void)500eb1d0faSAndy Lutomirski static void sigsegv(int sig, siginfo_t *si, void *ctx_void)
510eb1d0faSAndy Lutomirski {
520eb1d0faSAndy Lutomirski siglongjmp(jmpbuf, 1);
530eb1d0faSAndy Lutomirski }
540eb1d0faSAndy Lutomirski
try_outb(unsigned short port)550eb1d0faSAndy Lutomirski static bool try_outb(unsigned short port)
560eb1d0faSAndy Lutomirski {
570eb1d0faSAndy Lutomirski sethandler(SIGSEGV, sigsegv, SA_RESETHAND);
580eb1d0faSAndy Lutomirski if (sigsetjmp(jmpbuf, 1) != 0) {
590eb1d0faSAndy Lutomirski return false;
600eb1d0faSAndy Lutomirski } else {
610eb1d0faSAndy Lutomirski asm volatile ("outb %%al, %w[port]"
620eb1d0faSAndy Lutomirski : : [port] "Nd" (port), "a" (0));
630eb1d0faSAndy Lutomirski return true;
640eb1d0faSAndy Lutomirski }
650eb1d0faSAndy Lutomirski clearhandler(SIGSEGV);
660eb1d0faSAndy Lutomirski }
670eb1d0faSAndy Lutomirski
expect_ok(unsigned short port)680eb1d0faSAndy Lutomirski static void expect_ok(unsigned short port)
690eb1d0faSAndy Lutomirski {
700eb1d0faSAndy Lutomirski if (!try_outb(port)) {
710eb1d0faSAndy Lutomirski printf("[FAIL]\toutb to 0x%02hx failed\n", port);
720eb1d0faSAndy Lutomirski exit(1);
730eb1d0faSAndy Lutomirski }
740eb1d0faSAndy Lutomirski
750eb1d0faSAndy Lutomirski printf("[OK]\toutb to 0x%02hx worked\n", port);
760eb1d0faSAndy Lutomirski }
770eb1d0faSAndy Lutomirski
expect_gp(unsigned short port)780eb1d0faSAndy Lutomirski static void expect_gp(unsigned short port)
790eb1d0faSAndy Lutomirski {
800eb1d0faSAndy Lutomirski if (try_outb(port)) {
810eb1d0faSAndy Lutomirski printf("[FAIL]\toutb to 0x%02hx worked\n", port);
820eb1d0faSAndy Lutomirski exit(1);
830eb1d0faSAndy Lutomirski }
840eb1d0faSAndy Lutomirski
850eb1d0faSAndy Lutomirski printf("[OK]\toutb to 0x%02hx failed\n", port);
860eb1d0faSAndy Lutomirski }
870eb1d0faSAndy Lutomirski
main(void)880eb1d0faSAndy Lutomirski int main(void)
890eb1d0faSAndy Lutomirski {
900eb1d0faSAndy Lutomirski cpu_set_t cpuset;
910eb1d0faSAndy Lutomirski CPU_ZERO(&cpuset);
920eb1d0faSAndy Lutomirski CPU_SET(0, &cpuset);
930eb1d0faSAndy Lutomirski if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0)
940eb1d0faSAndy Lutomirski err(1, "sched_setaffinity to CPU 0");
950eb1d0faSAndy Lutomirski
960eb1d0faSAndy Lutomirski expect_gp(0x80);
970eb1d0faSAndy Lutomirski expect_gp(0xed);
980eb1d0faSAndy Lutomirski
990eb1d0faSAndy Lutomirski /*
1000eb1d0faSAndy Lutomirski * Probe for ioperm support. Note that clearing ioperm bits
1010eb1d0faSAndy Lutomirski * works even as nonroot.
1020eb1d0faSAndy Lutomirski */
1030eb1d0faSAndy Lutomirski printf("[RUN]\tenable 0x80\n");
1040eb1d0faSAndy Lutomirski if (ioperm(0x80, 1, 1) != 0) {
1050eb1d0faSAndy Lutomirski printf("[OK]\tioperm(0x80, 1, 1) failed (%d) -- try running as root\n",
1060eb1d0faSAndy Lutomirski errno);
1070eb1d0faSAndy Lutomirski return 0;
1080eb1d0faSAndy Lutomirski }
1090eb1d0faSAndy Lutomirski expect_ok(0x80);
1100eb1d0faSAndy Lutomirski expect_gp(0xed);
1110eb1d0faSAndy Lutomirski
1120eb1d0faSAndy Lutomirski printf("[RUN]\tdisable 0x80\n");
1130eb1d0faSAndy Lutomirski if (ioperm(0x80, 1, 0) != 0) {
1140eb1d0faSAndy Lutomirski printf("[FAIL]\tioperm(0x80, 1, 0) failed (%d)", errno);
1150eb1d0faSAndy Lutomirski return 1;
1160eb1d0faSAndy Lutomirski }
1170eb1d0faSAndy Lutomirski expect_gp(0x80);
1180eb1d0faSAndy Lutomirski expect_gp(0xed);
1190eb1d0faSAndy Lutomirski
1200eb1d0faSAndy Lutomirski /* Make sure that fork() preserves ioperm. */
1210eb1d0faSAndy Lutomirski if (ioperm(0x80, 1, 1) != 0) {
1220eb1d0faSAndy Lutomirski printf("[FAIL]\tioperm(0x80, 1, 0) failed (%d)", errno);
1230eb1d0faSAndy Lutomirski return 1;
1240eb1d0faSAndy Lutomirski }
1250eb1d0faSAndy Lutomirski
1260eb1d0faSAndy Lutomirski pid_t child = fork();
1270eb1d0faSAndy Lutomirski if (child == -1)
1280eb1d0faSAndy Lutomirski err(1, "fork");
1290eb1d0faSAndy Lutomirski
1300eb1d0faSAndy Lutomirski if (child == 0) {
1310eb1d0faSAndy Lutomirski printf("[RUN]\tchild: check that we inherited permissions\n");
1320eb1d0faSAndy Lutomirski expect_ok(0x80);
1330eb1d0faSAndy Lutomirski expect_gp(0xed);
1340907a09cSThomas Gleixner printf("[RUN]\tchild: Extend permissions to 0x81\n");
1350907a09cSThomas Gleixner if (ioperm(0x81, 1, 1) != 0) {
1360907a09cSThomas Gleixner printf("[FAIL]\tioperm(0x81, 1, 1) failed (%d)", errno);
1370907a09cSThomas Gleixner return 1;
1380907a09cSThomas Gleixner }
1390907a09cSThomas Gleixner printf("[RUN]\tchild: Drop permissions to 0x80\n");
1400907a09cSThomas Gleixner if (ioperm(0x80, 1, 0) != 0) {
1410907a09cSThomas Gleixner printf("[FAIL]\tioperm(0x80, 1, 0) failed (%d)", errno);
1420907a09cSThomas Gleixner return 1;
1430907a09cSThomas Gleixner }
1440907a09cSThomas Gleixner expect_gp(0x80);
1450eb1d0faSAndy Lutomirski return 0;
1460eb1d0faSAndy Lutomirski } else {
1470eb1d0faSAndy Lutomirski int status;
1480eb1d0faSAndy Lutomirski if (waitpid(child, &status, 0) != child ||
1490eb1d0faSAndy Lutomirski !WIFEXITED(status)) {
1500eb1d0faSAndy Lutomirski printf("[FAIL]\tChild died\n");
1510eb1d0faSAndy Lutomirski nerrs++;
1520eb1d0faSAndy Lutomirski } else if (WEXITSTATUS(status) != 0) {
1530eb1d0faSAndy Lutomirski printf("[FAIL]\tChild failed\n");
1540eb1d0faSAndy Lutomirski nerrs++;
1550eb1d0faSAndy Lutomirski } else {
1560eb1d0faSAndy Lutomirski printf("[OK]\tChild succeeded\n");
1570eb1d0faSAndy Lutomirski }
1580eb1d0faSAndy Lutomirski }
1590eb1d0faSAndy Lutomirski
1600907a09cSThomas Gleixner /* Verify that the child dropping 0x80 did not affect the parent */
1610907a09cSThomas Gleixner printf("\tVerify that unsharing the bitmap worked\n");
1620907a09cSThomas Gleixner expect_ok(0x80);
1630eb1d0faSAndy Lutomirski
1640907a09cSThomas Gleixner /* Test the capability checks. */
1650eb1d0faSAndy Lutomirski printf("\tDrop privileges\n");
1660eb1d0faSAndy Lutomirski if (setresuid(1, 1, 1) != 0) {
1670eb1d0faSAndy Lutomirski printf("[WARN]\tDropping privileges failed\n");
1680eb1d0faSAndy Lutomirski return 0;
1690eb1d0faSAndy Lutomirski }
1700eb1d0faSAndy Lutomirski
1710eb1d0faSAndy Lutomirski printf("[RUN]\tdisable 0x80\n");
1720eb1d0faSAndy Lutomirski if (ioperm(0x80, 1, 0) != 0) {
1730eb1d0faSAndy Lutomirski printf("[FAIL]\tioperm(0x80, 1, 0) failed (%d)", errno);
1740eb1d0faSAndy Lutomirski return 1;
1750eb1d0faSAndy Lutomirski }
1760eb1d0faSAndy Lutomirski printf("[OK]\tit worked\n");
1770eb1d0faSAndy Lutomirski
1780eb1d0faSAndy Lutomirski printf("[RUN]\tenable 0x80 again\n");
1790eb1d0faSAndy Lutomirski if (ioperm(0x80, 1, 1) == 0) {
1800eb1d0faSAndy Lutomirski printf("[FAIL]\tit succeeded but should have failed.\n");
1810eb1d0faSAndy Lutomirski return 1;
1820eb1d0faSAndy Lutomirski }
1830eb1d0faSAndy Lutomirski printf("[OK]\tit failed\n");
1840eb1d0faSAndy Lutomirski return 0;
1850eb1d0faSAndy Lutomirski }
186