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