xref: /openbsd-src/regress/lib/libc/sys/t_setrlimit.c (revision 49a6e16f2c2c8e509184b1f777366d1a6f337e1c)
1*49a6e16fSderaadt /*	$OpenBSD: t_setrlimit.c,v 1.2 2021/12/13 16:56:48 deraadt Exp $	*/
2abbaa274Smbuhl /* $NetBSD: t_setrlimit.c,v 1.7 2020/10/13 06:58:57 rin Exp $ */
3abbaa274Smbuhl 
4abbaa274Smbuhl /*-
5abbaa274Smbuhl  * Copyright (c) 2011 The NetBSD Foundation, Inc.
6abbaa274Smbuhl  * All rights reserved.
7abbaa274Smbuhl  *
8abbaa274Smbuhl  * This code is derived from software contributed to The NetBSD Foundation
9abbaa274Smbuhl  * by Jukka Ruohonen.
10abbaa274Smbuhl  *
11abbaa274Smbuhl  * Redistribution and use in source and binary forms, with or without
12abbaa274Smbuhl  * modification, are permitted provided that the following conditions
13abbaa274Smbuhl  * are met:
14abbaa274Smbuhl  * 1. Redistributions of source code must retain the above copyright
15abbaa274Smbuhl  *    notice, this list of conditions and the following disclaimer.
16abbaa274Smbuhl  * 2. Redistributions in binary form must reproduce the above copyright
17abbaa274Smbuhl  *    notice, this list of conditions and the following disclaimer in the
18abbaa274Smbuhl  *    documentation and/or other materials provided with the distribution.
19abbaa274Smbuhl  *
20abbaa274Smbuhl  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21abbaa274Smbuhl  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22abbaa274Smbuhl  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23abbaa274Smbuhl  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24abbaa274Smbuhl  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25abbaa274Smbuhl  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26abbaa274Smbuhl  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27abbaa274Smbuhl  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28abbaa274Smbuhl  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29abbaa274Smbuhl  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30abbaa274Smbuhl  * POSSIBILITY OF SUCH DAMAGE.
31abbaa274Smbuhl  */
32abbaa274Smbuhl #include "macros.h"
33abbaa274Smbuhl 
34abbaa274Smbuhl #include <sys/resource.h>
35abbaa274Smbuhl #include <sys/mman.h>
36abbaa274Smbuhl #include <sys/wait.h>
37abbaa274Smbuhl 
38abbaa274Smbuhl #include "atf-c.h"
39abbaa274Smbuhl #include <errno.h>
40abbaa274Smbuhl #include <fcntl.h>
41abbaa274Smbuhl #include <limits.h>
42abbaa274Smbuhl #ifndef __OpenBSD__
43abbaa274Smbuhl #include <lwp.h>
44abbaa274Smbuhl #endif
45abbaa274Smbuhl #include <signal.h>
46abbaa274Smbuhl #include <stdint.h>
47abbaa274Smbuhl #include <stdio.h>
48abbaa274Smbuhl #include <stdlib.h>
49abbaa274Smbuhl #include <string.h>
50abbaa274Smbuhl #ifndef __OpenBSD__
51abbaa274Smbuhl #include <ucontext.h>
52abbaa274Smbuhl #endif
53abbaa274Smbuhl #include <unistd.h>
54abbaa274Smbuhl 
55abbaa274Smbuhl static void		 sighandler(int);
56abbaa274Smbuhl static const char	 path[] = "setrlimit";
57abbaa274Smbuhl 
58abbaa274Smbuhl static const int rlimit[] = {
59abbaa274Smbuhl #ifndef __OpenBSD__
60abbaa274Smbuhl 	RLIMIT_AS,
61abbaa274Smbuhl #endif
62abbaa274Smbuhl 	RLIMIT_CORE,
63abbaa274Smbuhl 	RLIMIT_CPU,
64abbaa274Smbuhl 	RLIMIT_DATA,
65abbaa274Smbuhl 	RLIMIT_FSIZE,
66abbaa274Smbuhl 	RLIMIT_MEMLOCK,
67abbaa274Smbuhl 	RLIMIT_NOFILE,
68abbaa274Smbuhl 	RLIMIT_NPROC,
69abbaa274Smbuhl 	RLIMIT_RSS,
70abbaa274Smbuhl #ifndef __OpenBSD__
71abbaa274Smbuhl 	RLIMIT_SBSIZE,
72abbaa274Smbuhl #endif
73abbaa274Smbuhl 	RLIMIT_STACK
74abbaa274Smbuhl };
75abbaa274Smbuhl 
76abbaa274Smbuhl ATF_TC(setrlimit_basic);
ATF_TC_HEAD(setrlimit_basic,tc)77abbaa274Smbuhl ATF_TC_HEAD(setrlimit_basic, tc)
78abbaa274Smbuhl {
79abbaa274Smbuhl 	atf_tc_set_md_var(tc, "descr", "A basic soft limit test");
80abbaa274Smbuhl }
81abbaa274Smbuhl 
ATF_TC_BODY(setrlimit_basic,tc)82abbaa274Smbuhl ATF_TC_BODY(setrlimit_basic, tc)
83abbaa274Smbuhl {
84abbaa274Smbuhl 	struct rlimit res;
85abbaa274Smbuhl 	int *buf, lim;
86abbaa274Smbuhl 	size_t i;
87abbaa274Smbuhl 
88abbaa274Smbuhl 	buf = calloc(__arraycount(rlimit), sizeof(int));
89abbaa274Smbuhl 
90abbaa274Smbuhl 	if (buf == NULL)
91abbaa274Smbuhl 		atf_tc_fail("initialization failed");
92abbaa274Smbuhl 
93abbaa274Smbuhl 	for (i = lim = 0; i < __arraycount(rlimit); i++) {
94abbaa274Smbuhl 
95abbaa274Smbuhl 		(void)memset(&res, 0, sizeof(struct rlimit));
96abbaa274Smbuhl 
97abbaa274Smbuhl 		if (getrlimit(rlimit[i], &res) != 0)
98abbaa274Smbuhl 			continue;
99abbaa274Smbuhl 
100abbaa274Smbuhl 		if (res.rlim_cur == RLIM_INFINITY || res.rlim_cur == 0)
101abbaa274Smbuhl 			continue;
102abbaa274Smbuhl 
103abbaa274Smbuhl 		if (res.rlim_cur == res.rlim_max) /* An unprivileged run. */
104abbaa274Smbuhl 			continue;
105abbaa274Smbuhl 
106abbaa274Smbuhl 		buf[i] = res.rlim_cur;
107abbaa274Smbuhl 		res.rlim_cur = res.rlim_cur - 1;
108abbaa274Smbuhl 
109abbaa274Smbuhl 		if (setrlimit(rlimit[i], &res) != 0) {
110abbaa274Smbuhl 			lim = rlimit[i];
111abbaa274Smbuhl 			goto out;
112abbaa274Smbuhl 		}
113abbaa274Smbuhl 	}
114abbaa274Smbuhl 
115abbaa274Smbuhl out:
116abbaa274Smbuhl 	for (i = 0; i < __arraycount(rlimit); i++) {
117abbaa274Smbuhl 
118abbaa274Smbuhl 		(void)memset(&res, 0, sizeof(struct rlimit));
119abbaa274Smbuhl 
120abbaa274Smbuhl 		if (buf[i] == 0)
121abbaa274Smbuhl 			continue;
122abbaa274Smbuhl 
123abbaa274Smbuhl 		if (getrlimit(rlimit[i], &res) != 0)
124abbaa274Smbuhl 			continue;
125abbaa274Smbuhl 
126abbaa274Smbuhl 		res.rlim_cur = buf[i];
127abbaa274Smbuhl 
128abbaa274Smbuhl 		(void)setrlimit(rlimit[i], &res);
129abbaa274Smbuhl 	}
130abbaa274Smbuhl 
131abbaa274Smbuhl 	if (lim != 0)
132abbaa274Smbuhl 		atf_tc_fail("failed to set limit (%d)", lim);
133abbaa274Smbuhl 	free(buf);
134abbaa274Smbuhl }
135abbaa274Smbuhl 
136abbaa274Smbuhl ATF_TC(setrlimit_current);
ATF_TC_HEAD(setrlimit_current,tc)137abbaa274Smbuhl ATF_TC_HEAD(setrlimit_current, tc)
138abbaa274Smbuhl {
139abbaa274Smbuhl 	atf_tc_set_md_var(tc, "descr", "setrlimit(3) with current limits");
140abbaa274Smbuhl }
141abbaa274Smbuhl 
ATF_TC_BODY(setrlimit_current,tc)142abbaa274Smbuhl ATF_TC_BODY(setrlimit_current, tc)
143abbaa274Smbuhl {
144abbaa274Smbuhl 	struct rlimit res;
145abbaa274Smbuhl 	size_t i;
146abbaa274Smbuhl 
147abbaa274Smbuhl 	for (i = 0; i < __arraycount(rlimit); i++) {
148abbaa274Smbuhl 
149abbaa274Smbuhl 		(void)memset(&res, 0, sizeof(struct rlimit));
150abbaa274Smbuhl 
151abbaa274Smbuhl 		ATF_REQUIRE(getrlimit(rlimit[i], &res) == 0);
152abbaa274Smbuhl 		ATF_REQUIRE(setrlimit(rlimit[i], &res) == 0);
153abbaa274Smbuhl 	}
154abbaa274Smbuhl }
155abbaa274Smbuhl 
156abbaa274Smbuhl ATF_TC(setrlimit_err);
ATF_TC_HEAD(setrlimit_err,tc)157abbaa274Smbuhl ATF_TC_HEAD(setrlimit_err, tc)
158abbaa274Smbuhl {
159abbaa274Smbuhl 	atf_tc_set_md_var(tc, "descr", "Test error conditions");
160abbaa274Smbuhl }
161abbaa274Smbuhl 
ATF_TC_BODY(setrlimit_err,tc)162abbaa274Smbuhl ATF_TC_BODY(setrlimit_err, tc)
163abbaa274Smbuhl {
164abbaa274Smbuhl 	struct rlimit res;
165abbaa274Smbuhl 	size_t i;
166abbaa274Smbuhl 
167abbaa274Smbuhl 	for (i = 0; i < __arraycount(rlimit); i++) {
168abbaa274Smbuhl 
169abbaa274Smbuhl 		errno = 0;
170abbaa274Smbuhl 
171abbaa274Smbuhl 		ATF_REQUIRE(getrlimit(rlimit[i], (void *)0) != 0);
172abbaa274Smbuhl 		ATF_REQUIRE(errno == EFAULT);
173abbaa274Smbuhl 	}
174abbaa274Smbuhl 
175abbaa274Smbuhl 	errno = 0;
176abbaa274Smbuhl 
177abbaa274Smbuhl 	ATF_REQUIRE(getrlimit(INT_MAX, &res) != 0);
178abbaa274Smbuhl 	ATF_REQUIRE(errno == EINVAL);
179abbaa274Smbuhl }
180abbaa274Smbuhl 
181abbaa274Smbuhl ATF_TC_WITH_CLEANUP(setrlimit_fsize);
ATF_TC_HEAD(setrlimit_fsize,tc)182abbaa274Smbuhl ATF_TC_HEAD(setrlimit_fsize, tc)
183abbaa274Smbuhl {
184abbaa274Smbuhl 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_FSIZE");
185abbaa274Smbuhl }
186abbaa274Smbuhl 
ATF_TC_BODY(setrlimit_fsize,tc)187abbaa274Smbuhl ATF_TC_BODY(setrlimit_fsize, tc)
188abbaa274Smbuhl {
189abbaa274Smbuhl 	struct rlimit res;
190abbaa274Smbuhl 	int fd, sta;
191abbaa274Smbuhl 	pid_t pid;
192abbaa274Smbuhl 
193abbaa274Smbuhl 	fd = open(path, O_RDWR | O_CREAT, 0700);
194abbaa274Smbuhl 
195abbaa274Smbuhl 	if (fd < 0)
196abbaa274Smbuhl 		atf_tc_fail("initialization failed");
197abbaa274Smbuhl 
198abbaa274Smbuhl 	pid = fork();
199abbaa274Smbuhl 	ATF_REQUIRE(pid >= 0);
200abbaa274Smbuhl 
201abbaa274Smbuhl 	if (pid == 0) {
202abbaa274Smbuhl 
203abbaa274Smbuhl 		res.rlim_cur = 2;
204abbaa274Smbuhl 		res.rlim_max = 2;
205abbaa274Smbuhl 
206abbaa274Smbuhl 		if (setrlimit(RLIMIT_FSIZE, &res) != 0)
207abbaa274Smbuhl 			_exit(EXIT_FAILURE);
208abbaa274Smbuhl 
209abbaa274Smbuhl 		if (signal(SIGXFSZ, sighandler) == SIG_ERR)
210abbaa274Smbuhl 			_exit(EXIT_FAILURE);
211abbaa274Smbuhl 
212abbaa274Smbuhl 		/*
213abbaa274Smbuhl 		 * The third call should generate a SIGXFSZ.
214abbaa274Smbuhl 		 */
215abbaa274Smbuhl 		(void)write(fd, "X", 1);
216abbaa274Smbuhl 		(void)write(fd, "X", 1);
217abbaa274Smbuhl 		(void)write(fd, "X", 1);
218abbaa274Smbuhl 
219abbaa274Smbuhl 		_exit(EXIT_FAILURE);
220abbaa274Smbuhl 	}
221abbaa274Smbuhl 
222abbaa274Smbuhl 	(void)close(fd);
223abbaa274Smbuhl 	(void)wait(&sta);
224abbaa274Smbuhl 	(void)unlink(path);
225abbaa274Smbuhl 
226abbaa274Smbuhl 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
227abbaa274Smbuhl 		atf_tc_fail("RLIMIT_FSIZE not enforced");
228abbaa274Smbuhl }
229abbaa274Smbuhl 
ATF_TC_CLEANUP(setrlimit_fsize,tc)230abbaa274Smbuhl ATF_TC_CLEANUP(setrlimit_fsize, tc)
231abbaa274Smbuhl {
232abbaa274Smbuhl 	(void)unlink(path);
233abbaa274Smbuhl }
234abbaa274Smbuhl 
235abbaa274Smbuhl static void
sighandler(int signo)236abbaa274Smbuhl sighandler(int signo)
237abbaa274Smbuhl {
238abbaa274Smbuhl 
239abbaa274Smbuhl 	if (signo != SIGXFSZ)
240abbaa274Smbuhl 		_exit(EXIT_FAILURE);
241abbaa274Smbuhl 
242abbaa274Smbuhl 	_exit(EXIT_SUCCESS);
243abbaa274Smbuhl }
244abbaa274Smbuhl 
245abbaa274Smbuhl ATF_TC(setrlimit_memlock);
ATF_TC_HEAD(setrlimit_memlock,tc)246abbaa274Smbuhl ATF_TC_HEAD(setrlimit_memlock, tc)
247abbaa274Smbuhl {
248abbaa274Smbuhl 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_MEMLOCK");
249abbaa274Smbuhl }
250abbaa274Smbuhl 
ATF_TC_BODY(setrlimit_memlock,tc)251abbaa274Smbuhl ATF_TC_BODY(setrlimit_memlock, tc)
252abbaa274Smbuhl {
253abbaa274Smbuhl 	struct rlimit res;
254abbaa274Smbuhl 	void *buf;
255abbaa274Smbuhl 	long page;
256abbaa274Smbuhl 	pid_t pid;
257abbaa274Smbuhl 	int sta;
258abbaa274Smbuhl 
259abbaa274Smbuhl 	page = sysconf(_SC_PAGESIZE);
260abbaa274Smbuhl 	ATF_REQUIRE(page >= 0);
261abbaa274Smbuhl 
262abbaa274Smbuhl 	buf = malloc(page);
263abbaa274Smbuhl 	pid = fork();
264abbaa274Smbuhl 
265abbaa274Smbuhl 	if (buf == NULL || pid < 0)
266abbaa274Smbuhl 		atf_tc_fail("initialization failed");
267abbaa274Smbuhl 
268abbaa274Smbuhl 	if (pid == 0) {
269abbaa274Smbuhl 
270abbaa274Smbuhl 		/*
271abbaa274Smbuhl 		 * Try to lock a page while
272abbaa274Smbuhl 		 * RLIMIT_MEMLOCK is zero.
273abbaa274Smbuhl 		 */
274abbaa274Smbuhl 		if (mlock(buf, page) != 0)
275abbaa274Smbuhl 			_exit(EXIT_FAILURE);
276abbaa274Smbuhl 
277abbaa274Smbuhl 		if (munlock(buf, page) != 0)
278abbaa274Smbuhl 			_exit(EXIT_FAILURE);
279abbaa274Smbuhl 
280abbaa274Smbuhl 		res.rlim_cur = 0;
281abbaa274Smbuhl 		res.rlim_max = 0;
282abbaa274Smbuhl 
283abbaa274Smbuhl 		if (setrlimit(RLIMIT_MEMLOCK, &res) != 0)
284abbaa274Smbuhl 			_exit(EXIT_FAILURE);
285abbaa274Smbuhl 
286abbaa274Smbuhl 		if (mlock(buf, page) != 0)
287abbaa274Smbuhl 			_exit(EXIT_SUCCESS);
288abbaa274Smbuhl 
289abbaa274Smbuhl 		(void)munlock(buf, page);
290abbaa274Smbuhl 
291abbaa274Smbuhl 		_exit(EXIT_FAILURE);
292abbaa274Smbuhl 	}
293abbaa274Smbuhl 
294abbaa274Smbuhl 	free(buf);
295abbaa274Smbuhl 
296abbaa274Smbuhl 	(void)wait(&sta);
297abbaa274Smbuhl 
298abbaa274Smbuhl 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
299abbaa274Smbuhl 		atf_tc_fail("RLIMIT_MEMLOCK not enforced");
300abbaa274Smbuhl }
301abbaa274Smbuhl 
302abbaa274Smbuhl ATF_TC(setrlimit_nofile_1);
ATF_TC_HEAD(setrlimit_nofile_1,tc)303abbaa274Smbuhl ATF_TC_HEAD(setrlimit_nofile_1, tc)
304abbaa274Smbuhl {
305abbaa274Smbuhl 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NOFILE, #1");
306abbaa274Smbuhl }
307abbaa274Smbuhl 
ATF_TC_BODY(setrlimit_nofile_1,tc)308abbaa274Smbuhl ATF_TC_BODY(setrlimit_nofile_1, tc)
309abbaa274Smbuhl {
310abbaa274Smbuhl 	struct rlimit res;
311abbaa274Smbuhl 	int fd, i, rv, sta;
312abbaa274Smbuhl 	pid_t pid;
313abbaa274Smbuhl 
314abbaa274Smbuhl 	res.rlim_cur = 0;
315abbaa274Smbuhl 	res.rlim_max = 0;
316abbaa274Smbuhl 
317abbaa274Smbuhl 	pid = fork();
318abbaa274Smbuhl 	ATF_REQUIRE(pid >= 0);
319abbaa274Smbuhl 
320abbaa274Smbuhl 	if (pid == 0) {
321abbaa274Smbuhl 
322abbaa274Smbuhl 		/*
323abbaa274Smbuhl 		 * Close all descriptors, set RLIMIT_NOFILE
324abbaa274Smbuhl 		 * to zero, and try to open a random file.
325abbaa274Smbuhl 		 * This should fail with EMFILE.
326abbaa274Smbuhl 		 */
327abbaa274Smbuhl 		for (i = 0; i < 1024; i++)
328abbaa274Smbuhl 			(void)close(i);
329abbaa274Smbuhl 
330abbaa274Smbuhl 		rv = setrlimit(RLIMIT_NOFILE, &res);
331abbaa274Smbuhl 
332abbaa274Smbuhl 		if (rv != 0)
333abbaa274Smbuhl 			_exit(EXIT_FAILURE);
334abbaa274Smbuhl 
335abbaa274Smbuhl 		errno = 0;
336abbaa274Smbuhl 		fd = open("/etc/passwd", O_RDONLY);
337abbaa274Smbuhl 
338abbaa274Smbuhl 		if (fd >= 0 || errno != EMFILE)
339abbaa274Smbuhl 			_exit(EXIT_FAILURE);
340abbaa274Smbuhl 
341abbaa274Smbuhl 		_exit(EXIT_SUCCESS);
342abbaa274Smbuhl 	}
343abbaa274Smbuhl 
344abbaa274Smbuhl 	(void)wait(&sta);
345abbaa274Smbuhl 
346abbaa274Smbuhl 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
347abbaa274Smbuhl 		atf_tc_fail("RLIMIT_NOFILE not enforced");
348abbaa274Smbuhl }
349abbaa274Smbuhl 
350abbaa274Smbuhl ATF_TC(setrlimit_nofile_2);
ATF_TC_HEAD(setrlimit_nofile_2,tc)351abbaa274Smbuhl ATF_TC_HEAD(setrlimit_nofile_2, tc)
352abbaa274Smbuhl {
353abbaa274Smbuhl 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NOFILE, #2");
354abbaa274Smbuhl }
355abbaa274Smbuhl 
ATF_TC_BODY(setrlimit_nofile_2,tc)356abbaa274Smbuhl ATF_TC_BODY(setrlimit_nofile_2, tc)
357abbaa274Smbuhl {
358abbaa274Smbuhl 	static const rlim_t lim = 12;
359abbaa274Smbuhl 	struct rlimit res;
360abbaa274Smbuhl 	int fd, i, rv, sta;
361abbaa274Smbuhl 	pid_t pid;
362abbaa274Smbuhl 
363abbaa274Smbuhl 	/*
364abbaa274Smbuhl 	 * See that an arbitrary limit on
365abbaa274Smbuhl 	 * open files is being enforced.
366abbaa274Smbuhl 	 */
367abbaa274Smbuhl 	res.rlim_cur = lim;
368abbaa274Smbuhl 	res.rlim_max = lim;
369abbaa274Smbuhl 
370abbaa274Smbuhl 	pid = fork();
371abbaa274Smbuhl 	ATF_REQUIRE(pid >= 0);
372abbaa274Smbuhl 
373abbaa274Smbuhl 	if (pid == 0) {
374abbaa274Smbuhl 
375abbaa274Smbuhl 		for (i = 0; i < 1024; i++)
376abbaa274Smbuhl 			(void)close(i);
377abbaa274Smbuhl 
378abbaa274Smbuhl 		rv = setrlimit(RLIMIT_NOFILE, &res);
379abbaa274Smbuhl 
380abbaa274Smbuhl 		if (rv != 0)
381abbaa274Smbuhl 			_exit(EXIT_FAILURE);
382abbaa274Smbuhl 
383abbaa274Smbuhl 		for (i = 0; i < (int)lim; i++) {
384abbaa274Smbuhl 
385abbaa274Smbuhl 			fd = open("/etc/passwd", O_RDONLY);
386abbaa274Smbuhl 
387abbaa274Smbuhl 			if (fd < 0)
388abbaa274Smbuhl 				_exit(EXIT_FAILURE);
389abbaa274Smbuhl 		}
390abbaa274Smbuhl 
391abbaa274Smbuhl 		/*
392abbaa274Smbuhl 		 * After the limit has been reached,
393abbaa274Smbuhl 		 * EMFILE should again follow.
394abbaa274Smbuhl 		 */
395abbaa274Smbuhl 		fd = open("/etc/passwd", O_RDONLY);
396abbaa274Smbuhl 
397abbaa274Smbuhl 		if (fd >= 0 || errno != EMFILE)
398abbaa274Smbuhl 			_exit(EXIT_FAILURE);
399abbaa274Smbuhl 
400abbaa274Smbuhl 		_exit(EXIT_SUCCESS);
401abbaa274Smbuhl 	}
402abbaa274Smbuhl 
403abbaa274Smbuhl 	(void)wait(&sta);
404abbaa274Smbuhl 
405abbaa274Smbuhl 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
406abbaa274Smbuhl 		atf_tc_fail("RLIMIT_NOFILE not enforced");
407abbaa274Smbuhl }
408abbaa274Smbuhl 
409abbaa274Smbuhl ATF_TC(setrlimit_nproc);
ATF_TC_HEAD(setrlimit_nproc,tc)410abbaa274Smbuhl ATF_TC_HEAD(setrlimit_nproc, tc)
411abbaa274Smbuhl {
412abbaa274Smbuhl 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NPROC");
413abbaa274Smbuhl 	atf_tc_set_md_var(tc, "require.user", "unprivileged");
414abbaa274Smbuhl }
415abbaa274Smbuhl 
ATF_TC_BODY(setrlimit_nproc,tc)416abbaa274Smbuhl ATF_TC_BODY(setrlimit_nproc, tc)
417abbaa274Smbuhl {
418abbaa274Smbuhl 	struct rlimit res;
419abbaa274Smbuhl 	pid_t pid, cpid;
420abbaa274Smbuhl 	int sta;
421abbaa274Smbuhl 
422abbaa274Smbuhl 	pid = fork();
423abbaa274Smbuhl 	ATF_REQUIRE(pid >= 0);
424abbaa274Smbuhl 
425abbaa274Smbuhl 	if (pid == 0) {
426abbaa274Smbuhl 
427abbaa274Smbuhl 		/*
428abbaa274Smbuhl 		 * Set RLIMIT_NPROC to zero and try to fork.
429abbaa274Smbuhl 		 */
430abbaa274Smbuhl 		res.rlim_cur = 0;
431abbaa274Smbuhl 		res.rlim_max = 0;
432abbaa274Smbuhl 
433abbaa274Smbuhl 		if (setrlimit(RLIMIT_NPROC, &res) != 0)
434abbaa274Smbuhl 			_exit(EXIT_FAILURE);
435abbaa274Smbuhl 
436abbaa274Smbuhl 		cpid = fork();
437abbaa274Smbuhl 
438abbaa274Smbuhl 		if (cpid < 0)
439abbaa274Smbuhl 			_exit(EXIT_SUCCESS);
440abbaa274Smbuhl 
441abbaa274Smbuhl 		_exit(EXIT_FAILURE);
442abbaa274Smbuhl 	}
443abbaa274Smbuhl 
444abbaa274Smbuhl 	(void)waitpid(pid, &sta, 0);
445abbaa274Smbuhl 
446abbaa274Smbuhl 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
447abbaa274Smbuhl 		atf_tc_fail("RLIMIT_NPROC not enforced");
448abbaa274Smbuhl }
449abbaa274Smbuhl 
450abbaa274Smbuhl #ifndef __OpenBSD__
451abbaa274Smbuhl 
452abbaa274Smbuhl ATF_TC(setrlimit_nthr);
ATF_TC_HEAD(setrlimit_nthr,tc)453abbaa274Smbuhl ATF_TC_HEAD(setrlimit_nthr, tc)
454abbaa274Smbuhl {
455abbaa274Smbuhl 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NTHR");
456abbaa274Smbuhl 	atf_tc_set_md_var(tc, "require.user", "unprivileged");
457abbaa274Smbuhl }
458abbaa274Smbuhl 
459abbaa274Smbuhl static void
func(lwpid_t * id)460abbaa274Smbuhl func(lwpid_t *id)
461abbaa274Smbuhl {
462abbaa274Smbuhl 	printf("thread %d\n", *id);
463abbaa274Smbuhl 	fflush(stdout);
464abbaa274Smbuhl 	_lwp_exit();
465abbaa274Smbuhl }
466abbaa274Smbuhl 
ATF_TC_BODY(setrlimit_nthr,tc)467abbaa274Smbuhl ATF_TC_BODY(setrlimit_nthr, tc)
468abbaa274Smbuhl {
469abbaa274Smbuhl 	struct rlimit res;
470abbaa274Smbuhl 	lwpid_t lwpid;
471abbaa274Smbuhl 	ucontext_t c;
472abbaa274Smbuhl 
473abbaa274Smbuhl 	/*
474abbaa274Smbuhl 	 * Set RLIMIT_NTHR to zero and try to create a thread.
475abbaa274Smbuhl 	 */
476abbaa274Smbuhl 	res.rlim_cur = 0;
477abbaa274Smbuhl 	res.rlim_max = 0;
478abbaa274Smbuhl 	ATF_REQUIRE(setrlimit(RLIMIT_NTHR, &res) == 0);
479abbaa274Smbuhl 	ATF_REQUIRE(getcontext(&c) == 0);
480abbaa274Smbuhl 	c.uc_link = NULL;
481abbaa274Smbuhl 	sigemptyset(&c.uc_sigmask);
482abbaa274Smbuhl 	c.uc_stack.ss_flags = 0;
483abbaa274Smbuhl 	c.uc_stack.ss_size = 4096;
484abbaa274Smbuhl 	ATF_REQUIRE((c.uc_stack.ss_sp = malloc(c.uc_stack.ss_size)) != NULL);
485abbaa274Smbuhl 	makecontext(&c, func, 1, &lwpid);
486abbaa274Smbuhl 	ATF_CHECK_ERRNO(EAGAIN, _lwp_create(&c, 0, &lwpid) == -1);
487abbaa274Smbuhl }
488abbaa274Smbuhl #endif
489abbaa274Smbuhl 
490abbaa274Smbuhl ATF_TC(setrlimit_perm);
ATF_TC_HEAD(setrlimit_perm,tc)491abbaa274Smbuhl ATF_TC_HEAD(setrlimit_perm, tc)
492abbaa274Smbuhl {
493abbaa274Smbuhl 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2) for EPERM");
494abbaa274Smbuhl 	atf_tc_set_md_var(tc, "require.user", "unprivileged");
495abbaa274Smbuhl }
496abbaa274Smbuhl 
ATF_TC_BODY(setrlimit_perm,tc)497abbaa274Smbuhl ATF_TC_BODY(setrlimit_perm, tc)
498abbaa274Smbuhl {
499abbaa274Smbuhl 	struct rlimit res;
500abbaa274Smbuhl 	size_t i;
501abbaa274Smbuhl 
502abbaa274Smbuhl 	/*
503abbaa274Smbuhl 	 * Try to raise the maximum limits as an user.
504abbaa274Smbuhl 	 */
505abbaa274Smbuhl 	for (i = 0; i < __arraycount(rlimit); i++) {
506abbaa274Smbuhl 
507abbaa274Smbuhl 		ATF_REQUIRE(getrlimit(rlimit[i], &res) == 0);
508abbaa274Smbuhl 
509abbaa274Smbuhl 		if (res.rlim_max == UINT64_MAX) /* Overflow. */
510abbaa274Smbuhl 			continue;
511abbaa274Smbuhl 
512abbaa274Smbuhl 		errno = 0;
513abbaa274Smbuhl 		res.rlim_max = res.rlim_max + 1;
514abbaa274Smbuhl 
515abbaa274Smbuhl 		ATF_CHECK_ERRNO(EPERM, setrlimit(rlimit[i], &res) != 0);
516abbaa274Smbuhl 	}
517abbaa274Smbuhl }
518abbaa274Smbuhl 
519abbaa274Smbuhl ATF_TC(setrlimit_stack);
ATF_TC_HEAD(setrlimit_stack,tc)520abbaa274Smbuhl ATF_TC_HEAD(setrlimit_stack, tc)
521abbaa274Smbuhl {
522abbaa274Smbuhl 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_STACK");
523abbaa274Smbuhl 	atf_tc_set_md_var(tc, "require.user", "unprivileged");
524abbaa274Smbuhl }
525abbaa274Smbuhl 
ATF_TC_BODY(setrlimit_stack,tc)526abbaa274Smbuhl ATF_TC_BODY(setrlimit_stack, tc)
527abbaa274Smbuhl {
528abbaa274Smbuhl 	struct rlimit res;
529abbaa274Smbuhl 
530abbaa274Smbuhl 	/* Ensure soft limit is not bigger than hard limit */
531abbaa274Smbuhl 	res.rlim_cur = res.rlim_max = 6 * 1024 * 1024;
532abbaa274Smbuhl 	ATF_REQUIRE(setrlimit(RLIMIT_STACK, &res) == 0);
533abbaa274Smbuhl 	ATF_REQUIRE(getrlimit(RLIMIT_STACK, &res) == 0);
534abbaa274Smbuhl 	ATF_CHECK(res.rlim_cur <= res.rlim_max);
535abbaa274Smbuhl 
536abbaa274Smbuhl }
537abbaa274Smbuhl 
ATF_TP_ADD_TCS(tp)538abbaa274Smbuhl ATF_TP_ADD_TCS(tp)
539abbaa274Smbuhl {
540abbaa274Smbuhl 
541abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, setrlimit_basic);
542abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, setrlimit_current);
543abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, setrlimit_err);
544abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, setrlimit_fsize);
545abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, setrlimit_memlock);
546abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, setrlimit_nofile_1);
547abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, setrlimit_nofile_2);
548abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, setrlimit_nproc);
549abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, setrlimit_perm);
550abbaa274Smbuhl #ifndef __OpenBSD__
551abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, setrlimit_nthr);
552abbaa274Smbuhl #endif
553abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, setrlimit_stack);
554abbaa274Smbuhl 
555abbaa274Smbuhl 	return atf_no_error();
556abbaa274Smbuhl }
557