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