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