xref: /netbsd/tests/lib/libc/sys/t_setrlimit.c (revision cc84348d)
1*cc84348dSrin /* $NetBSD: t_setrlimit.c,v 1.7 2020/10/13 06:58:57 rin Exp $ */
2774b9069Sjruoho 
3774b9069Sjruoho /*-
4774b9069Sjruoho  * Copyright (c) 2011 The NetBSD Foundation, Inc.
5774b9069Sjruoho  * All rights reserved.
6774b9069Sjruoho  *
7774b9069Sjruoho  * This code is derived from software contributed to The NetBSD Foundation
8774b9069Sjruoho  * by Jukka Ruohonen.
9774b9069Sjruoho  *
10774b9069Sjruoho  * Redistribution and use in source and binary forms, with or without
11774b9069Sjruoho  * modification, are permitted provided that the following conditions
12774b9069Sjruoho  * are met:
13774b9069Sjruoho  * 1. Redistributions of source code must retain the above copyright
14774b9069Sjruoho  *    notice, this list of conditions and the following disclaimer.
15774b9069Sjruoho  * 2. Redistributions in binary form must reproduce the above copyright
16774b9069Sjruoho  *    notice, this list of conditions and the following disclaimer in the
17774b9069Sjruoho  *    documentation and/or other materials provided with the distribution.
18774b9069Sjruoho  *
19774b9069Sjruoho  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20774b9069Sjruoho  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21774b9069Sjruoho  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22774b9069Sjruoho  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23774b9069Sjruoho  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24774b9069Sjruoho  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25774b9069Sjruoho  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26774b9069Sjruoho  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27774b9069Sjruoho  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28774b9069Sjruoho  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29774b9069Sjruoho  * POSSIBILITY OF SUCH DAMAGE.
30774b9069Sjruoho  */
31774b9069Sjruoho #include <sys/cdefs.h>
32*cc84348dSrin __RCSID("$NetBSD: t_setrlimit.c,v 1.7 2020/10/13 06:58:57 rin Exp $");
33774b9069Sjruoho 
34774b9069Sjruoho #include <sys/resource.h>
35774b9069Sjruoho #include <sys/mman.h>
36774b9069Sjruoho #include <sys/wait.h>
37774b9069Sjruoho 
38774b9069Sjruoho #include <atf-c.h>
39774b9069Sjruoho #include <errno.h>
40774b9069Sjruoho #include <fcntl.h>
41774b9069Sjruoho #include <limits.h>
4274a08b15Schristos #include <lwp.h>
43774b9069Sjruoho #include <signal.h>
44ada921b8Sdholland #include <stdint.h>
4574a08b15Schristos #include <stdio.h>
46774b9069Sjruoho #include <stdlib.h>
47774b9069Sjruoho #include <string.h>
4874a08b15Schristos #include <ucontext.h>
49774b9069Sjruoho #include <unistd.h>
50774b9069Sjruoho 
51774b9069Sjruoho static void		 sighandler(int);
52774b9069Sjruoho static const char	 path[] = "setrlimit";
53774b9069Sjruoho 
54774b9069Sjruoho static const int rlimit[] = {
55774b9069Sjruoho 	RLIMIT_AS,
56774b9069Sjruoho 	RLIMIT_CORE,
57774b9069Sjruoho 	RLIMIT_CPU,
58774b9069Sjruoho 	RLIMIT_DATA,
59774b9069Sjruoho 	RLIMIT_FSIZE,
60774b9069Sjruoho 	RLIMIT_MEMLOCK,
61774b9069Sjruoho 	RLIMIT_NOFILE,
62774b9069Sjruoho 	RLIMIT_NPROC,
63774b9069Sjruoho 	RLIMIT_RSS,
64774b9069Sjruoho 	RLIMIT_SBSIZE,
65774b9069Sjruoho 	RLIMIT_STACK
66774b9069Sjruoho };
67774b9069Sjruoho 
68774b9069Sjruoho ATF_TC(setrlimit_basic);
ATF_TC_HEAD(setrlimit_basic,tc)69774b9069Sjruoho ATF_TC_HEAD(setrlimit_basic, tc)
70774b9069Sjruoho {
71774b9069Sjruoho 	atf_tc_set_md_var(tc, "descr", "A basic soft limit test");
72774b9069Sjruoho }
73774b9069Sjruoho 
ATF_TC_BODY(setrlimit_basic,tc)74774b9069Sjruoho ATF_TC_BODY(setrlimit_basic, tc)
75774b9069Sjruoho {
76774b9069Sjruoho 	struct rlimit res;
77774b9069Sjruoho 	int *buf, lim;
78774b9069Sjruoho 	size_t i;
79774b9069Sjruoho 
80774b9069Sjruoho 	buf = calloc(__arraycount(rlimit), sizeof(int));
81774b9069Sjruoho 
82774b9069Sjruoho 	if (buf == NULL)
83774b9069Sjruoho 		atf_tc_fail("initialization failed");
84774b9069Sjruoho 
85774b9069Sjruoho 	for (i = lim = 0; i < __arraycount(rlimit); i++) {
86774b9069Sjruoho 
87774b9069Sjruoho 		(void)memset(&res, 0, sizeof(struct rlimit));
88774b9069Sjruoho 
89774b9069Sjruoho 		if (getrlimit(rlimit[i], &res) != 0)
90774b9069Sjruoho 			continue;
91774b9069Sjruoho 
92774b9069Sjruoho 		if (res.rlim_cur == RLIM_INFINITY || res.rlim_cur == 0)
93774b9069Sjruoho 			continue;
94774b9069Sjruoho 
95774b9069Sjruoho 		if (res.rlim_cur == res.rlim_max) /* An unprivileged run. */
96774b9069Sjruoho 			continue;
97774b9069Sjruoho 
98774b9069Sjruoho 		buf[i] = res.rlim_cur;
99774b9069Sjruoho 		res.rlim_cur = res.rlim_cur - 1;
100774b9069Sjruoho 
101774b9069Sjruoho 		if (setrlimit(rlimit[i], &res) != 0) {
102774b9069Sjruoho 			lim = rlimit[i];
103774b9069Sjruoho 			goto out;
104774b9069Sjruoho 		}
105774b9069Sjruoho 	}
106774b9069Sjruoho 
107774b9069Sjruoho out:
108774b9069Sjruoho 	for (i = 0; i < __arraycount(rlimit); i++) {
109774b9069Sjruoho 
110774b9069Sjruoho 		(void)memset(&res, 0, sizeof(struct rlimit));
111774b9069Sjruoho 
112774b9069Sjruoho 		if (buf[i] == 0)
113774b9069Sjruoho 			continue;
114774b9069Sjruoho 
115774b9069Sjruoho 		if (getrlimit(rlimit[i], &res) != 0)
116774b9069Sjruoho 			continue;
117774b9069Sjruoho 
118774b9069Sjruoho 		res.rlim_cur = buf[i];
119774b9069Sjruoho 
120774b9069Sjruoho 		(void)setrlimit(rlimit[i], &res);
121774b9069Sjruoho 	}
122774b9069Sjruoho 
123774b9069Sjruoho 	if (lim != 0)
124774b9069Sjruoho 		atf_tc_fail("failed to set limit (%d)", lim);
1255ab7387aSchristos 	free(buf);
126774b9069Sjruoho }
127774b9069Sjruoho 
128774b9069Sjruoho ATF_TC(setrlimit_current);
ATF_TC_HEAD(setrlimit_current,tc)129774b9069Sjruoho ATF_TC_HEAD(setrlimit_current, tc)
130774b9069Sjruoho {
131774b9069Sjruoho 	atf_tc_set_md_var(tc, "descr", "setrlimit(3) with current limits");
132774b9069Sjruoho }
133774b9069Sjruoho 
ATF_TC_BODY(setrlimit_current,tc)134774b9069Sjruoho ATF_TC_BODY(setrlimit_current, tc)
135774b9069Sjruoho {
136774b9069Sjruoho 	struct rlimit res;
137774b9069Sjruoho 	size_t i;
138774b9069Sjruoho 
139774b9069Sjruoho 	for (i = 0; i < __arraycount(rlimit); i++) {
140774b9069Sjruoho 
141774b9069Sjruoho 		(void)memset(&res, 0, sizeof(struct rlimit));
142774b9069Sjruoho 
143774b9069Sjruoho 		ATF_REQUIRE(getrlimit(rlimit[i], &res) == 0);
144774b9069Sjruoho 		ATF_REQUIRE(setrlimit(rlimit[i], &res) == 0);
145774b9069Sjruoho 	}
146774b9069Sjruoho }
147774b9069Sjruoho 
148774b9069Sjruoho ATF_TC(setrlimit_err);
ATF_TC_HEAD(setrlimit_err,tc)149774b9069Sjruoho ATF_TC_HEAD(setrlimit_err, tc)
150774b9069Sjruoho {
151774b9069Sjruoho 	atf_tc_set_md_var(tc, "descr", "Test error conditions");
152774b9069Sjruoho }
153774b9069Sjruoho 
ATF_TC_BODY(setrlimit_err,tc)154774b9069Sjruoho ATF_TC_BODY(setrlimit_err, tc)
155774b9069Sjruoho {
156774b9069Sjruoho 	struct rlimit res;
157774b9069Sjruoho 	size_t i;
158774b9069Sjruoho 
159774b9069Sjruoho 	for (i = 0; i < __arraycount(rlimit); i++) {
160774b9069Sjruoho 
161774b9069Sjruoho 		errno = 0;
162774b9069Sjruoho 
163774b9069Sjruoho 		ATF_REQUIRE(getrlimit(rlimit[i], (void *)0) != 0);
164774b9069Sjruoho 		ATF_REQUIRE(errno == EFAULT);
165774b9069Sjruoho 	}
166774b9069Sjruoho 
167774b9069Sjruoho 	errno = 0;
168774b9069Sjruoho 
169774b9069Sjruoho 	ATF_REQUIRE(getrlimit(INT_MAX, &res) != 0);
170774b9069Sjruoho 	ATF_REQUIRE(errno == EINVAL);
171774b9069Sjruoho }
172774b9069Sjruoho 
173774b9069Sjruoho ATF_TC_WITH_CLEANUP(setrlimit_fsize);
ATF_TC_HEAD(setrlimit_fsize,tc)174774b9069Sjruoho ATF_TC_HEAD(setrlimit_fsize, tc)
175774b9069Sjruoho {
176774b9069Sjruoho 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_FSIZE");
177774b9069Sjruoho }
178774b9069Sjruoho 
ATF_TC_BODY(setrlimit_fsize,tc)179774b9069Sjruoho ATF_TC_BODY(setrlimit_fsize, tc)
180774b9069Sjruoho {
181774b9069Sjruoho 	struct rlimit res;
182774b9069Sjruoho 	int fd, sta;
183774b9069Sjruoho 	pid_t pid;
184774b9069Sjruoho 
185774b9069Sjruoho 	fd = open(path, O_RDWR | O_CREAT, 0700);
186774b9069Sjruoho 
187774b9069Sjruoho 	if (fd < 0)
188774b9069Sjruoho 		atf_tc_fail("initialization failed");
189774b9069Sjruoho 
190774b9069Sjruoho 	pid = fork();
191774b9069Sjruoho 	ATF_REQUIRE(pid >= 0);
192774b9069Sjruoho 
193774b9069Sjruoho 	if (pid == 0) {
194774b9069Sjruoho 
195774b9069Sjruoho 		res.rlim_cur = 2;
196774b9069Sjruoho 		res.rlim_max = 2;
197774b9069Sjruoho 
198774b9069Sjruoho 		if (setrlimit(RLIMIT_FSIZE, &res) != 0)
199774b9069Sjruoho 			_exit(EXIT_FAILURE);
200774b9069Sjruoho 
201774b9069Sjruoho 		if (signal(SIGXFSZ, sighandler) == SIG_ERR)
202774b9069Sjruoho 			_exit(EXIT_FAILURE);
203774b9069Sjruoho 
204774b9069Sjruoho 		/*
205774b9069Sjruoho 		 * The third call should generate a SIGXFSZ.
206774b9069Sjruoho 		 */
207774b9069Sjruoho 		(void)write(fd, "X", 1);
208774b9069Sjruoho 		(void)write(fd, "X", 1);
209774b9069Sjruoho 		(void)write(fd, "X", 1);
210774b9069Sjruoho 
211774b9069Sjruoho 		_exit(EXIT_FAILURE);
212774b9069Sjruoho 	}
213774b9069Sjruoho 
214774b9069Sjruoho 	(void)close(fd);
215774b9069Sjruoho 	(void)wait(&sta);
216774b9069Sjruoho 	(void)unlink(path);
217774b9069Sjruoho 
218774b9069Sjruoho 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
219774b9069Sjruoho 		atf_tc_fail("RLIMIT_FSIZE not enforced");
220774b9069Sjruoho }
221774b9069Sjruoho 
ATF_TC_CLEANUP(setrlimit_fsize,tc)222774b9069Sjruoho ATF_TC_CLEANUP(setrlimit_fsize, tc)
223774b9069Sjruoho {
224774b9069Sjruoho 	(void)unlink(path);
225774b9069Sjruoho }
226774b9069Sjruoho 
227774b9069Sjruoho static void
sighandler(int signo)228774b9069Sjruoho sighandler(int signo)
229774b9069Sjruoho {
230774b9069Sjruoho 
231774b9069Sjruoho 	if (signo != SIGXFSZ)
232774b9069Sjruoho 		_exit(EXIT_FAILURE);
233774b9069Sjruoho 
234774b9069Sjruoho 	_exit(EXIT_SUCCESS);
235774b9069Sjruoho }
236774b9069Sjruoho 
237774b9069Sjruoho ATF_TC(setrlimit_memlock);
ATF_TC_HEAD(setrlimit_memlock,tc)238774b9069Sjruoho ATF_TC_HEAD(setrlimit_memlock, tc)
239774b9069Sjruoho {
240774b9069Sjruoho 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_MEMLOCK");
241774b9069Sjruoho }
242774b9069Sjruoho 
ATF_TC_BODY(setrlimit_memlock,tc)243774b9069Sjruoho ATF_TC_BODY(setrlimit_memlock, tc)
244774b9069Sjruoho {
245774b9069Sjruoho 	struct rlimit res;
246774b9069Sjruoho 	void *buf;
247774b9069Sjruoho 	long page;
248774b9069Sjruoho 	pid_t pid;
249774b9069Sjruoho 	int sta;
250774b9069Sjruoho 
251774b9069Sjruoho 	page = sysconf(_SC_PAGESIZE);
252774b9069Sjruoho 	ATF_REQUIRE(page >= 0);
253774b9069Sjruoho 
254774b9069Sjruoho 	buf = malloc(page);
255774b9069Sjruoho 	pid = fork();
256774b9069Sjruoho 
257774b9069Sjruoho 	if (buf == NULL || pid < 0)
258774b9069Sjruoho 		atf_tc_fail("initialization failed");
259774b9069Sjruoho 
260774b9069Sjruoho 	if (pid == 0) {
261774b9069Sjruoho 
262774b9069Sjruoho 		/*
263774b9069Sjruoho 		 * Try to lock a page while
264774b9069Sjruoho 		 * RLIMIT_MEMLOCK is zero.
265774b9069Sjruoho 		 */
266774b9069Sjruoho 		if (mlock(buf, page) != 0)
267774b9069Sjruoho 			_exit(EXIT_FAILURE);
268774b9069Sjruoho 
269774b9069Sjruoho 		if (munlock(buf, page) != 0)
270774b9069Sjruoho 			_exit(EXIT_FAILURE);
271774b9069Sjruoho 
272774b9069Sjruoho 		res.rlim_cur = 0;
273774b9069Sjruoho 		res.rlim_max = 0;
274774b9069Sjruoho 
275774b9069Sjruoho 		if (setrlimit(RLIMIT_MEMLOCK, &res) != 0)
276774b9069Sjruoho 			_exit(EXIT_FAILURE);
277774b9069Sjruoho 
278774b9069Sjruoho 		if (mlock(buf, page) != 0)
279774b9069Sjruoho 			_exit(EXIT_SUCCESS);
280774b9069Sjruoho 
281774b9069Sjruoho 		(void)munlock(buf, page);
282774b9069Sjruoho 
283774b9069Sjruoho 		_exit(EXIT_FAILURE);
284774b9069Sjruoho 	}
285774b9069Sjruoho 
286774b9069Sjruoho 	free(buf);
287774b9069Sjruoho 
288774b9069Sjruoho 	(void)wait(&sta);
289774b9069Sjruoho 
290774b9069Sjruoho 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
291774b9069Sjruoho 		atf_tc_fail("RLIMIT_MEMLOCK not enforced");
292774b9069Sjruoho }
293774b9069Sjruoho 
294774b9069Sjruoho ATF_TC(setrlimit_nofile_1);
ATF_TC_HEAD(setrlimit_nofile_1,tc)295774b9069Sjruoho ATF_TC_HEAD(setrlimit_nofile_1, tc)
296774b9069Sjruoho {
297774b9069Sjruoho 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NOFILE, #1");
298774b9069Sjruoho }
299774b9069Sjruoho 
ATF_TC_BODY(setrlimit_nofile_1,tc)300774b9069Sjruoho ATF_TC_BODY(setrlimit_nofile_1, tc)
301774b9069Sjruoho {
302774b9069Sjruoho 	struct rlimit res;
303774b9069Sjruoho 	int fd, i, rv, sta;
304774b9069Sjruoho 	pid_t pid;
305774b9069Sjruoho 
306774b9069Sjruoho 	res.rlim_cur = 0;
307774b9069Sjruoho 	res.rlim_max = 0;
308774b9069Sjruoho 
309774b9069Sjruoho 	pid = fork();
310774b9069Sjruoho 	ATF_REQUIRE(pid >= 0);
311774b9069Sjruoho 
312774b9069Sjruoho 	if (pid == 0) {
313774b9069Sjruoho 
314774b9069Sjruoho 		/*
315774b9069Sjruoho 		 * Close all descriptors, set RLIMIT_NOFILE
316774b9069Sjruoho 		 * to zero, and try to open a random file.
317774b9069Sjruoho 		 * This should fail with EMFILE.
318774b9069Sjruoho 		 */
319774b9069Sjruoho 		for (i = 0; i < 1024; i++)
320774b9069Sjruoho 			(void)close(i);
321774b9069Sjruoho 
322774b9069Sjruoho 		rv = setrlimit(RLIMIT_NOFILE, &res);
323774b9069Sjruoho 
324774b9069Sjruoho 		if (rv != 0)
325774b9069Sjruoho 			_exit(EXIT_FAILURE);
326774b9069Sjruoho 
327774b9069Sjruoho 		errno = 0;
328774b9069Sjruoho 		fd = open("/etc/passwd", O_RDONLY);
329774b9069Sjruoho 
330774b9069Sjruoho 		if (fd >= 0 || errno != EMFILE)
331774b9069Sjruoho 			_exit(EXIT_FAILURE);
332774b9069Sjruoho 
333774b9069Sjruoho 		_exit(EXIT_SUCCESS);
334774b9069Sjruoho 	}
335774b9069Sjruoho 
336774b9069Sjruoho 	(void)wait(&sta);
337774b9069Sjruoho 
338774b9069Sjruoho 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
339774b9069Sjruoho 		atf_tc_fail("RLIMIT_NOFILE not enforced");
340774b9069Sjruoho }
341774b9069Sjruoho 
342774b9069Sjruoho ATF_TC(setrlimit_nofile_2);
ATF_TC_HEAD(setrlimit_nofile_2,tc)343774b9069Sjruoho ATF_TC_HEAD(setrlimit_nofile_2, tc)
344774b9069Sjruoho {
345774b9069Sjruoho 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NOFILE, #2");
346774b9069Sjruoho }
347774b9069Sjruoho 
ATF_TC_BODY(setrlimit_nofile_2,tc)348774b9069Sjruoho ATF_TC_BODY(setrlimit_nofile_2, tc)
349774b9069Sjruoho {
350774b9069Sjruoho 	static const rlim_t lim = 12;
351774b9069Sjruoho 	struct rlimit res;
352774b9069Sjruoho 	int fd, i, rv, sta;
353774b9069Sjruoho 	pid_t pid;
354774b9069Sjruoho 
355774b9069Sjruoho 	/*
356774b9069Sjruoho 	 * See that an arbitrary limit on
357774b9069Sjruoho 	 * open files is being enforced.
358774b9069Sjruoho 	 */
359774b9069Sjruoho 	res.rlim_cur = lim;
360774b9069Sjruoho 	res.rlim_max = lim;
361774b9069Sjruoho 
362774b9069Sjruoho 	pid = fork();
363774b9069Sjruoho 	ATF_REQUIRE(pid >= 0);
364774b9069Sjruoho 
365774b9069Sjruoho 	if (pid == 0) {
366774b9069Sjruoho 
367774b9069Sjruoho 		for (i = 0; i < 1024; i++)
368774b9069Sjruoho 			(void)close(i);
369774b9069Sjruoho 
370774b9069Sjruoho 		rv = setrlimit(RLIMIT_NOFILE, &res);
371774b9069Sjruoho 
372774b9069Sjruoho 		if (rv != 0)
373774b9069Sjruoho 			_exit(EXIT_FAILURE);
374774b9069Sjruoho 
375774b9069Sjruoho 		for (i = 0; i < (int)lim; i++) {
376774b9069Sjruoho 
377774b9069Sjruoho 			fd = open("/etc/passwd", O_RDONLY);
378774b9069Sjruoho 
379774b9069Sjruoho 			if (fd < 0)
380774b9069Sjruoho 				_exit(EXIT_FAILURE);
381774b9069Sjruoho 		}
382774b9069Sjruoho 
383774b9069Sjruoho 		/*
384774b9069Sjruoho 		 * After the limit has been reached,
385774b9069Sjruoho 		 * EMFILE should again follow.
386774b9069Sjruoho 		 */
387774b9069Sjruoho 		fd = open("/etc/passwd", O_RDONLY);
388774b9069Sjruoho 
389774b9069Sjruoho 		if (fd >= 0 || errno != EMFILE)
390774b9069Sjruoho 			_exit(EXIT_FAILURE);
391774b9069Sjruoho 
392774b9069Sjruoho 		_exit(EXIT_SUCCESS);
393774b9069Sjruoho 	}
394774b9069Sjruoho 
395774b9069Sjruoho 	(void)wait(&sta);
396774b9069Sjruoho 
397774b9069Sjruoho 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
398774b9069Sjruoho 		atf_tc_fail("RLIMIT_NOFILE not enforced");
399774b9069Sjruoho }
400774b9069Sjruoho 
401774b9069Sjruoho ATF_TC(setrlimit_nproc);
ATF_TC_HEAD(setrlimit_nproc,tc)402774b9069Sjruoho ATF_TC_HEAD(setrlimit_nproc, tc)
403774b9069Sjruoho {
404774b9069Sjruoho 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NPROC");
405774b9069Sjruoho 	atf_tc_set_md_var(tc, "require.user", "unprivileged");
406774b9069Sjruoho }
407774b9069Sjruoho 
ATF_TC_BODY(setrlimit_nproc,tc)408774b9069Sjruoho ATF_TC_BODY(setrlimit_nproc, tc)
409774b9069Sjruoho {
410774b9069Sjruoho 	struct rlimit res;
411774b9069Sjruoho 	pid_t pid, cpid;
412774b9069Sjruoho 	int sta;
413774b9069Sjruoho 
414774b9069Sjruoho 	pid = fork();
415774b9069Sjruoho 	ATF_REQUIRE(pid >= 0);
416774b9069Sjruoho 
417774b9069Sjruoho 	if (pid == 0) {
418774b9069Sjruoho 
419774b9069Sjruoho 		/*
420774b9069Sjruoho 		 * Set RLIMIT_NPROC to zero and try to fork.
421774b9069Sjruoho 		 */
422774b9069Sjruoho 		res.rlim_cur = 0;
423774b9069Sjruoho 		res.rlim_max = 0;
424774b9069Sjruoho 
425774b9069Sjruoho 		if (setrlimit(RLIMIT_NPROC, &res) != 0)
426774b9069Sjruoho 			_exit(EXIT_FAILURE);
427774b9069Sjruoho 
428774b9069Sjruoho 		cpid = fork();
429774b9069Sjruoho 
430774b9069Sjruoho 		if (cpid < 0)
431774b9069Sjruoho 			_exit(EXIT_SUCCESS);
432774b9069Sjruoho 
433774b9069Sjruoho 		_exit(EXIT_FAILURE);
434774b9069Sjruoho 	}
435774b9069Sjruoho 
436774b9069Sjruoho 	(void)waitpid(pid, &sta, 0);
437774b9069Sjruoho 
438774b9069Sjruoho 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
439774b9069Sjruoho 		atf_tc_fail("RLIMIT_NPROC not enforced");
440774b9069Sjruoho }
441774b9069Sjruoho 
44274a08b15Schristos ATF_TC(setrlimit_nthr);
ATF_TC_HEAD(setrlimit_nthr,tc)44374a08b15Schristos ATF_TC_HEAD(setrlimit_nthr, tc)
44474a08b15Schristos {
44574a08b15Schristos 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NTHR");
44674a08b15Schristos 	atf_tc_set_md_var(tc, "require.user", "unprivileged");
44774a08b15Schristos }
44874a08b15Schristos 
44974a08b15Schristos static void
func(lwpid_t * id)45074a08b15Schristos func(lwpid_t *id)
45174a08b15Schristos {
45274a08b15Schristos 	printf("thread %d\n", *id);
45374a08b15Schristos 	fflush(stdout);
45474a08b15Schristos 	_lwp_exit();
45574a08b15Schristos }
45674a08b15Schristos 
ATF_TC_BODY(setrlimit_nthr,tc)45774a08b15Schristos ATF_TC_BODY(setrlimit_nthr, tc)
45874a08b15Schristos {
45974a08b15Schristos 	struct rlimit res;
46074a08b15Schristos 	lwpid_t lwpid;
46174a08b15Schristos 	ucontext_t c;
46274a08b15Schristos 
46374a08b15Schristos 	/*
46474a08b15Schristos 	 * Set RLIMIT_NTHR to zero and try to create a thread.
46574a08b15Schristos 	 */
46674a08b15Schristos 	res.rlim_cur = 0;
46774a08b15Schristos 	res.rlim_max = 0;
46874a08b15Schristos 	ATF_REQUIRE(setrlimit(RLIMIT_NTHR, &res) == 0);
46974a08b15Schristos 	ATF_REQUIRE(getcontext(&c) == 0);
47074a08b15Schristos 	c.uc_link = NULL;
47174a08b15Schristos 	sigemptyset(&c.uc_sigmask);
47274a08b15Schristos 	c.uc_stack.ss_flags = 0;
47374a08b15Schristos 	c.uc_stack.ss_size = 4096;
47474a08b15Schristos 	ATF_REQUIRE((c.uc_stack.ss_sp = malloc(c.uc_stack.ss_size)) != NULL);
47574a08b15Schristos 	makecontext(&c, func, 1, &lwpid);
47674a08b15Schristos 	ATF_CHECK_ERRNO(EAGAIN, _lwp_create(&c, 0, &lwpid) == -1);
47774a08b15Schristos }
47874a08b15Schristos 
479774b9069Sjruoho ATF_TC(setrlimit_perm);
ATF_TC_HEAD(setrlimit_perm,tc)480774b9069Sjruoho ATF_TC_HEAD(setrlimit_perm, tc)
481774b9069Sjruoho {
482774b9069Sjruoho 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2) for EPERM");
483774b9069Sjruoho 	atf_tc_set_md_var(tc, "require.user", "unprivileged");
484774b9069Sjruoho }
485774b9069Sjruoho 
ATF_TC_BODY(setrlimit_perm,tc)486774b9069Sjruoho ATF_TC_BODY(setrlimit_perm, tc)
487774b9069Sjruoho {
488774b9069Sjruoho 	struct rlimit res;
489774b9069Sjruoho 	size_t i;
490774b9069Sjruoho 
491774b9069Sjruoho 	/*
492774b9069Sjruoho 	 * Try to raise the maximum limits as an user.
493774b9069Sjruoho 	 */
494774b9069Sjruoho 	for (i = 0; i < __arraycount(rlimit); i++) {
495774b9069Sjruoho 
496774b9069Sjruoho 		ATF_REQUIRE(getrlimit(rlimit[i], &res) == 0);
497774b9069Sjruoho 
498774b9069Sjruoho 		if (res.rlim_max == UINT64_MAX) /* Overflow. */
499774b9069Sjruoho 			continue;
500774b9069Sjruoho 
501774b9069Sjruoho 		errno = 0;
502774b9069Sjruoho 		res.rlim_max = res.rlim_max + 1;
503774b9069Sjruoho 
504c2113380Snjoly 		ATF_CHECK_ERRNO(EPERM, setrlimit(rlimit[i], &res) != 0);
505774b9069Sjruoho 	}
506774b9069Sjruoho }
507774b9069Sjruoho 
50803a790a7Snjoly ATF_TC(setrlimit_stack);
ATF_TC_HEAD(setrlimit_stack,tc)50903a790a7Snjoly ATF_TC_HEAD(setrlimit_stack, tc)
51003a790a7Snjoly {
51103a790a7Snjoly 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_STACK");
51203a790a7Snjoly 	atf_tc_set_md_var(tc, "require.user", "unprivileged");
51303a790a7Snjoly }
51403a790a7Snjoly 
ATF_TC_BODY(setrlimit_stack,tc)51503a790a7Snjoly ATF_TC_BODY(setrlimit_stack, tc)
51603a790a7Snjoly {
51703a790a7Snjoly 	struct rlimit res;
51803a790a7Snjoly 
51903a790a7Snjoly 	/* Ensure soft limit is not bigger than hard limit */
520*cc84348dSrin 	res.rlim_cur = res.rlim_max = 6 * 1024 * 1024;
52103a790a7Snjoly 	ATF_REQUIRE(setrlimit(RLIMIT_STACK, &res) == 0);
52203a790a7Snjoly 	ATF_REQUIRE(getrlimit(RLIMIT_STACK, &res) == 0);
52303a790a7Snjoly 	ATF_CHECK(res.rlim_cur <= res.rlim_max);
52403a790a7Snjoly 
52503a790a7Snjoly }
52603a790a7Snjoly 
ATF_TP_ADD_TCS(tp)527774b9069Sjruoho ATF_TP_ADD_TCS(tp)
528774b9069Sjruoho {
529774b9069Sjruoho 
530774b9069Sjruoho 	ATF_TP_ADD_TC(tp, setrlimit_basic);
531774b9069Sjruoho 	ATF_TP_ADD_TC(tp, setrlimit_current);
532774b9069Sjruoho 	ATF_TP_ADD_TC(tp, setrlimit_err);
533774b9069Sjruoho 	ATF_TP_ADD_TC(tp, setrlimit_fsize);
534774b9069Sjruoho 	ATF_TP_ADD_TC(tp, setrlimit_memlock);
535774b9069Sjruoho 	ATF_TP_ADD_TC(tp, setrlimit_nofile_1);
536774b9069Sjruoho 	ATF_TP_ADD_TC(tp, setrlimit_nofile_2);
537774b9069Sjruoho 	ATF_TP_ADD_TC(tp, setrlimit_nproc);
538774b9069Sjruoho 	ATF_TP_ADD_TC(tp, setrlimit_perm);
53974a08b15Schristos 	ATF_TP_ADD_TC(tp, setrlimit_nthr);
54003a790a7Snjoly 	ATF_TP_ADD_TC(tp, setrlimit_stack);
541774b9069Sjruoho 
542774b9069Sjruoho 	return atf_no_error();
543774b9069Sjruoho }
544