xref: /freebsd/contrib/netbsd-tests/lib/libc/sys/t_setrlimit.c (revision 7f9dff23d3092aa33ad45b2b63e52469b3c13a6e)
1 /* $NetBSD: t_setrlimit.c,v 1.5 2016/07/13 09:53:16 njoly 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.5 2016/07/13 09:53:16 njoly 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 #ifdef __NetBSD__
43 #include <lwp.h>
44 #endif
45 #include <signal.h>
46 #include <stdint.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <ucontext.h>
51 #include <unistd.h>
52 
53 #ifdef __FreeBSD__
54 void set_vm_max_wired(int);
55 void restore_vm_max_wired(void);
56 #endif
57 
58 static void		 sighandler(int);
59 static const char	 path[] = "setrlimit";
60 
61 static const int rlimit[] = {
62 	RLIMIT_AS,
63 	RLIMIT_CORE,
64 	RLIMIT_CPU,
65 	RLIMIT_DATA,
66 	RLIMIT_FSIZE,
67 	RLIMIT_MEMLOCK,
68 	RLIMIT_NOFILE,
69 	RLIMIT_NPROC,
70 	RLIMIT_RSS,
71 	RLIMIT_SBSIZE,
72 	RLIMIT_STACK
73 };
74 
75 ATF_TC(setrlimit_basic);
76 ATF_TC_HEAD(setrlimit_basic, tc)
77 {
78 	atf_tc_set_md_var(tc, "descr", "A basic soft limit test");
79 }
80 
81 ATF_TC_BODY(setrlimit_basic, tc)
82 {
83 	struct rlimit res;
84 	int *buf, lim;
85 	size_t i;
86 
87 	buf = calloc(__arraycount(rlimit), sizeof(int));
88 
89 	if (buf == NULL)
90 		atf_tc_fail("initialization failed");
91 
92 	for (i = lim = 0; i < __arraycount(rlimit); i++) {
93 
94 		(void)memset(&res, 0, sizeof(struct rlimit));
95 
96 		if (getrlimit(rlimit[i], &res) != 0)
97 			continue;
98 
99 		if (res.rlim_cur == RLIM_INFINITY || res.rlim_cur == 0)
100 			continue;
101 
102 		if (res.rlim_cur == res.rlim_max) /* An unprivileged run. */
103 			continue;
104 
105 		buf[i] = res.rlim_cur;
106 		res.rlim_cur = res.rlim_cur - 1;
107 
108 		if (setrlimit(rlimit[i], &res) != 0) {
109 			lim = rlimit[i];
110 			goto out;
111 		}
112 	}
113 
114 out:
115 	for (i = 0; i < __arraycount(rlimit); i++) {
116 
117 		(void)memset(&res, 0, sizeof(struct rlimit));
118 
119 		if (buf[i] == 0)
120 			continue;
121 
122 		if (getrlimit(rlimit[i], &res) != 0)
123 			continue;
124 
125 		res.rlim_cur = buf[i];
126 
127 		(void)setrlimit(rlimit[i], &res);
128 	}
129 
130 	if (lim != 0)
131 		atf_tc_fail("failed to set limit (%d)", lim);
132 }
133 
134 ATF_TC(setrlimit_current);
135 ATF_TC_HEAD(setrlimit_current, tc)
136 {
137 	atf_tc_set_md_var(tc, "descr", "setrlimit(3) with current limits");
138 }
139 
140 ATF_TC_BODY(setrlimit_current, tc)
141 {
142 	struct rlimit res;
143 	size_t i;
144 
145 	for (i = 0; i < __arraycount(rlimit); i++) {
146 
147 		(void)memset(&res, 0, sizeof(struct rlimit));
148 
149 		ATF_REQUIRE(getrlimit(rlimit[i], &res) == 0);
150 		ATF_REQUIRE(setrlimit(rlimit[i], &res) == 0);
151 	}
152 }
153 
154 ATF_TC(setrlimit_err);
155 ATF_TC_HEAD(setrlimit_err, tc)
156 {
157 	atf_tc_set_md_var(tc, "descr", "Test error conditions");
158 }
159 
160 ATF_TC_BODY(setrlimit_err, tc)
161 {
162 	struct rlimit res;
163 	size_t i;
164 
165 	for (i = 0; i < __arraycount(rlimit); i++) {
166 
167 		errno = 0;
168 
169 		ATF_REQUIRE(getrlimit(rlimit[i], (void *)0) != 0);
170 		ATF_REQUIRE(errno == EFAULT);
171 	}
172 
173 	errno = 0;
174 
175 	ATF_REQUIRE(getrlimit(INT_MAX, &res) != 0);
176 	ATF_REQUIRE(errno == EINVAL);
177 }
178 
179 ATF_TC_WITH_CLEANUP(setrlimit_fsize);
180 ATF_TC_HEAD(setrlimit_fsize, tc)
181 {
182 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_FSIZE");
183 }
184 
185 ATF_TC_BODY(setrlimit_fsize, tc)
186 {
187 	struct rlimit res;
188 	int fd, sta;
189 	pid_t pid;
190 
191 	fd = open(path, O_RDWR | O_CREAT, 0700);
192 
193 	if (fd < 0)
194 		atf_tc_fail("initialization failed");
195 
196 	pid = fork();
197 	ATF_REQUIRE(pid >= 0);
198 
199 	if (pid == 0) {
200 
201 		res.rlim_cur = 2;
202 		res.rlim_max = 2;
203 
204 		if (setrlimit(RLIMIT_FSIZE, &res) != 0)
205 			_exit(EXIT_FAILURE);
206 
207 		if (signal(SIGXFSZ, sighandler) == SIG_ERR)
208 			_exit(EXIT_FAILURE);
209 
210 		/*
211 		 * The third call should generate a SIGXFSZ.
212 		 */
213 		(void)write(fd, "X", 1);
214 		(void)write(fd, "X", 1);
215 		(void)write(fd, "X", 1);
216 
217 		_exit(EXIT_FAILURE);
218 	}
219 
220 	(void)close(fd);
221 	(void)wait(&sta);
222 	(void)unlink(path);
223 
224 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
225 		atf_tc_fail("RLIMIT_FSIZE not enforced");
226 }
227 
228 ATF_TC_CLEANUP(setrlimit_fsize, tc)
229 {
230 	(void)unlink(path);
231 }
232 
233 static void
234 sighandler(int signo)
235 {
236 
237 	if (signo != SIGXFSZ)
238 		_exit(EXIT_FAILURE);
239 
240 	_exit(EXIT_SUCCESS);
241 }
242 
243 #ifdef __FreeBSD__
244 ATF_TC_WITH_CLEANUP(setrlimit_memlock);
245 #else
246 ATF_TC(setrlimit_memlock);
247 #endif
248 ATF_TC_HEAD(setrlimit_memlock, tc)
249 {
250 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_MEMLOCK");
251 #ifdef __FreeBSD__
252 	atf_tc_set_md_var(tc, "require.config", "allow_sysctl_side_effects");
253 	atf_tc_set_md_var(tc, "require.user", "root");
254 #endif
255 }
256 
257 ATF_TC_BODY(setrlimit_memlock, tc)
258 {
259 	struct rlimit res;
260 	void *buf;
261 	long page;
262 	pid_t pid;
263 	int sta;
264 
265 #ifdef __FreeBSD__
266 	/* Set max_wired really really high to avoid EAGAIN */
267 	set_vm_max_wired(INT_MAX);
268 #endif
269 
270 	page = sysconf(_SC_PAGESIZE);
271 	ATF_REQUIRE(page >= 0);
272 
273 	buf = malloc(page);
274 	pid = fork();
275 
276 	if (buf == NULL || pid < 0)
277 		atf_tc_fail("initialization failed");
278 
279 	if (pid == 0) {
280 
281 		/*
282 		 * Try to lock a page while
283 		 * RLIMIT_MEMLOCK is zero.
284 		 */
285 		if (mlock(buf, page) != 0)
286 			_exit(EXIT_FAILURE);
287 
288 		if (munlock(buf, page) != 0)
289 			_exit(EXIT_FAILURE);
290 
291 		res.rlim_cur = 0;
292 		res.rlim_max = 0;
293 
294 		if (setrlimit(RLIMIT_MEMLOCK, &res) != 0)
295 			_exit(EXIT_FAILURE);
296 
297 		if (mlock(buf, page) != 0)
298 			_exit(EXIT_SUCCESS);
299 
300 		(void)munlock(buf, page);
301 
302 		_exit(EXIT_FAILURE);
303 	}
304 
305 	free(buf);
306 
307 	(void)wait(&sta);
308 
309 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
310 		atf_tc_fail("RLIMIT_MEMLOCK not enforced");
311 }
312 
313 #ifdef __FreeBSD__
314 ATF_TC_CLEANUP(setrlimit_memlock, tc)
315 {
316 
317 	restore_vm_max_wired();
318 }
319 #endif
320 
321 ATF_TC(setrlimit_nofile_1);
322 ATF_TC_HEAD(setrlimit_nofile_1, tc)
323 {
324 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NOFILE, #1");
325 }
326 
327 ATF_TC_BODY(setrlimit_nofile_1, tc)
328 {
329 	struct rlimit res;
330 	int fd, i, rv, sta;
331 	pid_t pid;
332 
333 	res.rlim_cur = 0;
334 	res.rlim_max = 0;
335 
336 	pid = fork();
337 	ATF_REQUIRE(pid >= 0);
338 
339 	if (pid == 0) {
340 
341 		/*
342 		 * Close all descriptors, set RLIMIT_NOFILE
343 		 * to zero, and try to open a random file.
344 		 * This should fail with EMFILE.
345 		 */
346 		for (i = 0; i < 1024; i++)
347 			(void)close(i);
348 
349 		rv = setrlimit(RLIMIT_NOFILE, &res);
350 
351 		if (rv != 0)
352 			_exit(EXIT_FAILURE);
353 
354 		errno = 0;
355 		fd = open("/etc/passwd", O_RDONLY);
356 
357 		if (fd >= 0 || errno != EMFILE)
358 			_exit(EXIT_FAILURE);
359 
360 		_exit(EXIT_SUCCESS);
361 	}
362 
363 	(void)wait(&sta);
364 
365 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
366 		atf_tc_fail("RLIMIT_NOFILE not enforced");
367 }
368 
369 ATF_TC(setrlimit_nofile_2);
370 ATF_TC_HEAD(setrlimit_nofile_2, tc)
371 {
372 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NOFILE, #2");
373 }
374 
375 ATF_TC_BODY(setrlimit_nofile_2, tc)
376 {
377 	static const rlim_t lim = 12;
378 	struct rlimit res;
379 	int fd, i, rv, sta;
380 	pid_t pid;
381 
382 	/*
383 	 * See that an arbitrary limit on
384 	 * open files is being enforced.
385 	 */
386 	res.rlim_cur = lim;
387 	res.rlim_max = lim;
388 
389 	pid = fork();
390 	ATF_REQUIRE(pid >= 0);
391 
392 	if (pid == 0) {
393 
394 		for (i = 0; i < 1024; i++)
395 			(void)close(i);
396 
397 		rv = setrlimit(RLIMIT_NOFILE, &res);
398 
399 		if (rv != 0)
400 			_exit(EXIT_FAILURE);
401 
402 		for (i = 0; i < (int)lim; i++) {
403 
404 			fd = open("/etc/passwd", O_RDONLY);
405 
406 			if (fd < 0)
407 				_exit(EXIT_FAILURE);
408 		}
409 
410 		/*
411 		 * After the limit has been reached,
412 		 * EMFILE should again follow.
413 		 */
414 		fd = open("/etc/passwd", O_RDONLY);
415 
416 		if (fd >= 0 || errno != EMFILE)
417 			_exit(EXIT_FAILURE);
418 
419 		_exit(EXIT_SUCCESS);
420 	}
421 
422 	(void)wait(&sta);
423 
424 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
425 		atf_tc_fail("RLIMIT_NOFILE not enforced");
426 }
427 
428 ATF_TC(setrlimit_nproc);
429 ATF_TC_HEAD(setrlimit_nproc, tc)
430 {
431 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NPROC");
432 	atf_tc_set_md_var(tc, "require.user", "unprivileged");
433 }
434 
435 ATF_TC_BODY(setrlimit_nproc, tc)
436 {
437 	struct rlimit res;
438 	pid_t pid, cpid;
439 	int sta;
440 
441 	pid = fork();
442 	ATF_REQUIRE(pid >= 0);
443 
444 	if (pid == 0) {
445 
446 		/*
447 		 * Set RLIMIT_NPROC to zero and try to fork.
448 		 */
449 		res.rlim_cur = 0;
450 		res.rlim_max = 0;
451 
452 		if (setrlimit(RLIMIT_NPROC, &res) != 0)
453 			_exit(EXIT_FAILURE);
454 
455 		cpid = fork();
456 
457 		if (cpid < 0)
458 			_exit(EXIT_SUCCESS);
459 
460 		_exit(EXIT_FAILURE);
461 	}
462 
463 	(void)waitpid(pid, &sta, 0);
464 
465 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
466 		atf_tc_fail("RLIMIT_NPROC not enforced");
467 }
468 
469 #ifdef __NetBSD__
470 ATF_TC(setrlimit_nthr);
471 ATF_TC_HEAD(setrlimit_nthr, tc)
472 {
473 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NTHR");
474 	atf_tc_set_md_var(tc, "require.user", "unprivileged");
475 }
476 
477 static void
478 func(lwpid_t *id)
479 {
480 	printf("thread %d\n", *id);
481 	fflush(stdout);
482 	_lwp_exit();
483 }
484 
485 ATF_TC_BODY(setrlimit_nthr, tc)
486 {
487 	struct rlimit res;
488 	lwpid_t lwpid;
489 	ucontext_t c;
490 
491 	/*
492 	 * Set RLIMIT_NTHR to zero and try to create a thread.
493 	 */
494 	res.rlim_cur = 0;
495 	res.rlim_max = 0;
496 	ATF_REQUIRE(setrlimit(RLIMIT_NTHR, &res) == 0);
497 	ATF_REQUIRE(getcontext(&c) == 0);
498 	c.uc_link = NULL;
499 	sigemptyset(&c.uc_sigmask);
500 	c.uc_stack.ss_flags = 0;
501 	c.uc_stack.ss_size = 4096;
502 	ATF_REQUIRE((c.uc_stack.ss_sp = malloc(c.uc_stack.ss_size)) != NULL);
503 	makecontext(&c, func, 1, &lwpid);
504 	ATF_CHECK_ERRNO(EAGAIN, _lwp_create(&c, 0, &lwpid) == -1);
505 }
506 #endif
507 
508 ATF_TC(setrlimit_perm);
509 ATF_TC_HEAD(setrlimit_perm, tc)
510 {
511 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2) for EPERM");
512 	atf_tc_set_md_var(tc, "require.user", "unprivileged");
513 }
514 
515 ATF_TC_BODY(setrlimit_perm, tc)
516 {
517 	struct rlimit res;
518 	size_t i;
519 
520 	/*
521 	 * Try to raise the maximum limits as an user.
522 	 */
523 	for (i = 0; i < __arraycount(rlimit); i++) {
524 
525 		ATF_REQUIRE(getrlimit(rlimit[i], &res) == 0);
526 
527 #ifdef __FreeBSD__
528 		if (res.rlim_max == INT64_MAX) /* Overflow. */
529 #else
530 		if (res.rlim_max == UINT64_MAX) /* Overflow. */
531 #endif
532 			continue;
533 
534 		errno = 0;
535 		res.rlim_max = res.rlim_max + 1;
536 
537 		ATF_CHECK_ERRNO(EPERM, setrlimit(rlimit[i], &res) != 0);
538 	}
539 }
540 
541 ATF_TC(setrlimit_stack);
542 ATF_TC_HEAD(setrlimit_stack, tc)
543 {
544 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_STACK");
545 	atf_tc_set_md_var(tc, "require.user", "unprivileged");
546 }
547 
548 ATF_TC_BODY(setrlimit_stack, tc)
549 {
550 	struct rlimit res;
551 
552 	/* Ensure soft limit is not bigger than hard limit */
553 	res.rlim_cur = res.rlim_max = 4192256;
554 	ATF_REQUIRE(setrlimit(RLIMIT_STACK, &res) == 0);
555 	ATF_REQUIRE(getrlimit(RLIMIT_STACK, &res) == 0);
556 	ATF_CHECK(res.rlim_cur <= res.rlim_max);
557 
558 }
559 
560 ATF_TP_ADD_TCS(tp)
561 {
562 
563 	ATF_TP_ADD_TC(tp, setrlimit_basic);
564 	ATF_TP_ADD_TC(tp, setrlimit_current);
565 	ATF_TP_ADD_TC(tp, setrlimit_err);
566 	ATF_TP_ADD_TC(tp, setrlimit_fsize);
567 	ATF_TP_ADD_TC(tp, setrlimit_memlock);
568 	ATF_TP_ADD_TC(tp, setrlimit_nofile_1);
569 	ATF_TP_ADD_TC(tp, setrlimit_nofile_2);
570 	ATF_TP_ADD_TC(tp, setrlimit_nproc);
571 	ATF_TP_ADD_TC(tp, setrlimit_perm);
572 #ifdef __NetBSD__
573 	ATF_TP_ADD_TC(tp, setrlimit_nthr);
574 #endif
575 	ATF_TP_ADD_TC(tp, setrlimit_stack);
576 
577 	return atf_no_error();
578 }
579