xref: /freebsd/contrib/netbsd-tests/lib/libc/sys/t_setrlimit.c (revision 7bd2df8c82e863396ae96ad4c43418c762e9f702)
1*63d1fd59SEnji Cooper /* $NetBSD: t_setrlimit.c,v 1.6 2017/01/13 21:16:38 christos Exp $ */
257718be8SEnji Cooper 
357718be8SEnji Cooper /*-
457718be8SEnji Cooper  * Copyright (c) 2011 The NetBSD Foundation, Inc.
557718be8SEnji Cooper  * All rights reserved.
657718be8SEnji Cooper  *
757718be8SEnji Cooper  * This code is derived from software contributed to The NetBSD Foundation
857718be8SEnji Cooper  * by Jukka Ruohonen.
957718be8SEnji Cooper  *
1057718be8SEnji Cooper  * Redistribution and use in source and binary forms, with or without
1157718be8SEnji Cooper  * modification, are permitted provided that the following conditions
1257718be8SEnji Cooper  * are met:
1357718be8SEnji Cooper  * 1. Redistributions of source code must retain the above copyright
1457718be8SEnji Cooper  *    notice, this list of conditions and the following disclaimer.
1557718be8SEnji Cooper  * 2. Redistributions in binary form must reproduce the above copyright
1657718be8SEnji Cooper  *    notice, this list of conditions and the following disclaimer in the
1757718be8SEnji Cooper  *    documentation and/or other materials provided with the distribution.
1857718be8SEnji Cooper  *
1957718be8SEnji Cooper  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2057718be8SEnji Cooper  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2157718be8SEnji Cooper  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2257718be8SEnji Cooper  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2357718be8SEnji Cooper  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2457718be8SEnji Cooper  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2557718be8SEnji Cooper  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2657718be8SEnji Cooper  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2757718be8SEnji Cooper  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2857718be8SEnji Cooper  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2957718be8SEnji Cooper  * POSSIBILITY OF SUCH DAMAGE.
3057718be8SEnji Cooper  */
3157718be8SEnji Cooper #include <sys/cdefs.h>
32*63d1fd59SEnji Cooper __RCSID("$NetBSD: t_setrlimit.c,v 1.6 2017/01/13 21:16:38 christos Exp $");
3357718be8SEnji Cooper 
3457718be8SEnji Cooper #include <sys/resource.h>
3557718be8SEnji Cooper #include <sys/mman.h>
3657718be8SEnji Cooper #include <sys/wait.h>
3757718be8SEnji Cooper 
3857718be8SEnji Cooper #include <atf-c.h>
3957718be8SEnji Cooper #include <errno.h>
4057718be8SEnji Cooper #include <fcntl.h>
4157718be8SEnji Cooper #include <limits.h>
42928eb3afSEnji Cooper #ifdef __NetBSD__
4357718be8SEnji Cooper #include <lwp.h>
44928eb3afSEnji Cooper #endif
4557718be8SEnji Cooper #include <signal.h>
4657718be8SEnji Cooper #include <stdint.h>
4757718be8SEnji Cooper #include <stdio.h>
4857718be8SEnji Cooper #include <stdlib.h>
4957718be8SEnji Cooper #include <string.h>
5057718be8SEnji Cooper #include <ucontext.h>
5157718be8SEnji Cooper #include <unistd.h>
5257718be8SEnji Cooper 
53710542dfSBryan Drewery #ifdef __FreeBSD__
54710542dfSBryan Drewery void set_vm_max_wired(int);
55710542dfSBryan Drewery void restore_vm_max_wired(void);
56710542dfSBryan Drewery #endif
57710542dfSBryan Drewery 
5857718be8SEnji Cooper static void		 sighandler(int);
5957718be8SEnji Cooper static const char	 path[] = "setrlimit";
6057718be8SEnji Cooper 
6157718be8SEnji Cooper static const int rlimit[] = {
6257718be8SEnji Cooper 	RLIMIT_AS,
6357718be8SEnji Cooper 	RLIMIT_CORE,
6457718be8SEnji Cooper 	RLIMIT_CPU,
6557718be8SEnji Cooper 	RLIMIT_DATA,
6657718be8SEnji Cooper 	RLIMIT_FSIZE,
6757718be8SEnji Cooper 	RLIMIT_MEMLOCK,
6857718be8SEnji Cooper 	RLIMIT_NOFILE,
6957718be8SEnji Cooper 	RLIMIT_NPROC,
7057718be8SEnji Cooper 	RLIMIT_RSS,
7157718be8SEnji Cooper 	RLIMIT_SBSIZE,
7257718be8SEnji Cooper 	RLIMIT_STACK
7357718be8SEnji Cooper };
7457718be8SEnji Cooper 
7557718be8SEnji Cooper ATF_TC(setrlimit_basic);
ATF_TC_HEAD(setrlimit_basic,tc)7657718be8SEnji Cooper ATF_TC_HEAD(setrlimit_basic, tc)
7757718be8SEnji Cooper {
7857718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "A basic soft limit test");
7957718be8SEnji Cooper }
8057718be8SEnji Cooper 
ATF_TC_BODY(setrlimit_basic,tc)8157718be8SEnji Cooper ATF_TC_BODY(setrlimit_basic, tc)
8257718be8SEnji Cooper {
8357718be8SEnji Cooper 	struct rlimit res;
8457718be8SEnji Cooper 	int *buf, lim;
8557718be8SEnji Cooper 	size_t i;
8657718be8SEnji Cooper 
8757718be8SEnji Cooper 	buf = calloc(__arraycount(rlimit), sizeof(int));
8857718be8SEnji Cooper 
8957718be8SEnji Cooper 	if (buf == NULL)
9057718be8SEnji Cooper 		atf_tc_fail("initialization failed");
9157718be8SEnji Cooper 
9257718be8SEnji Cooper 	for (i = lim = 0; i < __arraycount(rlimit); i++) {
9357718be8SEnji Cooper 
9457718be8SEnji Cooper 		(void)memset(&res, 0, sizeof(struct rlimit));
9557718be8SEnji Cooper 
9657718be8SEnji Cooper 		if (getrlimit(rlimit[i], &res) != 0)
9757718be8SEnji Cooper 			continue;
9857718be8SEnji Cooper 
9957718be8SEnji Cooper 		if (res.rlim_cur == RLIM_INFINITY || res.rlim_cur == 0)
10057718be8SEnji Cooper 			continue;
10157718be8SEnji Cooper 
10257718be8SEnji Cooper 		if (res.rlim_cur == res.rlim_max) /* An unprivileged run. */
10357718be8SEnji Cooper 			continue;
10457718be8SEnji Cooper 
10557718be8SEnji Cooper 		buf[i] = res.rlim_cur;
10657718be8SEnji Cooper 		res.rlim_cur = res.rlim_cur - 1;
10757718be8SEnji Cooper 
10857718be8SEnji Cooper 		if (setrlimit(rlimit[i], &res) != 0) {
10957718be8SEnji Cooper 			lim = rlimit[i];
11057718be8SEnji Cooper 			goto out;
11157718be8SEnji Cooper 		}
11257718be8SEnji Cooper 	}
11357718be8SEnji Cooper 
11457718be8SEnji Cooper out:
11557718be8SEnji Cooper 	for (i = 0; i < __arraycount(rlimit); i++) {
11657718be8SEnji Cooper 
11757718be8SEnji Cooper 		(void)memset(&res, 0, sizeof(struct rlimit));
11857718be8SEnji Cooper 
11957718be8SEnji Cooper 		if (buf[i] == 0)
12057718be8SEnji Cooper 			continue;
12157718be8SEnji Cooper 
12257718be8SEnji Cooper 		if (getrlimit(rlimit[i], &res) != 0)
12357718be8SEnji Cooper 			continue;
12457718be8SEnji Cooper 
12557718be8SEnji Cooper 		res.rlim_cur = buf[i];
12657718be8SEnji Cooper 
12757718be8SEnji Cooper 		(void)setrlimit(rlimit[i], &res);
12857718be8SEnji Cooper 	}
12957718be8SEnji Cooper 
13057718be8SEnji Cooper 	if (lim != 0)
13157718be8SEnji Cooper 		atf_tc_fail("failed to set limit (%d)", lim);
132dca7cc98SEnji Cooper 	free(buf);
13357718be8SEnji Cooper }
13457718be8SEnji Cooper 
13557718be8SEnji Cooper ATF_TC(setrlimit_current);
ATF_TC_HEAD(setrlimit_current,tc)13657718be8SEnji Cooper ATF_TC_HEAD(setrlimit_current, tc)
13757718be8SEnji Cooper {
13857718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "setrlimit(3) with current limits");
13957718be8SEnji Cooper }
14057718be8SEnji Cooper 
ATF_TC_BODY(setrlimit_current,tc)14157718be8SEnji Cooper ATF_TC_BODY(setrlimit_current, tc)
14257718be8SEnji Cooper {
14357718be8SEnji Cooper 	struct rlimit res;
14457718be8SEnji Cooper 	size_t i;
14557718be8SEnji Cooper 
14657718be8SEnji Cooper 	for (i = 0; i < __arraycount(rlimit); i++) {
14757718be8SEnji Cooper 
14857718be8SEnji Cooper 		(void)memset(&res, 0, sizeof(struct rlimit));
14957718be8SEnji Cooper 
15057718be8SEnji Cooper 		ATF_REQUIRE(getrlimit(rlimit[i], &res) == 0);
15157718be8SEnji Cooper 		ATF_REQUIRE(setrlimit(rlimit[i], &res) == 0);
15257718be8SEnji Cooper 	}
15357718be8SEnji Cooper }
15457718be8SEnji Cooper 
15557718be8SEnji Cooper ATF_TC(setrlimit_err);
ATF_TC_HEAD(setrlimit_err,tc)15657718be8SEnji Cooper ATF_TC_HEAD(setrlimit_err, tc)
15757718be8SEnji Cooper {
15857718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test error conditions");
15957718be8SEnji Cooper }
16057718be8SEnji Cooper 
ATF_TC_BODY(setrlimit_err,tc)16157718be8SEnji Cooper ATF_TC_BODY(setrlimit_err, tc)
16257718be8SEnji Cooper {
16357718be8SEnji Cooper 	struct rlimit res;
16457718be8SEnji Cooper 	size_t i;
16557718be8SEnji Cooper 
16657718be8SEnji Cooper 	for (i = 0; i < __arraycount(rlimit); i++) {
16757718be8SEnji Cooper 
16857718be8SEnji Cooper 		errno = 0;
16957718be8SEnji Cooper 
17057718be8SEnji Cooper 		ATF_REQUIRE(getrlimit(rlimit[i], (void *)0) != 0);
17157718be8SEnji Cooper 		ATF_REQUIRE(errno == EFAULT);
17257718be8SEnji Cooper 	}
17357718be8SEnji Cooper 
17457718be8SEnji Cooper 	errno = 0;
17557718be8SEnji Cooper 
17657718be8SEnji Cooper 	ATF_REQUIRE(getrlimit(INT_MAX, &res) != 0);
17757718be8SEnji Cooper 	ATF_REQUIRE(errno == EINVAL);
17857718be8SEnji Cooper }
17957718be8SEnji Cooper 
18057718be8SEnji Cooper ATF_TC_WITH_CLEANUP(setrlimit_fsize);
ATF_TC_HEAD(setrlimit_fsize,tc)18157718be8SEnji Cooper ATF_TC_HEAD(setrlimit_fsize, tc)
18257718be8SEnji Cooper {
18357718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_FSIZE");
18457718be8SEnji Cooper }
18557718be8SEnji Cooper 
ATF_TC_BODY(setrlimit_fsize,tc)18657718be8SEnji Cooper ATF_TC_BODY(setrlimit_fsize, tc)
18757718be8SEnji Cooper {
18857718be8SEnji Cooper 	struct rlimit res;
18957718be8SEnji Cooper 	int fd, sta;
19057718be8SEnji Cooper 	pid_t pid;
19157718be8SEnji Cooper 
19257718be8SEnji Cooper 	fd = open(path, O_RDWR | O_CREAT, 0700);
19357718be8SEnji Cooper 
19457718be8SEnji Cooper 	if (fd < 0)
19557718be8SEnji Cooper 		atf_tc_fail("initialization failed");
19657718be8SEnji Cooper 
19757718be8SEnji Cooper 	pid = fork();
19857718be8SEnji Cooper 	ATF_REQUIRE(pid >= 0);
19957718be8SEnji Cooper 
20057718be8SEnji Cooper 	if (pid == 0) {
20157718be8SEnji Cooper 
20257718be8SEnji Cooper 		res.rlim_cur = 2;
20357718be8SEnji Cooper 		res.rlim_max = 2;
20457718be8SEnji Cooper 
20557718be8SEnji Cooper 		if (setrlimit(RLIMIT_FSIZE, &res) != 0)
20657718be8SEnji Cooper 			_exit(EXIT_FAILURE);
20757718be8SEnji Cooper 
20857718be8SEnji Cooper 		if (signal(SIGXFSZ, sighandler) == SIG_ERR)
20957718be8SEnji Cooper 			_exit(EXIT_FAILURE);
21057718be8SEnji Cooper 
21157718be8SEnji Cooper 		/*
21257718be8SEnji Cooper 		 * The third call should generate a SIGXFSZ.
21357718be8SEnji Cooper 		 */
21457718be8SEnji Cooper 		(void)write(fd, "X", 1);
21557718be8SEnji Cooper 		(void)write(fd, "X", 1);
21657718be8SEnji Cooper 		(void)write(fd, "X", 1);
21757718be8SEnji Cooper 
21857718be8SEnji Cooper 		_exit(EXIT_FAILURE);
21957718be8SEnji Cooper 	}
22057718be8SEnji Cooper 
22157718be8SEnji Cooper 	(void)close(fd);
22257718be8SEnji Cooper 	(void)wait(&sta);
22357718be8SEnji Cooper 	(void)unlink(path);
22457718be8SEnji Cooper 
22557718be8SEnji Cooper 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
22657718be8SEnji Cooper 		atf_tc_fail("RLIMIT_FSIZE not enforced");
22757718be8SEnji Cooper }
22857718be8SEnji Cooper 
ATF_TC_CLEANUP(setrlimit_fsize,tc)22957718be8SEnji Cooper ATF_TC_CLEANUP(setrlimit_fsize, tc)
23057718be8SEnji Cooper {
23157718be8SEnji Cooper 	(void)unlink(path);
23257718be8SEnji Cooper }
23357718be8SEnji Cooper 
23457718be8SEnji Cooper static void
sighandler(int signo)23557718be8SEnji Cooper sighandler(int signo)
23657718be8SEnji Cooper {
23757718be8SEnji Cooper 
23857718be8SEnji Cooper 	if (signo != SIGXFSZ)
23957718be8SEnji Cooper 		_exit(EXIT_FAILURE);
24057718be8SEnji Cooper 
24157718be8SEnji Cooper 	_exit(EXIT_SUCCESS);
24257718be8SEnji Cooper }
24357718be8SEnji Cooper 
244710542dfSBryan Drewery #ifdef __FreeBSD__
245710542dfSBryan Drewery ATF_TC_WITH_CLEANUP(setrlimit_memlock);
246710542dfSBryan Drewery #else
24757718be8SEnji Cooper ATF_TC(setrlimit_memlock);
248710542dfSBryan Drewery #endif
ATF_TC_HEAD(setrlimit_memlock,tc)24957718be8SEnji Cooper ATF_TC_HEAD(setrlimit_memlock, tc)
25057718be8SEnji Cooper {
25157718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_MEMLOCK");
252710542dfSBryan Drewery #ifdef __FreeBSD__
253710542dfSBryan Drewery 	atf_tc_set_md_var(tc, "require.config", "allow_sysctl_side_effects");
254710542dfSBryan Drewery 	atf_tc_set_md_var(tc, "require.user", "root");
255710542dfSBryan Drewery #endif
25657718be8SEnji Cooper }
25757718be8SEnji Cooper 
ATF_TC_BODY(setrlimit_memlock,tc)25857718be8SEnji Cooper ATF_TC_BODY(setrlimit_memlock, tc)
25957718be8SEnji Cooper {
26057718be8SEnji Cooper 	struct rlimit res;
26157718be8SEnji Cooper 	void *buf;
26257718be8SEnji Cooper 	long page;
26357718be8SEnji Cooper 	pid_t pid;
26457718be8SEnji Cooper 	int sta;
26557718be8SEnji Cooper 
266710542dfSBryan Drewery #ifdef __FreeBSD__
267710542dfSBryan Drewery 	/* Set max_wired really really high to avoid EAGAIN */
268710542dfSBryan Drewery 	set_vm_max_wired(INT_MAX);
269710542dfSBryan Drewery #endif
270710542dfSBryan Drewery 
27157718be8SEnji Cooper 	page = sysconf(_SC_PAGESIZE);
27257718be8SEnji Cooper 	ATF_REQUIRE(page >= 0);
27357718be8SEnji Cooper 
27457718be8SEnji Cooper 	buf = malloc(page);
27557718be8SEnji Cooper 	pid = fork();
27657718be8SEnji Cooper 
27757718be8SEnji Cooper 	if (buf == NULL || pid < 0)
27857718be8SEnji Cooper 		atf_tc_fail("initialization failed");
27957718be8SEnji Cooper 
28057718be8SEnji Cooper 	if (pid == 0) {
28157718be8SEnji Cooper 
28257718be8SEnji Cooper 		/*
28357718be8SEnji Cooper 		 * Try to lock a page while
28457718be8SEnji Cooper 		 * RLIMIT_MEMLOCK is zero.
28557718be8SEnji Cooper 		 */
28657718be8SEnji Cooper 		if (mlock(buf, page) != 0)
28757718be8SEnji Cooper 			_exit(EXIT_FAILURE);
28857718be8SEnji Cooper 
28957718be8SEnji Cooper 		if (munlock(buf, page) != 0)
29057718be8SEnji Cooper 			_exit(EXIT_FAILURE);
29157718be8SEnji Cooper 
29257718be8SEnji Cooper 		res.rlim_cur = 0;
29357718be8SEnji Cooper 		res.rlim_max = 0;
29457718be8SEnji Cooper 
29557718be8SEnji Cooper 		if (setrlimit(RLIMIT_MEMLOCK, &res) != 0)
29657718be8SEnji Cooper 			_exit(EXIT_FAILURE);
29757718be8SEnji Cooper 
29857718be8SEnji Cooper 		if (mlock(buf, page) != 0)
29957718be8SEnji Cooper 			_exit(EXIT_SUCCESS);
30057718be8SEnji Cooper 
30157718be8SEnji Cooper 		(void)munlock(buf, page);
30257718be8SEnji Cooper 
30357718be8SEnji Cooper 		_exit(EXIT_FAILURE);
30457718be8SEnji Cooper 	}
30557718be8SEnji Cooper 
30657718be8SEnji Cooper 	free(buf);
30757718be8SEnji Cooper 
30857718be8SEnji Cooper 	(void)wait(&sta);
30957718be8SEnji Cooper 
31057718be8SEnji Cooper 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
31157718be8SEnji Cooper 		atf_tc_fail("RLIMIT_MEMLOCK not enforced");
31257718be8SEnji Cooper }
31357718be8SEnji Cooper 
314710542dfSBryan Drewery #ifdef __FreeBSD__
ATF_TC_CLEANUP(setrlimit_memlock,tc)315710542dfSBryan Drewery ATF_TC_CLEANUP(setrlimit_memlock, tc)
316710542dfSBryan Drewery {
317710542dfSBryan Drewery 
318710542dfSBryan Drewery 	restore_vm_max_wired();
319710542dfSBryan Drewery }
320710542dfSBryan Drewery #endif
321710542dfSBryan Drewery 
32257718be8SEnji Cooper ATF_TC(setrlimit_nofile_1);
ATF_TC_HEAD(setrlimit_nofile_1,tc)32357718be8SEnji Cooper ATF_TC_HEAD(setrlimit_nofile_1, tc)
32457718be8SEnji Cooper {
32557718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NOFILE, #1");
32657718be8SEnji Cooper }
32757718be8SEnji Cooper 
ATF_TC_BODY(setrlimit_nofile_1,tc)32857718be8SEnji Cooper ATF_TC_BODY(setrlimit_nofile_1, tc)
32957718be8SEnji Cooper {
33057718be8SEnji Cooper 	struct rlimit res;
33157718be8SEnji Cooper 	int fd, i, rv, sta;
33257718be8SEnji Cooper 	pid_t pid;
33357718be8SEnji Cooper 
33457718be8SEnji Cooper 	res.rlim_cur = 0;
33557718be8SEnji Cooper 	res.rlim_max = 0;
33657718be8SEnji Cooper 
33757718be8SEnji Cooper 	pid = fork();
33857718be8SEnji Cooper 	ATF_REQUIRE(pid >= 0);
33957718be8SEnji Cooper 
34057718be8SEnji Cooper 	if (pid == 0) {
34157718be8SEnji Cooper 
34257718be8SEnji Cooper 		/*
34357718be8SEnji Cooper 		 * Close all descriptors, set RLIMIT_NOFILE
34457718be8SEnji Cooper 		 * to zero, and try to open a random file.
34557718be8SEnji Cooper 		 * This should fail with EMFILE.
34657718be8SEnji Cooper 		 */
34757718be8SEnji Cooper 		for (i = 0; i < 1024; i++)
34857718be8SEnji Cooper 			(void)close(i);
34957718be8SEnji Cooper 
35057718be8SEnji Cooper 		rv = setrlimit(RLIMIT_NOFILE, &res);
35157718be8SEnji Cooper 
35257718be8SEnji Cooper 		if (rv != 0)
35357718be8SEnji Cooper 			_exit(EXIT_FAILURE);
35457718be8SEnji Cooper 
35557718be8SEnji Cooper 		errno = 0;
35657718be8SEnji Cooper 		fd = open("/etc/passwd", O_RDONLY);
35757718be8SEnji Cooper 
35857718be8SEnji Cooper 		if (fd >= 0 || errno != EMFILE)
35957718be8SEnji Cooper 			_exit(EXIT_FAILURE);
36057718be8SEnji Cooper 
36157718be8SEnji Cooper 		_exit(EXIT_SUCCESS);
36257718be8SEnji Cooper 	}
36357718be8SEnji Cooper 
36457718be8SEnji Cooper 	(void)wait(&sta);
36557718be8SEnji Cooper 
36657718be8SEnji Cooper 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
36757718be8SEnji Cooper 		atf_tc_fail("RLIMIT_NOFILE not enforced");
36857718be8SEnji Cooper }
36957718be8SEnji Cooper 
37057718be8SEnji Cooper ATF_TC(setrlimit_nofile_2);
ATF_TC_HEAD(setrlimit_nofile_2,tc)37157718be8SEnji Cooper ATF_TC_HEAD(setrlimit_nofile_2, tc)
37257718be8SEnji Cooper {
37357718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NOFILE, #2");
37457718be8SEnji Cooper }
37557718be8SEnji Cooper 
ATF_TC_BODY(setrlimit_nofile_2,tc)37657718be8SEnji Cooper ATF_TC_BODY(setrlimit_nofile_2, tc)
37757718be8SEnji Cooper {
37857718be8SEnji Cooper 	static const rlim_t lim = 12;
37957718be8SEnji Cooper 	struct rlimit res;
38057718be8SEnji Cooper 	int fd, i, rv, sta;
38157718be8SEnji Cooper 	pid_t pid;
38257718be8SEnji Cooper 
38357718be8SEnji Cooper 	/*
38457718be8SEnji Cooper 	 * See that an arbitrary limit on
38557718be8SEnji Cooper 	 * open files is being enforced.
38657718be8SEnji Cooper 	 */
38757718be8SEnji Cooper 	res.rlim_cur = lim;
38857718be8SEnji Cooper 	res.rlim_max = lim;
38957718be8SEnji Cooper 
39057718be8SEnji Cooper 	pid = fork();
39157718be8SEnji Cooper 	ATF_REQUIRE(pid >= 0);
39257718be8SEnji Cooper 
39357718be8SEnji Cooper 	if (pid == 0) {
39457718be8SEnji Cooper 
39557718be8SEnji Cooper 		for (i = 0; i < 1024; i++)
39657718be8SEnji Cooper 			(void)close(i);
39757718be8SEnji Cooper 
39857718be8SEnji Cooper 		rv = setrlimit(RLIMIT_NOFILE, &res);
39957718be8SEnji Cooper 
40057718be8SEnji Cooper 		if (rv != 0)
40157718be8SEnji Cooper 			_exit(EXIT_FAILURE);
40257718be8SEnji Cooper 
40357718be8SEnji Cooper 		for (i = 0; i < (int)lim; i++) {
40457718be8SEnji Cooper 
40557718be8SEnji Cooper 			fd = open("/etc/passwd", O_RDONLY);
40657718be8SEnji Cooper 
40757718be8SEnji Cooper 			if (fd < 0)
40857718be8SEnji Cooper 				_exit(EXIT_FAILURE);
40957718be8SEnji Cooper 		}
41057718be8SEnji Cooper 
41157718be8SEnji Cooper 		/*
41257718be8SEnji Cooper 		 * After the limit has been reached,
41357718be8SEnji Cooper 		 * EMFILE should again follow.
41457718be8SEnji Cooper 		 */
41557718be8SEnji Cooper 		fd = open("/etc/passwd", O_RDONLY);
41657718be8SEnji Cooper 
41757718be8SEnji Cooper 		if (fd >= 0 || errno != EMFILE)
41857718be8SEnji Cooper 			_exit(EXIT_FAILURE);
41957718be8SEnji Cooper 
42057718be8SEnji Cooper 		_exit(EXIT_SUCCESS);
42157718be8SEnji Cooper 	}
42257718be8SEnji Cooper 
42357718be8SEnji Cooper 	(void)wait(&sta);
42457718be8SEnji Cooper 
42557718be8SEnji Cooper 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
42657718be8SEnji Cooper 		atf_tc_fail("RLIMIT_NOFILE not enforced");
42757718be8SEnji Cooper }
42857718be8SEnji Cooper 
42957718be8SEnji Cooper ATF_TC(setrlimit_nproc);
ATF_TC_HEAD(setrlimit_nproc,tc)43057718be8SEnji Cooper ATF_TC_HEAD(setrlimit_nproc, tc)
43157718be8SEnji Cooper {
43257718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NPROC");
43357718be8SEnji Cooper 	atf_tc_set_md_var(tc, "require.user", "unprivileged");
43457718be8SEnji Cooper }
43557718be8SEnji Cooper 
ATF_TC_BODY(setrlimit_nproc,tc)43657718be8SEnji Cooper ATF_TC_BODY(setrlimit_nproc, tc)
43757718be8SEnji Cooper {
43857718be8SEnji Cooper 	struct rlimit res;
43957718be8SEnji Cooper 	pid_t pid, cpid;
44057718be8SEnji Cooper 	int sta;
44157718be8SEnji Cooper 
44257718be8SEnji Cooper 	pid = fork();
44357718be8SEnji Cooper 	ATF_REQUIRE(pid >= 0);
44457718be8SEnji Cooper 
44557718be8SEnji Cooper 	if (pid == 0) {
44657718be8SEnji Cooper 
44757718be8SEnji Cooper 		/*
44857718be8SEnji Cooper 		 * Set RLIMIT_NPROC to zero and try to fork.
44957718be8SEnji Cooper 		 */
45057718be8SEnji Cooper 		res.rlim_cur = 0;
45157718be8SEnji Cooper 		res.rlim_max = 0;
45257718be8SEnji Cooper 
45357718be8SEnji Cooper 		if (setrlimit(RLIMIT_NPROC, &res) != 0)
45457718be8SEnji Cooper 			_exit(EXIT_FAILURE);
45557718be8SEnji Cooper 
45657718be8SEnji Cooper 		cpid = fork();
45757718be8SEnji Cooper 
45857718be8SEnji Cooper 		if (cpid < 0)
45957718be8SEnji Cooper 			_exit(EXIT_SUCCESS);
46057718be8SEnji Cooper 
46157718be8SEnji Cooper 		_exit(EXIT_FAILURE);
46257718be8SEnji Cooper 	}
46357718be8SEnji Cooper 
46457718be8SEnji Cooper 	(void)waitpid(pid, &sta, 0);
46557718be8SEnji Cooper 
46657718be8SEnji Cooper 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
46757718be8SEnji Cooper 		atf_tc_fail("RLIMIT_NPROC not enforced");
46857718be8SEnji Cooper }
46957718be8SEnji Cooper 
470928eb3afSEnji Cooper #ifdef __NetBSD__
47157718be8SEnji Cooper ATF_TC(setrlimit_nthr);
ATF_TC_HEAD(setrlimit_nthr,tc)47257718be8SEnji Cooper ATF_TC_HEAD(setrlimit_nthr, tc)
47357718be8SEnji Cooper {
47457718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NTHR");
47557718be8SEnji Cooper 	atf_tc_set_md_var(tc, "require.user", "unprivileged");
47657718be8SEnji Cooper }
47757718be8SEnji Cooper 
47857718be8SEnji Cooper static void
func(lwpid_t * id)47957718be8SEnji Cooper func(lwpid_t *id)
48057718be8SEnji Cooper {
48157718be8SEnji Cooper 	printf("thread %d\n", *id);
48257718be8SEnji Cooper 	fflush(stdout);
48357718be8SEnji Cooper 	_lwp_exit();
48457718be8SEnji Cooper }
48557718be8SEnji Cooper 
ATF_TC_BODY(setrlimit_nthr,tc)48657718be8SEnji Cooper ATF_TC_BODY(setrlimit_nthr, tc)
48757718be8SEnji Cooper {
48857718be8SEnji Cooper 	struct rlimit res;
48957718be8SEnji Cooper 	lwpid_t lwpid;
49057718be8SEnji Cooper 	ucontext_t c;
49157718be8SEnji Cooper 
49257718be8SEnji Cooper 	/*
49357718be8SEnji Cooper 	 * Set RLIMIT_NTHR to zero and try to create a thread.
49457718be8SEnji Cooper 	 */
49557718be8SEnji Cooper 	res.rlim_cur = 0;
49657718be8SEnji Cooper 	res.rlim_max = 0;
49757718be8SEnji Cooper 	ATF_REQUIRE(setrlimit(RLIMIT_NTHR, &res) == 0);
49857718be8SEnji Cooper 	ATF_REQUIRE(getcontext(&c) == 0);
49957718be8SEnji Cooper 	c.uc_link = NULL;
50057718be8SEnji Cooper 	sigemptyset(&c.uc_sigmask);
50157718be8SEnji Cooper 	c.uc_stack.ss_flags = 0;
50257718be8SEnji Cooper 	c.uc_stack.ss_size = 4096;
50357718be8SEnji Cooper 	ATF_REQUIRE((c.uc_stack.ss_sp = malloc(c.uc_stack.ss_size)) != NULL);
50457718be8SEnji Cooper 	makecontext(&c, func, 1, &lwpid);
50557718be8SEnji Cooper 	ATF_CHECK_ERRNO(EAGAIN, _lwp_create(&c, 0, &lwpid) == -1);
50657718be8SEnji Cooper }
507928eb3afSEnji Cooper #endif
50857718be8SEnji Cooper 
50957718be8SEnji Cooper ATF_TC(setrlimit_perm);
ATF_TC_HEAD(setrlimit_perm,tc)51057718be8SEnji Cooper ATF_TC_HEAD(setrlimit_perm, tc)
51157718be8SEnji Cooper {
51257718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2) for EPERM");
51357718be8SEnji Cooper 	atf_tc_set_md_var(tc, "require.user", "unprivileged");
51457718be8SEnji Cooper }
51557718be8SEnji Cooper 
ATF_TC_BODY(setrlimit_perm,tc)51657718be8SEnji Cooper ATF_TC_BODY(setrlimit_perm, tc)
51757718be8SEnji Cooper {
51857718be8SEnji Cooper 	struct rlimit res;
51957718be8SEnji Cooper 	size_t i;
52057718be8SEnji Cooper 
52157718be8SEnji Cooper 	/*
52257718be8SEnji Cooper 	 * Try to raise the maximum limits as an user.
52357718be8SEnji Cooper 	 */
52457718be8SEnji Cooper 	for (i = 0; i < __arraycount(rlimit); i++) {
52557718be8SEnji Cooper 
52657718be8SEnji Cooper 		ATF_REQUIRE(getrlimit(rlimit[i], &res) == 0);
52757718be8SEnji Cooper 
528928eb3afSEnji Cooper #ifdef __FreeBSD__
529928eb3afSEnji Cooper 		if (res.rlim_max == INT64_MAX) /* Overflow. */
530928eb3afSEnji Cooper #else
53157718be8SEnji Cooper 		if (res.rlim_max == UINT64_MAX) /* Overflow. */
532928eb3afSEnji Cooper #endif
53357718be8SEnji Cooper 			continue;
53457718be8SEnji Cooper 
53557718be8SEnji Cooper 		errno = 0;
53657718be8SEnji Cooper 		res.rlim_max = res.rlim_max + 1;
53757718be8SEnji Cooper 
53857718be8SEnji Cooper 		ATF_CHECK_ERRNO(EPERM, setrlimit(rlimit[i], &res) != 0);
53957718be8SEnji Cooper 	}
54057718be8SEnji Cooper }
54157718be8SEnji Cooper 
542640235e2SEnji Cooper ATF_TC(setrlimit_stack);
ATF_TC_HEAD(setrlimit_stack,tc)543640235e2SEnji Cooper ATF_TC_HEAD(setrlimit_stack, tc)
544640235e2SEnji Cooper {
545640235e2SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_STACK");
546640235e2SEnji Cooper 	atf_tc_set_md_var(tc, "require.user", "unprivileged");
547640235e2SEnji Cooper }
548640235e2SEnji Cooper 
ATF_TC_BODY(setrlimit_stack,tc)549640235e2SEnji Cooper ATF_TC_BODY(setrlimit_stack, tc)
550640235e2SEnji Cooper {
551640235e2SEnji Cooper 	struct rlimit res;
552640235e2SEnji Cooper 
553640235e2SEnji Cooper 	/* Ensure soft limit is not bigger than hard limit */
554640235e2SEnji Cooper 	res.rlim_cur = res.rlim_max = 4192256;
555640235e2SEnji Cooper 	ATF_REQUIRE(setrlimit(RLIMIT_STACK, &res) == 0);
556640235e2SEnji Cooper 	ATF_REQUIRE(getrlimit(RLIMIT_STACK, &res) == 0);
557640235e2SEnji Cooper 	ATF_CHECK(res.rlim_cur <= res.rlim_max);
558640235e2SEnji Cooper 
559640235e2SEnji Cooper }
560640235e2SEnji Cooper 
ATF_TP_ADD_TCS(tp)56157718be8SEnji Cooper ATF_TP_ADD_TCS(tp)
56257718be8SEnji Cooper {
56357718be8SEnji Cooper 
56457718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, setrlimit_basic);
56557718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, setrlimit_current);
56657718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, setrlimit_err);
56757718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, setrlimit_fsize);
56857718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, setrlimit_memlock);
56957718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, setrlimit_nofile_1);
57057718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, setrlimit_nofile_2);
57157718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, setrlimit_nproc);
57257718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, setrlimit_perm);
57370d69ef1SEnji Cooper #ifdef __NetBSD__
57457718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, setrlimit_nthr);
575928eb3afSEnji Cooper #endif
576640235e2SEnji Cooper 	ATF_TP_ADD_TC(tp, setrlimit_stack);
57757718be8SEnji Cooper 
57857718be8SEnji Cooper 	return atf_no_error();
57957718be8SEnji Cooper }
580