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