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