1/*-
2 * Copyright (c) 2006 nCircle Network Security, Inc.
3 * Copyright (c) 2007 Robert N. M. Watson
4 * All rights reserved.
5 *
6 * This software was developed by Robert N. M. Watson for the TrustedBSD
7 * Project under contract to nCircle Network Security, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY,
22 * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/*
32 * Test privilege associated with real time process settings.  There are
33 * three relevant notions of privilege:
34 *
35 * - Privilege to set the real-time priority of the current process.
36 * - Privilege to set the real-time priority of another process.
37 * - Privilege to set the idle priority of another process.
38 * - No privilege to set the idle priority of the current process.
39 *
40 * This requires a test process and a target (dummy) process running with
41 * various uids.  This test is based on the code in the setpriority() test.
42 */
43
44#include <sys/types.h>
45#include <sys/rtprio.h>
46#include <sys/wait.h>
47
48#include <err.h>
49#include <errno.h>
50#include <signal.h>
51#include <stdlib.h>
52#include <unistd.h>
53
54#include "main.h"
55
56static int	childproc_running;
57static pid_t	childproc;
58
59int
60priv_sched_rtprio_setup(int asroot, int injail, struct test *test)
61{
62	int another_uid, need_child;
63
64	/*
65	 * Some tests require a second process with specific credentials.
66	 * Set that up here, and kill in cleanup.
67	 */
68	need_child = 0;
69	if (test->t_test_func == priv_sched_rtprio_aproc_normal ||
70	    test->t_test_func == priv_sched_rtprio_aproc_idle ||
71	    test->t_test_func == priv_sched_rtprio_aproc_realtime) {
72		need_child = 1;
73		another_uid = 1;
74	}
75	if (test->t_test_func == priv_sched_rtprio_myproc_normal ||
76	    test->t_test_func == priv_sched_rtprio_myproc_idle ||
77	    test->t_test_func == priv_sched_rtprio_myproc_realtime) {
78		need_child = 1;
79	}
80
81	if (need_child) {
82		childproc = fork();
83		if (childproc < 0) {
84			warn("priv_sched_setup: fork");
85			return (-1);
86		}
87		if (childproc == 0) {
88			if (another_uid) {
89				if (setresuid(UID_THIRD, UID_THIRD,
90				    UID_THIRD) < 0)
91				err(-1, "setresuid(%d)", UID_THIRD);
92			}
93			while (1)
94				sleep(1);
95		}
96		childproc_running = 1;
97		sleep(1);	/* Allow dummy thread to change uids. */
98	}
99	return (0);
100}
101
102void
103priv_sched_rtprio_curproc_normal(int asroot, int injail, struct test *test)
104{
105	struct rtprio rtp;
106	int error;
107
108	rtp.type = RTP_PRIO_NORMAL;
109	rtp.prio = 0;
110	error = rtprio(RTP_SET, 0, &rtp);
111	if (asroot && injail)
112		expect("priv_sched_rtprio_curproc_normal(asroot, injail)",
113		    error, 0, 0);
114	if (asroot && !injail)
115		expect("priv_sched_rtprio_curproc_normal(asroot, !injail)",
116		    error, 0, 0);
117	if (!asroot && injail)
118		expect("priv_sched_rtprio_curproc_normal(!asroot, injail)",
119		    error, 0, 0);
120	if (!asroot && !injail)
121		expect("priv_sched_rtprio_curproc_normal(!asroot, !injail)",
122		    error, 0, 0);
123}
124
125void
126priv_sched_rtprio_curproc_idle(int asroot, int injail, struct test *test)
127{
128	struct rtprio rtp;
129	int error;
130
131	rtp.type = RTP_PRIO_IDLE;
132	rtp.prio = 0;
133	error = rtprio(RTP_SET, 0, &rtp);
134	if (asroot && injail)
135		expect("priv_sched_rtprio_curproc_idle(asroot, injail)",
136		    error, -1, EPERM);
137	if (asroot && !injail)
138		expect("priv_sched_rtprio_curproc_idle(asroot, !injail)",
139		    error, 0, 0);
140	if (!asroot && injail)
141		expect("priv_sched_rtprio_curproc_idle(!asroot, injail)",
142		    error, -1, EPERM);
143	if (!asroot && !injail)
144		expect("priv_sched_rtprio_curproc_idle(!asroot, !injail)",
145		    error, -1, EPERM);
146}
147
148void
149priv_sched_rtprio_curproc_realtime(int asroot, int injail, struct test *test)
150{
151	struct rtprio rtp;
152	int error;
153
154	rtp.type = RTP_PRIO_REALTIME;
155	rtp.prio = 0;
156	error = rtprio(RTP_SET, 0, &rtp);
157	if (asroot && injail)
158		expect("priv_sched_rtprio_curproc_realtime(asroot, injail)",
159		    error, -1, EPERM);
160	if (asroot && !injail)
161		expect("priv_sched_rtprio_curproc_realtime(asroot, !injail)",
162		    error, 0, 0);
163	if (!asroot && injail)
164		expect("priv_sched_rtprio_curproc_realtime(!asroot, injail)",
165		    error, -1, EPERM);
166	if (!asroot && !injail)
167		expect("priv_sched_rtprio_curproc_realtime(!asroot, !injail)",
168		    error, -1, EPERM);
169}
170
171void
172priv_sched_rtprio_myproc_normal(int asroot, int injail, struct test *test)
173{
174	struct rtprio rtp;
175	int error;
176
177	rtp.type = RTP_PRIO_NORMAL;
178	rtp.prio = 0;
179	error = rtprio(RTP_SET, 0, &rtp);
180	if (asroot && injail)
181		expect("priv_sched_rtprio_myproc_normal(asroot, injail)",
182		    error, 0, 0);
183	if (asroot && !injail)
184		expect("priv_sched_rtprio_myproc_normal(asroot, !injail)",
185		    error, 0, 0);
186	if (!asroot && injail)
187		expect("priv_sched_rtprio_myproc_normal(!asroot, injail)",
188		    error, 0, 0);
189	if (!asroot && !injail)
190		expect("priv_sched_rtprio_myproc_normal(!asroot, !injail)",
191		    error, 0, 0);
192}
193
194void
195priv_sched_rtprio_myproc_idle(int asroot, int injail, struct test *test)
196{
197	struct rtprio rtp;
198	int error;
199
200	rtp.type = RTP_PRIO_IDLE;
201	rtp.prio = 0;
202	error = rtprio(RTP_SET, 0, &rtp);
203	if (asroot && injail)
204		expect("priv_sched_rtprio_myproc_idle(asroot, injail)",
205		    error, -1, EPERM);
206	if (asroot && !injail)
207		expect("priv_sched_rtprio_myproc_idle(asroot, !injail)",
208		    error, 0, 0);
209	if (!asroot && injail)
210		expect("priv_sched_rtprio_myproc_idle(!asroot, injail)",
211		    error, -1, EPERM);
212	if (!asroot && !injail)
213		expect("priv_sched_rtprio_myproc_idle(!asroot, !injail)",
214		    error, -1, EPERM);
215}
216
217void
218priv_sched_rtprio_myproc_realtime(int asroot, int injail, struct test *test)
219{
220	struct rtprio rtp;
221	int error;
222
223	rtp.type = RTP_PRIO_REALTIME;
224	rtp.prio = 0;
225	error = rtprio(RTP_SET, 0, &rtp);
226	if (asroot && injail)
227		expect("priv_sched_rtprio_myproc_realtime(asroot, injail)",
228		    error, -1, EPERM);
229	if (asroot && !injail)
230		expect("priv_sched_rtprio_myproc_realtime(asroot, !injail)",
231		    error, 0, 0);
232	if (!asroot && injail)
233		expect("priv_sched_rtprio_myproc_realtime(!asroot, injail)",
234		    error, -1, EPERM);
235	if (!asroot && !injail)
236		expect("priv_sched_rtprio_myproc_realtime(!asroot, !injail)",
237		    error, -1, EPERM);
238}
239
240void
241priv_sched_rtprio_aproc_normal(int asroot, int injail, struct test *test)
242{
243	struct rtprio rtp;
244	int error;
245
246	rtp.type = RTP_PRIO_NORMAL;
247	rtp.prio = 0;
248	error = rtprio(RTP_SET, childproc, &rtp);
249	if (asroot && injail)
250		expect("priv_sched_rtprio_aproc_normal(asroot, injail)",
251		    error, -1, ESRCH);
252	if (asroot && !injail)
253		expect("priv_sched_rtprio_aproc_normal(asroot, !injail)",
254		    error, 0, 0);
255	if (!asroot && injail)
256		expect("priv_sched_rtprio_aproc_normal(!asroot, injail)",
257		    error, -1, ESRCH);
258	if (!asroot && !injail)
259		expect("priv_sched_rtprio_aproc_normal(!asroot, !injail)",
260		    error, -1, EPERM);
261}
262
263void
264priv_sched_rtprio_aproc_idle(int asroot, int injail, struct test *test)
265{
266	struct rtprio rtp;
267	int error;
268
269	rtp.type = RTP_PRIO_IDLE;
270	rtp.prio = 0;
271	error = rtprio(RTP_SET, childproc, &rtp);
272	if (asroot && injail)
273		expect("priv_sched_rtprio_aproc_idle(asroot, injail)",
274		    error, -1, ESRCH);
275	if (asroot && !injail)
276		expect("priv_sched_rtprio_aproc_idle(asroot, !injail)",
277		    error, 0, 0);
278	if (!asroot && injail)
279		expect("priv_sched_rtprio_aproc_idle(!asroot, injail)",
280		    error, -1, ESRCH);
281	if (!asroot && !injail)
282		expect("priv_sched_rtprio_aroc_idle(!asroot, !injail)",
283		    error, -1, EPERM);
284}
285
286void
287priv_sched_rtprio_aproc_realtime(int asroot, int injail, struct test *test)
288{
289	struct rtprio rtp;
290	int error;
291
292	rtp.type = RTP_PRIO_REALTIME;
293	rtp.prio = 0;
294	error = rtprio(RTP_SET, childproc, &rtp);
295	if (asroot && injail)
296		expect("priv_sched_rtprio_aproc_realtime(asroot, injail)",
297		    error, -1, ESRCH);
298	if (asroot && !injail)
299		expect("priv_sched_rtprio_aproc_realtime(asroot, !injail)",
300		    error, 0, 0);
301	if (!asroot && injail)
302		expect("priv_sched_rtprio_aproc_realtime(!asroot, injail)",
303		    error, -1, ESRCH);
304	if (!asroot && !injail)
305		expect("priv_sched_rtprio_aproc_realtime(!asroot, !injail)",
306		    error, -1, EPERM);
307}
308
309void
310priv_sched_rtprio_cleanup(int asroot, int injail, struct test *test)
311{
312	pid_t pid;
313
314	if (childproc_running) {
315		(void)kill(childproc, SIGKILL);
316		while (1) {
317			pid = waitpid(childproc, NULL, 0);
318			if (pid == -1)
319				warn("waitpid(%d (test), NULL, 0)",
320				    childproc);
321			if (pid == childproc)
322				break;
323		}
324		childproc_running = 0;
325		childproc = -1;
326	}
327}
328