1162271Srwatson/*-
2162271Srwatson * Copyright (c) 2006 nCircle Network Security, Inc.
3172106Srwatson * Copyright (c) 2007 Robert N. M. Watson
4162271Srwatson * All rights reserved.
5162271Srwatson *
6162271Srwatson * This software was developed by Robert N. M. Watson for the TrustedBSD
7162271Srwatson * Project under contract to nCircle Network Security, Inc.
8162271Srwatson *
9162271Srwatson * Redistribution and use in source and binary forms, with or without
10162271Srwatson * modification, are permitted provided that the following conditions
11162271Srwatson * are met:
12162271Srwatson * 1. Redistributions of source code must retain the above copyright
13162271Srwatson *    notice, this list of conditions and the following disclaimer.
14162271Srwatson * 2. Redistributions in binary form must reproduce the above copyright
15162271Srwatson *    notice, this list of conditions and the following disclaimer in the
16162271Srwatson *    documentation and/or other materials provided with the distribution.
17162271Srwatson *
18162271Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19162271Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20162271Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21162271Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY,
22162271Srwatson * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23162271Srwatson * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24162271Srwatson * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25162271Srwatson * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26162271Srwatson * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27162271Srwatson * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28162271Srwatson * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29162271Srwatson *
30162271Srwatson * $FreeBSD$
31162271Srwatson */
32162271Srwatson
33162271Srwatson/*
34162271Srwatson * Test that privilege is required to lower nice value; first test with, then
35162271Srwatson * without.  There are two failure modes associated with privilege: the right
36162271Srwatson * to renice a process with a different uid, and the right to renice to a
37162271Srwatson * lower priority.  Because both the real and effective uid are part of the
38162271Srwatson * permissions test, we have to create two children processes with different
39162271Srwatson * uids.
40162271Srwatson */
41162271Srwatson
42162271Srwatson#include <sys/types.h>
43162271Srwatson#include <sys/resource.h>
44162271Srwatson#include <sys/wait.h>
45162271Srwatson
46162271Srwatson#include <err.h>
47162271Srwatson#include <errno.h>
48162271Srwatson#include <signal.h>
49162271Srwatson#include <stdlib.h>
50162271Srwatson#include <unistd.h>
51162271Srwatson
52162271Srwatson#include "main.h"
53162271Srwatson
54172106Srwatsonstatic int	childproc_running;
55172106Srwatsonstatic pid_t	childproc;
56162271Srwatson
57172106Srwatsonint
58172106Srwatsonpriv_sched_setpriority_setup(int asroot, int injail, struct test *test)
59162271Srwatson{
60172106Srwatson	int another_uid, need_child;
61162271Srwatson
62162271Srwatson	/*
63172106Srwatson	 * Some tests require a second process with specific credentials.
64172106Srwatson	 * Set that up here, and kill in cleanup.
65162271Srwatson	 */
66172106Srwatson	need_child = 0;
67172106Srwatson	if (test->t_test_func == priv_sched_setpriority_aproc) {
68172106Srwatson		need_child = 1;
69172106Srwatson		another_uid = 1;
70162271Srwatson	}
71172106Srwatson	if (test->t_test_func == priv_sched_setpriority_myproc)
72172106Srwatson		need_child = 1;
73162271Srwatson
74172106Srwatson	if (need_child) {
75172106Srwatson		childproc = fork();
76172106Srwatson		if (childproc < 0) {
77172106Srwatson			warn("priv_sched_setup: fork");
78172106Srwatson			return (-1);
79172106Srwatson		}
80172106Srwatson		if (childproc == 0) {
81172106Srwatson			if (another_uid) {
82172106Srwatson				if (setresuid(UID_THIRD, UID_THIRD,
83172106Srwatson				    UID_THIRD) < 0)
84172106Srwatson				err(-1, "setresuid(%d)", UID_THIRD);
85172106Srwatson			}
86172106Srwatson			while (1)
87172106Srwatson				sleep(1);
88172106Srwatson		}
89172106Srwatson		childproc_running = 1;
90172106Srwatson		sleep(1);	/* Allow dummy thread to change uids. */
91162271Srwatson	}
92172106Srwatson	return (0);
93162271Srwatson}
94162271Srwatson
95172106Srwatsonvoid
96172106Srwatsonpriv_sched_setpriority_curproc(int asroot, int injail, struct test *test)
97162271Srwatson{
98162271Srwatson	int error;
99162271Srwatson
100172106Srwatson	error = setpriority(PRIO_PROCESS, 0, -1);
101172106Srwatson	if (asroot && injail)
102172106Srwatson		expect("priv_sched_setpriority_curproc(asroot, injail)",
103172106Srwatson		    error, -1, EACCES);
104172106Srwatson	if (asroot && !injail)
105172106Srwatson		expect("priv_sched_setpriority_curproc(asroot, !injail)",
106172106Srwatson		    error, 0, 0);
107172106Srwatson	if (!asroot && injail)
108172106Srwatson		expect("priv_sched_setpriority_curproc(!asroot, injail)",
109172106Srwatson		    error, -1, EACCES);
110172106Srwatson	if (!asroot && !injail)
111172106Srwatson		expect("priv_sched_setpriority_curproc(!asroot, !injail)",
112172106Srwatson		    error, -1, EACCES);
113172106Srwatson}
114162271Srwatson
115172106Srwatsonvoid
116172106Srwatsonpriv_sched_setpriority_myproc(int asroot, int injail, struct test *test)
117172106Srwatson{
118172106Srwatson	int error;
119162271Srwatson
120172106Srwatson	error = setpriority(PRIO_PROCESS, 0, -1);
121172106Srwatson	if (asroot && injail)
122172106Srwatson		expect("priv_sched_setpriority_myproc(asroot, injail)",
123172106Srwatson		    error, -1, EACCES);
124172106Srwatson	if (asroot && !injail)
125172106Srwatson		expect("priv_sched_setpriority_myproc(asroot, !injail)",
126172106Srwatson		    error, 0, 0);
127172106Srwatson	if (!asroot && injail)
128172106Srwatson		expect("priv_sched_setpriority_myproc(!asroot, injail)",
129172106Srwatson		    error, -1, EACCES);
130172106Srwatson	if (!asroot && !injail)
131172106Srwatson		expect("priv_sched_setpriority_myproc(!asroot, !injail)",
132172106Srwatson		    error, -1, EACCES);
133172106Srwatson}
134162271Srwatson
135172106Srwatsonvoid
136172106Srwatsonpriv_sched_setpriority_aproc(int asroot, int injail, struct test *test)
137172106Srwatson{
138172106Srwatson	int error;
139162271Srwatson
140172106Srwatson	error = setpriority(PRIO_PROCESS, 0, -1);
141172106Srwatson	if (asroot && injail)
142172106Srwatson		expect("priv_sched_setpriority_aproc(asroot, injail)",
143172106Srwatson		    error, -1, EACCES);
144172106Srwatson	if (asroot && !injail)
145172106Srwatson		expect("priv_sched_setpriority_aproc(asroot, !injail)",
146172106Srwatson		    error, 0, 0);
147172106Srwatson	if (!asroot && injail)
148172106Srwatson		expect("priv_sched_setpriority_aproc(!asroot, injail)",
149172106Srwatson		    error, -1, EACCES);
150172106Srwatson	if (!asroot && !injail)
151172106Srwatson		expect("priv_sched_setpriority_aproc(!asroot, !injail)",
152172106Srwatson		    error, -1, EACCES);
153162271Srwatson}
154162271Srwatson
155162271Srwatsonvoid
156172106Srwatsonpriv_sched_setpriority_cleanup(int asroot, int injail, struct test *test)
157162271Srwatson{
158172106Srwatson	pid_t pid;
159162271Srwatson
160172106Srwatson	if (childproc_running) {
161172106Srwatson		(void)kill(childproc, SIGKILL);
162172106Srwatson		while (1) {
163172106Srwatson			pid = waitpid(childproc, NULL, 0);
164172106Srwatson			if (pid == -1)
165172106Srwatson				warn("waitpid(%d (test), NULL, 0)",
166172106Srwatson				    childproc);
167172106Srwatson			if (pid == childproc)
168172106Srwatson				break;
169172106Srwatson		}
170172106Srwatson		childproc_running = 0;
171172106Srwatson		childproc = -1;
172162271Srwatson	}
173162271Srwatson}
174