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