xref: /freebsd/tools/regression/priv/priv_sched_rtprio.c (revision 9fa5f6b4b9580e7fd6829e3f4a267499d0ad3af1)
19fa5f6b4SRobert Watson /*-
29fa5f6b4SRobert Watson  * Copyright (c) 2006 nCircle Network Security, Inc.
39fa5f6b4SRobert Watson  * All rights reserved.
49fa5f6b4SRobert Watson  *
59fa5f6b4SRobert Watson  * This software was developed by Robert N. M. Watson for the TrustedBSD
69fa5f6b4SRobert Watson  * Project under contract to nCircle Network Security, Inc.
79fa5f6b4SRobert Watson  *
89fa5f6b4SRobert Watson  * Redistribution and use in source and binary forms, with or without
99fa5f6b4SRobert Watson  * modification, are permitted provided that the following conditions
109fa5f6b4SRobert Watson  * are met:
119fa5f6b4SRobert Watson  * 1. Redistributions of source code must retain the above copyright
129fa5f6b4SRobert Watson  *    notice, this list of conditions and the following disclaimer.
139fa5f6b4SRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
149fa5f6b4SRobert Watson  *    notice, this list of conditions and the following disclaimer in the
159fa5f6b4SRobert Watson  *    documentation and/or other materials provided with the distribution.
169fa5f6b4SRobert Watson  *
179fa5f6b4SRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
189fa5f6b4SRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
199fa5f6b4SRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
209fa5f6b4SRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY,
219fa5f6b4SRobert Watson  * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
229fa5f6b4SRobert Watson  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
239fa5f6b4SRobert Watson  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
249fa5f6b4SRobert Watson  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
259fa5f6b4SRobert Watson  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
269fa5f6b4SRobert Watson  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
279fa5f6b4SRobert Watson  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
289fa5f6b4SRobert Watson  *
299fa5f6b4SRobert Watson  * $FreeBSD$
309fa5f6b4SRobert Watson  */
319fa5f6b4SRobert Watson 
329fa5f6b4SRobert Watson /*
339fa5f6b4SRobert Watson  * Test privilege associated with real time process settings.  There are
349fa5f6b4SRobert Watson  * three relevant notions of privilege:
359fa5f6b4SRobert Watson  *
369fa5f6b4SRobert Watson  * - Privilege to set the real-time priority of the current process.
379fa5f6b4SRobert Watson  * - Privilege to set the real-time priority of another process.
389fa5f6b4SRobert Watson  * - Privilege to set the idle priority of another process.
399fa5f6b4SRobert Watson  * - No privilege to set the idle priority of the current process.
409fa5f6b4SRobert Watson  *
419fa5f6b4SRobert Watson  * This requires a test process and a target (dummy) process running with
429fa5f6b4SRobert Watson  * various uids.  This test is based on the code in the setpriority() test.
439fa5f6b4SRobert Watson  */
449fa5f6b4SRobert Watson 
459fa5f6b4SRobert Watson #include <sys/types.h>
469fa5f6b4SRobert Watson #include <sys/rtprio.h>
479fa5f6b4SRobert Watson #include <sys/wait.h>
489fa5f6b4SRobert Watson 
499fa5f6b4SRobert Watson #include <err.h>
509fa5f6b4SRobert Watson #include <errno.h>
519fa5f6b4SRobert Watson #include <signal.h>
529fa5f6b4SRobert Watson #include <stdlib.h>
539fa5f6b4SRobert Watson #include <unistd.h>
549fa5f6b4SRobert Watson 
559fa5f6b4SRobert Watson #include "main.h"
569fa5f6b4SRobert Watson 
579fa5f6b4SRobert Watson static void
589fa5f6b4SRobert Watson dummy(void)
599fa5f6b4SRobert Watson {
609fa5f6b4SRobert Watson 
619fa5f6b4SRobert Watson 	while (1)
629fa5f6b4SRobert Watson 		sleep(1);
639fa5f6b4SRobert Watson }
649fa5f6b4SRobert Watson 
659fa5f6b4SRobert Watson static void
669fa5f6b4SRobert Watson collect(pid_t test_pid, pid_t dummy_pid)
679fa5f6b4SRobert Watson {
689fa5f6b4SRobert Watson 	pid_t pid;
699fa5f6b4SRobert Watson 
709fa5f6b4SRobert Watson 	/*
719fa5f6b4SRobert Watson 	 * First, collect the main test process.  When it has exited, then
729fa5f6b4SRobert Watson 	 * kill off the dummy process.
739fa5f6b4SRobert Watson 	 */
749fa5f6b4SRobert Watson 	if (test_pid > 0) {
759fa5f6b4SRobert Watson 		while (1) {
769fa5f6b4SRobert Watson 			pid = waitpid(test_pid, NULL, 0);
779fa5f6b4SRobert Watson 			if (pid == -1)
789fa5f6b4SRobert Watson 				warn("waitpid(%d (test), NULL, 0)", test_pid);
799fa5f6b4SRobert Watson 			if (pid == test_pid)
809fa5f6b4SRobert Watson 				break;
819fa5f6b4SRobert Watson 		}
829fa5f6b4SRobert Watson 	}
839fa5f6b4SRobert Watson 
849fa5f6b4SRobert Watson 	if (kill(dummy_pid, SIGKILL) < 0)
859fa5f6b4SRobert Watson 		err(-1, "kill(%d, SIGKILL)", dummy_pid);
869fa5f6b4SRobert Watson 
879fa5f6b4SRobert Watson 	while (1) {
889fa5f6b4SRobert Watson 		pid = waitpid(dummy_pid, NULL, 0);
899fa5f6b4SRobert Watson 		if (pid == -1)
909fa5f6b4SRobert Watson 			warn("waitpid(%d, NULL, 0)", dummy_pid);
919fa5f6b4SRobert Watson 		if (pid == dummy_pid)
929fa5f6b4SRobert Watson 			return;
939fa5f6b4SRobert Watson 	}
949fa5f6b4SRobert Watson }
959fa5f6b4SRobert Watson 
969fa5f6b4SRobert Watson static void
979fa5f6b4SRobert Watson test(pid_t dummy_pid)
989fa5f6b4SRobert Watson {
999fa5f6b4SRobert Watson 	struct rtprio rtp;
1009fa5f6b4SRobert Watson 	int error;
1019fa5f6b4SRobert Watson 
1029fa5f6b4SRobert Watson 	/*
1039fa5f6b4SRobert Watson 	 * Tests first as root.  Test that we can set normal, realtime, and
1049fa5f6b4SRobert Watson 	 * idle priorities on the current thread and on the dummy thread.
1059fa5f6b4SRobert Watson 	 */
1069fa5f6b4SRobert Watson 	rtp.type = RTP_PRIO_REALTIME;
1079fa5f6b4SRobert Watson 	rtp.prio = 0;
1089fa5f6b4SRobert Watson 	if (rtprio(RTP_SET, 0, &rtp) < 0)
1099fa5f6b4SRobert Watson 		err(-1, "rtprio(RTP_SET, 0, {REALTIME, 0}) as root");
1109fa5f6b4SRobert Watson 
1119fa5f6b4SRobert Watson 	rtp.type = RTP_PRIO_IDLE;
1129fa5f6b4SRobert Watson 	rtp.prio = 0;
1139fa5f6b4SRobert Watson 	if (rtprio(RTP_SET, 0, &rtp) < 0)
1149fa5f6b4SRobert Watson 		err(-1, "rtprio(RTP_SET, 0, {IDLE, 0}) as root");
1159fa5f6b4SRobert Watson 
1169fa5f6b4SRobert Watson 	rtp.type = RTP_PRIO_NORMAL;
1179fa5f6b4SRobert Watson 	rtp.prio = 0;
1189fa5f6b4SRobert Watson 	if (rtprio(RTP_SET, 0, &rtp) < 0)
1199fa5f6b4SRobert Watson 		err(-1, "rtprio(RTP_SET, 0, {NORMAL, 0) as root");
1209fa5f6b4SRobert Watson 
1219fa5f6b4SRobert Watson 	rtp.type = RTP_PRIO_REALTIME;
1229fa5f6b4SRobert Watson 	rtp.prio = 0;
1239fa5f6b4SRobert Watson 	if (rtprio(RTP_SET, dummy_pid, &rtp) < 0)
1249fa5f6b4SRobert Watson 		err(-1, "rtprio(RTP_SET, %d, {REALTIME, 0}) as root",
1259fa5f6b4SRobert Watson 		    dummy_pid);
1269fa5f6b4SRobert Watson 
1279fa5f6b4SRobert Watson 	rtp.type = RTP_PRIO_IDLE;
1289fa5f6b4SRobert Watson 	rtp.prio = 0;
1299fa5f6b4SRobert Watson 	if (rtprio(RTP_SET, dummy_pid, &rtp) < 0)
1309fa5f6b4SRobert Watson 		err(-1, "rtprio(RTP_SET, %d, {IDLE, 0}) as root", dummy_pid);
1319fa5f6b4SRobert Watson 
1329fa5f6b4SRobert Watson 	rtp.type = RTP_PRIO_NORMAL;
1339fa5f6b4SRobert Watson 	rtp.prio = 0;
1349fa5f6b4SRobert Watson 	if (rtprio(RTP_SET, dummy_pid, &rtp) < 0)
1359fa5f6b4SRobert Watson 		err(-1, "rtprio(RTP_SET, %d, {NORMAL, 0) as root",
1369fa5f6b4SRobert Watson 		    dummy_pid);
1379fa5f6b4SRobert Watson 
1389fa5f6b4SRobert Watson 	/*
1399fa5f6b4SRobert Watson 	 * Then test again as a different credential.
1409fa5f6b4SRobert Watson 	 */
1419fa5f6b4SRobert Watson 	if (setresuid(UID_OTHER, UID_OTHER, UID_OTHER) < 0)
1429fa5f6b4SRobert Watson 		err(-1, "setresuid(%d)", UID_OTHER);
1439fa5f6b4SRobert Watson 
1449fa5f6b4SRobert Watson 	rtp.type = RTP_PRIO_REALTIME;
1459fa5f6b4SRobert Watson 	rtp.prio = 0;
1469fa5f6b4SRobert Watson 	error = rtprio(RTP_SET, 0, &rtp);
1479fa5f6b4SRobert Watson 	if (error == 0)
1489fa5f6b4SRobert Watson 		errx(-1,
1499fa5f6b4SRobert Watson 		    "rtprio(RTP_SET, 0, {REALTIME, 0}) succeeded as !root");
1509fa5f6b4SRobert Watson 	if (errno != EPERM)
1519fa5f6b4SRobert Watson 		err(-1, "rtprio(RTP_SET, 0, {REALTIME, 0}) wrong errno %d as"
1529fa5f6b4SRobert Watson 		    " !root", errno);
1539fa5f6b4SRobert Watson 
1549fa5f6b4SRobert Watson 	rtp.type = RTP_PRIO_IDLE;
1559fa5f6b4SRobert Watson 	rtp.prio = 0;
1569fa5f6b4SRobert Watson 	error = rtprio(RTP_SET, 0, &rtp);
1579fa5f6b4SRobert Watson 	if (error == 0)
1589fa5f6b4SRobert Watson 		errx(-1, "rtprio(RTP_SET, 0, {IDLE, 0}) succeeded as !root");
1599fa5f6b4SRobert Watson 	if (errno != EPERM)
1609fa5f6b4SRobert Watson 		err(-1, "rtprio(RTP_SET, 0, {IDLE, 0}) wrong errno %d as "
1619fa5f6b4SRobert Watson 		    "!root", errno);
1629fa5f6b4SRobert Watson 
1639fa5f6b4SRobert Watson 	rtp.type = RTP_PRIO_NORMAL;
1649fa5f6b4SRobert Watson 	rtp.prio = 0;
1659fa5f6b4SRobert Watson 	if (rtprio(RTP_SET, 0, &rtp) < 0)
1669fa5f6b4SRobert Watson 		err(-1, "rtprio(RTP_SET, 0, {NORMAL, 0}) as !root");
1679fa5f6b4SRobert Watson 
1689fa5f6b4SRobert Watson 	rtp.type = RTP_PRIO_REALTIME;
1699fa5f6b4SRobert Watson 	rtp.prio = 0;
1709fa5f6b4SRobert Watson 	error = rtprio(RTP_SET, dummy_pid, &rtp);
1719fa5f6b4SRobert Watson 	if (error == 0)
1729fa5f6b4SRobert Watson 		errx(-1,
1739fa5f6b4SRobert Watson 		    "rtprio(RTP_SET, %d, {REALTIME, 0}) succeeded as !root",
1749fa5f6b4SRobert Watson 		    dummy_pid);
1759fa5f6b4SRobert Watson 	if (errno != EPERM)
1769fa5f6b4SRobert Watson 		err(-1, "rtprio(RTP_SET, %d, {REALTIME, 0}) wrong errno %d as"
1779fa5f6b4SRobert Watson 		    " !root", dummy_pid, errno);
1789fa5f6b4SRobert Watson 
1799fa5f6b4SRobert Watson 	rtp.type = RTP_PRIO_IDLE;
1809fa5f6b4SRobert Watson 	rtp.prio = 0;
1819fa5f6b4SRobert Watson 	error = rtprio(RTP_SET, dummy_pid, &rtp);
1829fa5f6b4SRobert Watson 	if (error == 0)
1839fa5f6b4SRobert Watson 		errx(-1, "rtprio(RTP_SET, %d, {IDLE, 0}) succeeded as !root",
1849fa5f6b4SRobert Watson 		    dummy_pid);
1859fa5f6b4SRobert Watson 	if (errno != EPERM)
1869fa5f6b4SRobert Watson 		err(-1,
1879fa5f6b4SRobert Watson 		    "rtprio(RTP_SET, %d, {IDLE, 0}) wrong errno %d as !root",
1889fa5f6b4SRobert Watson 		    dummy_pid, errno);
1899fa5f6b4SRobert Watson 
1909fa5f6b4SRobert Watson 	rtp.type = RTP_PRIO_NORMAL;
1919fa5f6b4SRobert Watson 	rtp.prio = 0;
1929fa5f6b4SRobert Watson 	error = rtprio(RTP_SET, dummy_pid, &rtp);
1939fa5f6b4SRobert Watson 	if (error == 0)
1949fa5f6b4SRobert Watson 		errx(-1,
1959fa5f6b4SRobert Watson 		    "rtprio(RTP_SET, %d, {NORMAL, 0) succeeded as !root",
1969fa5f6b4SRobert Watson 		    dummy_pid);
1979fa5f6b4SRobert Watson 	if (errno != EPERM)
1989fa5f6b4SRobert Watson 		err(-1, "rtprio(RTP_SET, %d, {NORMAL, 0}) wrong errno %d as "
1999fa5f6b4SRobert Watson 		    "!root", dummy_pid, errno);
2009fa5f6b4SRobert Watson 
2019fa5f6b4SRobert Watson 	exit(0);
2029fa5f6b4SRobert Watson }
2039fa5f6b4SRobert Watson 
2049fa5f6b4SRobert Watson void
2059fa5f6b4SRobert Watson priv_sched_rtprio(void)
2069fa5f6b4SRobert Watson {
2079fa5f6b4SRobert Watson 	pid_t dummy_pid, test_pid;
2089fa5f6b4SRobert Watson 
2099fa5f6b4SRobert Watson 	assert_root();
2109fa5f6b4SRobert Watson 
2119fa5f6b4SRobert Watson 	/*
2129fa5f6b4SRobert Watson 	 * Set up dummy process, which we will kill before exiting.
2139fa5f6b4SRobert Watson 	 */
2149fa5f6b4SRobert Watson 	dummy_pid = fork();
2159fa5f6b4SRobert Watson 	if (dummy_pid < 0)
2169fa5f6b4SRobert Watson 		err(-1, "fork - dummy");
2179fa5f6b4SRobert Watson 	if (dummy_pid == 0) {
2189fa5f6b4SRobert Watson 		if (setresuid(UID_THIRD, UID_THIRD, UID_THIRD) < 0)
2199fa5f6b4SRobert Watson 			err(-1, "setresuid(%d)", UID_THIRD);
2209fa5f6b4SRobert Watson 		dummy();
2219fa5f6b4SRobert Watson 	}
2229fa5f6b4SRobert Watson 	sleep(1);	/* Allow dummy thread to change uids. */
2239fa5f6b4SRobert Watson 
2249fa5f6b4SRobert Watson 	test_pid = fork();
2259fa5f6b4SRobert Watson 	if (test_pid < 0) {
2269fa5f6b4SRobert Watson 		warn("fork - test");
2279fa5f6b4SRobert Watson 		collect(-1, dummy_pid);
2289fa5f6b4SRobert Watson 		return;
2299fa5f6b4SRobert Watson 	}
2309fa5f6b4SRobert Watson 	if (test_pid == 0)
2319fa5f6b4SRobert Watson 		test(dummy_pid);
2329fa5f6b4SRobert Watson 
2339fa5f6b4SRobert Watson 	collect(test_pid, dummy_pid);
2349fa5f6b4SRobert Watson }
235