1139743Simp/* $NetBSD: t_setrlimit.c,v 1.6 2017/01/13 21:16:38 christos Exp $ */
2123474Swpaul
3123474Swpaul/*-
4123474Swpaul * Copyright (c) 2011 The NetBSD Foundation, Inc.
5123474Swpaul * All rights reserved.
6123474Swpaul *
7123474Swpaul * This code is derived from software contributed to The NetBSD Foundation
8123474Swpaul * by Jukka Ruohonen.
9123474Swpaul *
10123474Swpaul * Redistribution and use in source and binary forms, with or without
11123474Swpaul * modification, are permitted provided that the following conditions
12123474Swpaul * are met:
13123474Swpaul * 1. Redistributions of source code must retain the above copyright
14123474Swpaul *    notice, this list of conditions and the following disclaimer.
15123474Swpaul * 2. Redistributions in binary form must reproduce the above copyright
16123474Swpaul *    notice, this list of conditions and the following disclaimer in the
17123474Swpaul *    documentation and/or other materials provided with the distribution.
18123474Swpaul *
19123474Swpaul * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20123474Swpaul * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21123474Swpaul * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22123474Swpaul * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23123474Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24123474Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25123474Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26123474Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27123474Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28123474Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29123474Swpaul * POSSIBILITY OF SUCH DAMAGE.
30123474Swpaul */
31123474Swpaul#include <sys/cdefs.h>
32123474Swpaul__RCSID("$NetBSD: t_setrlimit.c,v 1.6 2017/01/13 21:16:38 christos Exp $");
33123474Swpaul
34123474Swpaul#include <sys/resource.h>
35123474Swpaul#include <sys/mman.h>
36123474Swpaul#include <sys/wait.h>
37123474Swpaul
38123474Swpaul#include <atf-c.h>
39123474Swpaul#include <errno.h>
40123474Swpaul#include <fcntl.h>
41123474Swpaul#include <limits.h>
42123474Swpaul#ifdef __NetBSD__
43123474Swpaul#include <lwp.h>
44123474Swpaul#endif
45123474Swpaul#include <signal.h>
46123474Swpaul#include <stdint.h>
47123474Swpaul#include <stdio.h>
48123474Swpaul#include <stdlib.h>
49123474Swpaul#include <string.h>
50123474Swpaul#include <ucontext.h>
51123474Swpaul#include <unistd.h>
52129834Swpaul
53123474Swpaul#ifdef __FreeBSD__
54123474Swpaulvoid set_vm_max_wired(int);
55123474Swpaulvoid restore_vm_max_wired(void);
56123474Swpaul#endif
57123474Swpaul
58123474Swpaulstatic void		 sighandler(int);
59123474Swpaulstatic const char	 path[] = "setrlimit";
60123474Swpaul
61123474Swpaulstatic const int rlimit[] = {
62123474Swpaul	RLIMIT_AS,
63123474Swpaul	RLIMIT_CORE,
64123474Swpaul	RLIMIT_CPU,
65123504Swpaul	RLIMIT_DATA,
66123848Swpaul	RLIMIT_FSIZE,
67124122Swpaul	RLIMIT_MEMLOCK,
68124272Swpaul	RLIMIT_NOFILE,
69125377Swpaul	RLIMIT_NPROC,
70124272Swpaul	RLIMIT_RSS,
71124272Swpaul	RLIMIT_SBSIZE,
72124272Swpaul	RLIMIT_STACK
73125551Swpaul};
74132973Swpaul
75132973SwpaulATF_TC(setrlimit_basic);
76132973SwpaulATF_TC_HEAD(setrlimit_basic, tc)
77123474Swpaul{
78123474Swpaul	atf_tc_set_md_var(tc, "descr", "A basic soft limit test");
79123474Swpaul}
80123474Swpaul
81123474SwpaulATF_TC_BODY(setrlimit_basic, tc)
82123474Swpaul{
83123474Swpaul	struct rlimit res;
84124203Swpaul	int *buf, lim;
85123474Swpaul	size_t i;
86123474Swpaul
87123474Swpaul	buf = calloc(__arraycount(rlimit), sizeof(int));
88123474Swpaul
89123474Swpaul	if (buf == NULL)
90123474Swpaul		atf_tc_fail("initialization failed");
91123474Swpaul
92123474Swpaul	for (i = lim = 0; i < __arraycount(rlimit); i++) {
93123474Swpaul
94123474Swpaul		(void)memset(&res, 0, sizeof(struct rlimit));
95123695Swpaul
96123695Swpaul		if (getrlimit(rlimit[i], &res) != 0)
97123695Swpaul			continue;
98123474Swpaul
99123474Swpaul		if (res.rlim_cur == RLIM_INFINITY || res.rlim_cur == 0)
100123474Swpaul			continue;
101123474Swpaul
102145485Swpaul		if (res.rlim_cur == res.rlim_max) /* An unprivileged run. */
103123474Swpaul			continue;
104123512Swpaul
105128229Swpaul		buf[i] = res.rlim_cur;
106123474Swpaul		res.rlim_cur = res.rlim_cur - 1;
107123474Swpaul
108123474Swpaul		if (setrlimit(rlimit[i], &res) != 0) {
109124272Swpaul			lim = rlimit[i];
110125057Swpaul			goto out;
111123474Swpaul		}
112124272Swpaul	}
113124272Swpaul
114124272Swpaulout:
115144888Swpaul	for (i = 0; i < __arraycount(rlimit); i++) {
116141524Swpaul
117144888Swpaul		(void)memset(&res, 0, sizeof(struct rlimit));
118123474Swpaul
119144888Swpaul		if (buf[i] == 0)
120140751Swpaul			continue;
121144888Swpaul
122123474Swpaul		if (getrlimit(rlimit[i], &res) != 0)
123144888Swpaul			continue;
124144888Swpaul
125123474Swpaul		res.rlim_cur = buf[i];
126144888Swpaul
127140751Swpaul		(void)setrlimit(rlimit[i], &res);
128144888Swpaul	}
129140751Swpaul
130144888Swpaul	if (lim != 0)
131140751Swpaul		atf_tc_fail("failed to set limit (%d)", lim);
132123474Swpaul	free(buf);
133123474Swpaul}
134123526Swpaul
135123526SwpaulATF_TC(setrlimit_current);
136144888SwpaulATF_TC_HEAD(setrlimit_current, tc)
137123474Swpaul{
138144888Swpaul	atf_tc_set_md_var(tc, "descr", "setrlimit(3) with current limits");
139123526Swpaul}
140144888Swpaul
141144888SwpaulATF_TC_BODY(setrlimit_current, tc)
142144888Swpaul{
143144888Swpaul	struct rlimit res;
144144888Swpaul	size_t i;
145144888Swpaul
146144888Swpaul	for (i = 0; i < __arraycount(rlimit); i++) {
147145895Swpaul
148145895Swpaul		(void)memset(&res, 0, sizeof(struct rlimit));
149145895Swpaul
150145895Swpaul		ATF_REQUIRE(getrlimit(rlimit[i], &res) == 0);
151144888Swpaul		ATF_REQUIRE(setrlimit(rlimit[i], &res) == 0);
152123474Swpaul	}
153144888Swpaul}
154123474Swpaul
155140751SwpaulATF_TC(setrlimit_err);
156123474SwpaulATF_TC_HEAD(setrlimit_err, tc)
157144888Swpaul{
158140751Swpaul	atf_tc_set_md_var(tc, "descr", "Test error conditions");
159144888Swpaul}
160140751Swpaul
161144888SwpaulATF_TC_BODY(setrlimit_err, tc)
162123474Swpaul{
163144888Swpaul	struct rlimit res;
164125057Swpaul	size_t i;
165144888Swpaul
166144888Swpaul	for (i = 0; i < __arraycount(rlimit); i++) {
167144888Swpaul
168144888Swpaul		errno = 0;
169144174Swpaul
170144888Swpaul		ATF_REQUIRE(getrlimit(rlimit[i], (void *)0) != 0);
171123474Swpaul		ATF_REQUIRE(errno == EFAULT);
172144888Swpaul	}
173123474Swpaul
174144888Swpaul	errno = 0;
175123474Swpaul
176144888Swpaul	ATF_REQUIRE(getrlimit(INT_MAX, &res) != 0);
177123474Swpaul	ATF_REQUIRE(errno == EINVAL);
178144888Swpaul}
179144888Swpaul
180123474SwpaulATF_TC_WITH_CLEANUP(setrlimit_fsize);
181144888SwpaulATF_TC_HEAD(setrlimit_fsize, tc)
182123474Swpaul{
183144888Swpaul	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_FSIZE");
184123474Swpaul}
185145895Swpaul
186144888SwpaulATF_TC_BODY(setrlimit_fsize, tc)
187123474Swpaul{
188144888Swpaul	struct rlimit res;
189123474Swpaul	int fd, sta;
190144888Swpaul	pid_t pid;
191123474Swpaul
192144888Swpaul	fd = open(path, O_RDWR | O_CREAT, 0700);
193144888Swpaul
194144888Swpaul	if (fd < 0)
195144888Swpaul		atf_tc_fail("initialization failed");
196123474Swpaul
197144888Swpaul	pid = fork();
198144888Swpaul	ATF_REQUIRE(pid >= 0);
199144888Swpaul
200123474Swpaul	if (pid == 0) {
201144888Swpaul
202144888Swpaul		res.rlim_cur = 2;
203123474Swpaul		res.rlim_max = 2;
204144888Swpaul
205144888Swpaul		if (setrlimit(RLIMIT_FSIZE, &res) != 0)
206144888Swpaul			_exit(EXIT_FAILURE);
207144888Swpaul
208123474Swpaul		if (signal(SIGXFSZ, sighandler) == SIG_ERR)
209144888Swpaul			_exit(EXIT_FAILURE);
210144888Swpaul
211144888Swpaul		/*
212144888Swpaul		 * The third call should generate a SIGXFSZ.
213144888Swpaul		 */
214144888Swpaul		(void)write(fd, "X", 1);
215144888Swpaul		(void)write(fd, "X", 1);
216144888Swpaul		(void)write(fd, "X", 1);
217144888Swpaul
218144888Swpaul		_exit(EXIT_FAILURE);
219123474Swpaul	}
220144888Swpaul
221140751Swpaul	(void)close(fd);
222123526Swpaul	(void)wait(&sta);
223144888Swpaul	(void)unlink(path);
224123474Swpaul
225144888Swpaul	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
226123474Swpaul		atf_tc_fail("RLIMIT_FSIZE not enforced");
227123474Swpaul}
228144888Swpaul
229144888SwpaulATF_TC_CLEANUP(setrlimit_fsize, tc)
230123474Swpaul{
231144888Swpaul	(void)unlink(path);
232144888Swpaul}
233144888Swpaul
234140751Swpaulstatic void
235144888Swpaulsighandler(int signo)
236123474Swpaul{
237144888Swpaul
238144888Swpaul	if (signo != SIGXFSZ)
239123474Swpaul		_exit(EXIT_FAILURE);
240144888Swpaul
241123474Swpaul	_exit(EXIT_SUCCESS);
242144888Swpaul}
243125551Swpaul
244144888Swpaul#ifdef __FreeBSD__
245123474SwpaulATF_TC_WITH_CLEANUP(setrlimit_memlock);
246144888Swpaul#else
247125551SwpaulATF_TC(setrlimit_memlock);
248144888Swpaul#endif
249140751SwpaulATF_TC_HEAD(setrlimit_memlock, tc)
250123474Swpaul{
251144888Swpaul	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_MEMLOCK");
252144888Swpaul#ifdef __FreeBSD__
253144888Swpaul	atf_tc_set_md_var(tc, "require.config", "allow_sysctl_side_effects");
254144888Swpaul	atf_tc_set_md_var(tc, "require.user", "root");
255144888Swpaul#endif
256123941Swpaul}
257144888Swpaul
258144888SwpaulATF_TC_BODY(setrlimit_memlock, tc)
259144888Swpaul{
260144888Swpaul	struct rlimit res;
261125551Swpaul	void *buf;
262125551Swpaul	long page;
263144888Swpaul	pid_t pid;
264140751Swpaul	int sta;
265144888Swpaul
266140751Swpaul#ifdef __FreeBSD__
267132973Swpaul	/* Set max_wired really really high to avoid EAGAIN */
268144888Swpaul	set_vm_max_wired(INT_MAX);
269123822Swpaul#endif
270144888Swpaul
271144888Swpaul	page = sysconf(_SC_PAGESIZE);
272144888Swpaul	ATF_REQUIRE(page >= 0);
273144888Swpaul
274144888Swpaul	buf = malloc(page);
275144888Swpaul	pid = fork();
276124116Swpaul
277144402Swpaul	if (buf == NULL || pid < 0)
278144888Swpaul		atf_tc_fail("initialization failed");
279140751Swpaul
280144888Swpaul	if (pid == 0) {
281140751Swpaul
282144888Swpaul		/*
283125551Swpaul		 * Try to lock a page while
284125551Swpaul		 * RLIMIT_MEMLOCK is zero.
285144888Swpaul		 */
286144888Swpaul		if (mlock(buf, page) != 0)
287140751Swpaul			_exit(EXIT_FAILURE);
288125551Swpaul
289144888Swpaul		if (munlock(buf, page) != 0)
290144888Swpaul			_exit(EXIT_FAILURE);
291123474Swpaul
292124116Swpaul		res.rlim_cur = 0;
293124116Swpaul		res.rlim_max = 0;
294124116Swpaul
295124116Swpaul		if (setrlimit(RLIMIT_MEMLOCK, &res) != 0)
296124116Swpaul			_exit(EXIT_FAILURE);
297124116Swpaul
298124116Swpaul		if (mlock(buf, page) != 0)
299124116Swpaul			_exit(EXIT_SUCCESS);
300124116Swpaul
301123474Swpaul		(void)munlock(buf, page);
302123474Swpaul
303123474Swpaul		_exit(EXIT_FAILURE);
304123474Swpaul	}
305141963Swpaul
306141963Swpaul	free(buf);
307124272Swpaul
308141963Swpaul	(void)wait(&sta);
309141963Swpaul
310141963Swpaul	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
311141963Swpaul		atf_tc_fail("RLIMIT_MEMLOCK not enforced");
312144888Swpaul}
313144888Swpaul
314141963Swpaul#ifdef __FreeBSD__
315141963SwpaulATF_TC_CLEANUP(setrlimit_memlock, tc)
316141963Swpaul{
317123474Swpaul
318123474Swpaul	restore_vm_max_wired();
319123474Swpaul}
320123474Swpaul#endif
321123474Swpaul
322123474SwpaulATF_TC(setrlimit_nofile_1);
323141963SwpaulATF_TC_HEAD(setrlimit_nofile_1, tc)
324141963Swpaul{
325141963Swpaul	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NOFILE, #1");
326141963Swpaul}
327141963Swpaul
328141963SwpaulATF_TC_BODY(setrlimit_nofile_1, tc)
329141963Swpaul{
330141963Swpaul	struct rlimit res;
331123474Swpaul	int fd, i, rv, sta;
332123474Swpaul	pid_t pid;
333123474Swpaul
334144402Swpaul	res.rlim_cur = 0;
335144402Swpaul	res.rlim_max = 0;
336144402Swpaul
337144402Swpaul	pid = fork();
338144402Swpaul	ATF_REQUIRE(pid >= 0);
339144402Swpaul
340144428Swpaul	if (pid == 0) {
341144402Swpaul
342144402Swpaul		/*
343144402Swpaul		 * Close all descriptors, set RLIMIT_NOFILE
344144402Swpaul		 * to zero, and try to open a random file.
345144402Swpaul		 * This should fail with EMFILE.
346144402Swpaul		 */
347144402Swpaul		for (i = 0; i < 1024; i++)
348144402Swpaul			(void)close(i);
349144402Swpaul
350123474Swpaul		rv = setrlimit(RLIMIT_NOFILE, &res);
351123474Swpaul
352123474Swpaul		if (rv != 0)
353123474Swpaul			_exit(EXIT_FAILURE);
354123474Swpaul
355123474Swpaul		errno = 0;
356123474Swpaul		fd = open("/etc/passwd", O_RDONLY);
357123474Swpaul
358123474Swpaul		if (fd >= 0 || errno != EMFILE)
359123474Swpaul			_exit(EXIT_FAILURE);
360123474Swpaul
361123474Swpaul		_exit(EXIT_SUCCESS);
362123474Swpaul	}
363123474Swpaul
364123474Swpaul	(void)wait(&sta);
365123474Swpaul
366144174Swpaul	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
367123474Swpaul		atf_tc_fail("RLIMIT_NOFILE not enforced");
368123474Swpaul}
369123474Swpaul
370123474SwpaulATF_TC(setrlimit_nofile_2);
371123474SwpaulATF_TC_HEAD(setrlimit_nofile_2, tc)
372123474Swpaul{
373123474Swpaul	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NOFILE, #2");
374123474Swpaul}
375123474Swpaul
376123474SwpaulATF_TC_BODY(setrlimit_nofile_2, tc)
377123474Swpaul{
378123474Swpaul	static const rlim_t lim = 12;
379123474Swpaul	struct rlimit res;
380123474Swpaul	int fd, i, rv, sta;
381123474Swpaul	pid_t pid;
382123474Swpaul
383123474Swpaul	/*
384123474Swpaul	 * See that an arbitrary limit on
385123474Swpaul	 * open files is being enforced.
386123474Swpaul	 */
387123474Swpaul	res.rlim_cur = lim;
388123474Swpaul	res.rlim_max = lim;
389144174Swpaul
390123474Swpaul	pid = fork();
391123474Swpaul	ATF_REQUIRE(pid >= 0);
392123474Swpaul
393124100Swpaul	if (pid == 0) {
394123474Swpaul
395123474Swpaul		for (i = 0; i < 1024; i++)
396123474Swpaul			(void)close(i);
397123474Swpaul
398123474Swpaul		rv = setrlimit(RLIMIT_NOFILE, &res);
399123474Swpaul
400123474Swpaul		if (rv != 0)
401141524Swpaul			_exit(EXIT_FAILURE);
402141524Swpaul
403141524Swpaul		for (i = 0; i < (int)lim; i++) {
404141524Swpaul
405141524Swpaul			fd = open("/etc/passwd", O_RDONLY);
406144888Swpaul
407141524Swpaul			if (fd < 0)
408125551Swpaul				_exit(EXIT_FAILURE);
409141524Swpaul		}
410123474Swpaul
411123474Swpaul		/*
412123474Swpaul		 * After the limit has been reached,
413141524Swpaul		 * EMFILE should again follow.
414141524Swpaul		 */
415141524Swpaul		fd = open("/etc/passwd", O_RDONLY);
416141524Swpaul
417141524Swpaul		if (fd >= 0 || errno != EMFILE)
418141524Swpaul			_exit(EXIT_FAILURE);
419141524Swpaul
420141524Swpaul		_exit(EXIT_SUCCESS);
421141524Swpaul	}
422123474Swpaul
423141524Swpaul	(void)wait(&sta);
424123474Swpaul
425141524Swpaul	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
426141524Swpaul		atf_tc_fail("RLIMIT_NOFILE not enforced");
427141524Swpaul}
428141524Swpaul
429141524SwpaulATF_TC(setrlimit_nproc);
430141524SwpaulATF_TC_HEAD(setrlimit_nproc, tc)
431141524Swpaul{
432141524Swpaul	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NPROC");
433141524Swpaul	atf_tc_set_md_var(tc, "require.user", "unprivileged");
434141524Swpaul}
435123474Swpaul
436123474SwpaulATF_TC_BODY(setrlimit_nproc, tc)
437123474Swpaul{
438144888Swpaul	struct rlimit res;
439140751Swpaul	pid_t pid, cpid;
440123526Swpaul	int sta;
441123526Swpaul
442123526Swpaul	pid = fork();
443141524Swpaul	ATF_REQUIRE(pid >= 0);
444123526Swpaul
445123526Swpaul	if (pid == 0) {
446123526Swpaul
447144888Swpaul		/*
448140751Swpaul		 * Set RLIMIT_NPROC to zero and try to fork.
449123474Swpaul		 */
450123474Swpaul		res.rlim_cur = 0;
451123474Swpaul		res.rlim_max = 0;
452123474Swpaul
453141524Swpaul		if (setrlimit(RLIMIT_NPROC, &res) != 0)
454141524Swpaul			_exit(EXIT_FAILURE);
455123474Swpaul
456141524Swpaul		cpid = fork();
457141524Swpaul
458141524Swpaul		if (cpid < 0)
459141524Swpaul			_exit(EXIT_SUCCESS);
460141524Swpaul
461141524Swpaul		_exit(EXIT_FAILURE);
462141524Swpaul	}
463141524Swpaul
464141524Swpaul	(void)waitpid(pid, &sta, 0);
465141524Swpaul
466141524Swpaul	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
467141524Swpaul		atf_tc_fail("RLIMIT_NPROC not enforced");
468141524Swpaul}
469141524Swpaul
470141524Swpaul#ifdef __NetBSD__
471141524SwpaulATF_TC(setrlimit_nthr);
472141524SwpaulATF_TC_HEAD(setrlimit_nthr, tc)
473141524Swpaul{
474141524Swpaul	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NTHR");
475141524Swpaul	atf_tc_set_md_var(tc, "require.user", "unprivileged");
476141524Swpaul}
477141524Swpaul
478141524Swpaulstatic void
479141524Swpaulfunc(lwpid_t *id)
480141524Swpaul{
481125551Swpaul	printf("thread %d\n", *id);
482125551Swpaul	fflush(stdout);
483123474Swpaul	_lwp_exit();
484123474Swpaul}
485123474Swpaul
486144888SwpaulATF_TC_BODY(setrlimit_nthr, tc)
487140751Swpaul{
488123474Swpaul	struct rlimit res;
489123474Swpaul	lwpid_t lwpid;
490123474Swpaul	ucontext_t c;
491123474Swpaul
492123474Swpaul	/*
493123474Swpaul	 * Set RLIMIT_NTHR to zero and try to create a thread.
494141963Swpaul	 */
495141524Swpaul	res.rlim_cur = 0;
496123474Swpaul	res.rlim_max = 0;
497123474Swpaul	ATF_REQUIRE(setrlimit(RLIMIT_NTHR, &res) == 0);
498123474Swpaul	ATF_REQUIRE(getcontext(&c) == 0);
499123474Swpaul	c.uc_link = NULL;
500123474Swpaul	sigemptyset(&c.uc_sigmask);
501123474Swpaul	c.uc_stack.ss_flags = 0;
502123474Swpaul	c.uc_stack.ss_size = 4096;
503144888Swpaul	ATF_REQUIRE((c.uc_stack.ss_sp = malloc(c.uc_stack.ss_size)) != NULL);
504140751Swpaul	makecontext(&c, func, 1, &lwpid);
505123474Swpaul	ATF_CHECK_ERRNO(EAGAIN, _lwp_create(&c, 0, &lwpid) == -1);
506123474Swpaul}
507123474Swpaul#endif
508123474Swpaul
509123474SwpaulATF_TC(setrlimit_perm);
510123474SwpaulATF_TC_HEAD(setrlimit_perm, tc)
511123474Swpaul{
512141524Swpaul	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2) for EPERM");
513123474Swpaul	atf_tc_set_md_var(tc, "require.user", "unprivileged");
514123474Swpaul}
515123474Swpaul
516123474SwpaulATF_TC_BODY(setrlimit_perm, tc)
517123474Swpaul{
518123474Swpaul	struct rlimit res;
519123474Swpaul	size_t i;
520144888Swpaul
521140751Swpaul	/*
522123474Swpaul	 * Try to raise the maximum limits as an user.
523123474Swpaul	 */
524123474Swpaul	for (i = 0; i < __arraycount(rlimit); i++) {
525123474Swpaul
526123474Swpaul		ATF_REQUIRE(getrlimit(rlimit[i], &res) == 0);
527123474Swpaul
528125551Swpaul#ifdef __FreeBSD__
529141524Swpaul		if (res.rlim_max == INT64_MAX) /* Overflow. */
530141524Swpaul#else
531123474Swpaul		if (res.rlim_max == UINT64_MAX) /* Overflow. */
532123474Swpaul#endif
533123474Swpaul			continue;
534144888Swpaul
535140751Swpaul		errno = 0;
536123474Swpaul		res.rlim_max = res.rlim_max + 1;
537123474Swpaul
538123474Swpaul		ATF_CHECK_ERRNO(EPERM, setrlimit(rlimit[i], &res) != 0);
539123474Swpaul	}
540123474Swpaul}
541123474Swpaul
542123474SwpaulATF_TC(setrlimit_stack);
543123474SwpaulATF_TC_HEAD(setrlimit_stack, tc)
544123474Swpaul{
545123474Swpaul	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_STACK");
546123474Swpaul	atf_tc_set_md_var(tc, "require.user", "unprivileged");
547123474Swpaul}
548123474Swpaul
549123474SwpaulATF_TC_BODY(setrlimit_stack, tc)
550123474Swpaul{
551123474Swpaul	struct rlimit res;
552126833Swpaul
553123474Swpaul	/* Ensure soft limit is not bigger than hard limit */
554123474Swpaul	res.rlim_cur = res.rlim_max = 4192256;
555123474Swpaul	ATF_REQUIRE(setrlimit(RLIMIT_STACK, &res) == 0);
556123474Swpaul	ATF_REQUIRE(getrlimit(RLIMIT_STACK, &res) == 0);
557144888Swpaul	ATF_CHECK(res.rlim_cur <= res.rlim_max);
558140751Swpaul
559123474Swpaul}
560123474Swpaul
561123474SwpaulATF_TP_ADD_TCS(tp)
562123474Swpaul{
563123474Swpaul
564123474Swpaul	ATF_TP_ADD_TC(tp, setrlimit_basic);
565141524Swpaul	ATF_TP_ADD_TC(tp, setrlimit_current);
566123474Swpaul	ATF_TP_ADD_TC(tp, setrlimit_err);
567123474Swpaul	ATF_TP_ADD_TC(tp, setrlimit_fsize);
568123474Swpaul	ATF_TP_ADD_TC(tp, setrlimit_memlock);
569144888Swpaul	ATF_TP_ADD_TC(tp, setrlimit_nofile_1);
570140751Swpaul	ATF_TP_ADD_TC(tp, setrlimit_nofile_2);
571123526Swpaul	ATF_TP_ADD_TC(tp, setrlimit_nproc);
572123526Swpaul	ATF_TP_ADD_TC(tp, setrlimit_perm);
573123526Swpaul#ifdef __NetBSD__
574123526Swpaul	ATF_TP_ADD_TC(tp, setrlimit_nthr);
575123526Swpaul#endif
576123526Swpaul	ATF_TP_ADD_TC(tp, setrlimit_stack);
577123526Swpaul
578145895Swpaul	return atf_no_error();
579123526Swpaul}
580123526Swpaul