Home | History | Annotate | Line # | Download | only in sys
t_setrlimit.c revision 1.7.10.1
      1  1.7.10.1    martin /* $NetBSD: t_setrlimit.c,v 1.7.10.1 2023/11/28 12:56:27 martin Exp $ */
      2       1.1    jruoho 
      3       1.1    jruoho /*-
      4       1.1    jruoho  * Copyright (c) 2011 The NetBSD Foundation, Inc.
      5       1.1    jruoho  * All rights reserved.
      6       1.1    jruoho  *
      7       1.1    jruoho  * This code is derived from software contributed to The NetBSD Foundation
      8       1.1    jruoho  * by Jukka Ruohonen.
      9       1.1    jruoho  *
     10       1.1    jruoho  * Redistribution and use in source and binary forms, with or without
     11       1.1    jruoho  * modification, are permitted provided that the following conditions
     12       1.1    jruoho  * are met:
     13       1.1    jruoho  * 1. Redistributions of source code must retain the above copyright
     14       1.1    jruoho  *    notice, this list of conditions and the following disclaimer.
     15       1.1    jruoho  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.1    jruoho  *    notice, this list of conditions and the following disclaimer in the
     17       1.1    jruoho  *    documentation and/or other materials provided with the distribution.
     18       1.1    jruoho  *
     19       1.1    jruoho  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20       1.1    jruoho  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21       1.1    jruoho  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22       1.1    jruoho  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23       1.1    jruoho  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24       1.1    jruoho  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25       1.1    jruoho  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26       1.1    jruoho  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27       1.1    jruoho  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28       1.1    jruoho  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29       1.1    jruoho  * POSSIBILITY OF SUCH DAMAGE.
     30       1.1    jruoho  */
     31       1.1    jruoho #include <sys/cdefs.h>
     32  1.7.10.1    martin __RCSID("$NetBSD: t_setrlimit.c,v 1.7.10.1 2023/11/28 12:56:27 martin Exp $");
     33       1.1    jruoho 
     34       1.1    jruoho #include <sys/resource.h>
     35       1.1    jruoho #include <sys/mman.h>
     36       1.1    jruoho #include <sys/wait.h>
     37       1.1    jruoho 
     38       1.1    jruoho #include <atf-c.h>
     39       1.1    jruoho #include <errno.h>
     40       1.1    jruoho #include <fcntl.h>
     41       1.1    jruoho #include <limits.h>
     42       1.4  christos #include <lwp.h>
     43       1.1    jruoho #include <signal.h>
     44       1.2  dholland #include <stdint.h>
     45       1.4  christos #include <stdio.h>
     46       1.1    jruoho #include <stdlib.h>
     47       1.1    jruoho #include <string.h>
     48       1.4  christos #include <ucontext.h>
     49       1.1    jruoho #include <unistd.h>
     50       1.1    jruoho 
     51  1.7.10.1    martin #include "h_macros.h"
     52  1.7.10.1    martin 
     53       1.1    jruoho static void		 sighandler(int);
     54       1.1    jruoho static const char	 path[] = "setrlimit";
     55       1.1    jruoho 
     56       1.1    jruoho static const int rlimit[] = {
     57       1.1    jruoho 	RLIMIT_AS,
     58       1.1    jruoho 	RLIMIT_CORE,
     59       1.1    jruoho 	RLIMIT_CPU,
     60       1.1    jruoho 	RLIMIT_DATA,
     61       1.1    jruoho 	RLIMIT_FSIZE,
     62       1.1    jruoho 	RLIMIT_MEMLOCK,
     63       1.1    jruoho 	RLIMIT_NOFILE,
     64       1.1    jruoho 	RLIMIT_NPROC,
     65       1.1    jruoho 	RLIMIT_RSS,
     66       1.1    jruoho 	RLIMIT_SBSIZE,
     67       1.1    jruoho 	RLIMIT_STACK
     68       1.1    jruoho };
     69       1.1    jruoho 
     70       1.1    jruoho ATF_TC(setrlimit_basic);
     71       1.1    jruoho ATF_TC_HEAD(setrlimit_basic, tc)
     72       1.1    jruoho {
     73       1.1    jruoho 	atf_tc_set_md_var(tc, "descr", "A basic soft limit test");
     74       1.1    jruoho }
     75       1.1    jruoho 
     76       1.1    jruoho ATF_TC_BODY(setrlimit_basic, tc)
     77       1.1    jruoho {
     78       1.1    jruoho 	struct rlimit res;
     79       1.1    jruoho 	int *buf, lim;
     80       1.1    jruoho 	size_t i;
     81       1.1    jruoho 
     82       1.1    jruoho 	buf = calloc(__arraycount(rlimit), sizeof(int));
     83       1.1    jruoho 
     84       1.1    jruoho 	if (buf == NULL)
     85       1.1    jruoho 		atf_tc_fail("initialization failed");
     86       1.1    jruoho 
     87       1.1    jruoho 	for (i = lim = 0; i < __arraycount(rlimit); i++) {
     88       1.1    jruoho 
     89       1.1    jruoho 		(void)memset(&res, 0, sizeof(struct rlimit));
     90       1.1    jruoho 
     91       1.1    jruoho 		if (getrlimit(rlimit[i], &res) != 0)
     92       1.1    jruoho 			continue;
     93       1.1    jruoho 
     94       1.1    jruoho 		if (res.rlim_cur == RLIM_INFINITY || res.rlim_cur == 0)
     95       1.1    jruoho 			continue;
     96       1.1    jruoho 
     97       1.1    jruoho 		if (res.rlim_cur == res.rlim_max) /* An unprivileged run. */
     98       1.1    jruoho 			continue;
     99       1.1    jruoho 
    100       1.1    jruoho 		buf[i] = res.rlim_cur;
    101       1.1    jruoho 		res.rlim_cur = res.rlim_cur - 1;
    102       1.1    jruoho 
    103       1.1    jruoho 		if (setrlimit(rlimit[i], &res) != 0) {
    104       1.1    jruoho 			lim = rlimit[i];
    105       1.1    jruoho 			goto out;
    106       1.1    jruoho 		}
    107       1.1    jruoho 	}
    108       1.1    jruoho 
    109       1.1    jruoho out:
    110       1.1    jruoho 	for (i = 0; i < __arraycount(rlimit); i++) {
    111       1.1    jruoho 
    112       1.1    jruoho 		(void)memset(&res, 0, sizeof(struct rlimit));
    113       1.1    jruoho 
    114       1.1    jruoho 		if (buf[i] == 0)
    115       1.1    jruoho 			continue;
    116       1.1    jruoho 
    117       1.1    jruoho 		if (getrlimit(rlimit[i], &res) != 0)
    118       1.1    jruoho 			continue;
    119       1.1    jruoho 
    120       1.1    jruoho 		res.rlim_cur = buf[i];
    121       1.1    jruoho 
    122       1.1    jruoho 		(void)setrlimit(rlimit[i], &res);
    123       1.1    jruoho 	}
    124       1.1    jruoho 
    125       1.1    jruoho 	if (lim != 0)
    126       1.1    jruoho 		atf_tc_fail("failed to set limit (%d)", lim);
    127       1.6  christos 	free(buf);
    128       1.1    jruoho }
    129       1.1    jruoho 
    130       1.1    jruoho ATF_TC(setrlimit_current);
    131       1.1    jruoho ATF_TC_HEAD(setrlimit_current, tc)
    132       1.1    jruoho {
    133       1.1    jruoho 	atf_tc_set_md_var(tc, "descr", "setrlimit(3) with current limits");
    134       1.1    jruoho }
    135       1.1    jruoho 
    136       1.1    jruoho ATF_TC_BODY(setrlimit_current, tc)
    137       1.1    jruoho {
    138       1.1    jruoho 	struct rlimit res;
    139       1.1    jruoho 	size_t i;
    140       1.1    jruoho 
    141       1.1    jruoho 	for (i = 0; i < __arraycount(rlimit); i++) {
    142       1.1    jruoho 
    143       1.1    jruoho 		(void)memset(&res, 0, sizeof(struct rlimit));
    144       1.1    jruoho 
    145       1.1    jruoho 		ATF_REQUIRE(getrlimit(rlimit[i], &res) == 0);
    146       1.1    jruoho 		ATF_REQUIRE(setrlimit(rlimit[i], &res) == 0);
    147       1.1    jruoho 	}
    148       1.1    jruoho }
    149       1.1    jruoho 
    150       1.1    jruoho ATF_TC(setrlimit_err);
    151       1.1    jruoho ATF_TC_HEAD(setrlimit_err, tc)
    152       1.1    jruoho {
    153       1.1    jruoho 	atf_tc_set_md_var(tc, "descr", "Test error conditions");
    154       1.1    jruoho }
    155       1.1    jruoho 
    156       1.1    jruoho ATF_TC_BODY(setrlimit_err, tc)
    157       1.1    jruoho {
    158       1.1    jruoho 	struct rlimit res;
    159       1.1    jruoho 	size_t i;
    160       1.1    jruoho 
    161       1.1    jruoho 	for (i = 0; i < __arraycount(rlimit); i++) {
    162       1.1    jruoho 
    163       1.1    jruoho 		errno = 0;
    164       1.1    jruoho 
    165       1.1    jruoho 		ATF_REQUIRE(getrlimit(rlimit[i], (void *)0) != 0);
    166       1.1    jruoho 		ATF_REQUIRE(errno == EFAULT);
    167       1.1    jruoho 	}
    168       1.1    jruoho 
    169       1.1    jruoho 	errno = 0;
    170       1.1    jruoho 
    171       1.1    jruoho 	ATF_REQUIRE(getrlimit(INT_MAX, &res) != 0);
    172       1.1    jruoho 	ATF_REQUIRE(errno == EINVAL);
    173       1.1    jruoho }
    174       1.1    jruoho 
    175       1.1    jruoho ATF_TC_WITH_CLEANUP(setrlimit_fsize);
    176       1.1    jruoho ATF_TC_HEAD(setrlimit_fsize, tc)
    177       1.1    jruoho {
    178       1.1    jruoho 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_FSIZE");
    179       1.1    jruoho }
    180       1.1    jruoho 
    181       1.1    jruoho ATF_TC_BODY(setrlimit_fsize, tc)
    182       1.1    jruoho {
    183       1.1    jruoho 	struct rlimit res;
    184       1.1    jruoho 	int fd, sta;
    185       1.1    jruoho 	pid_t pid;
    186       1.1    jruoho 
    187       1.1    jruoho 	fd = open(path, O_RDWR | O_CREAT, 0700);
    188       1.1    jruoho 
    189       1.1    jruoho 	if (fd < 0)
    190       1.1    jruoho 		atf_tc_fail("initialization failed");
    191       1.1    jruoho 
    192       1.1    jruoho 	pid = fork();
    193       1.1    jruoho 	ATF_REQUIRE(pid >= 0);
    194       1.1    jruoho 
    195       1.1    jruoho 	if (pid == 0) {
    196       1.1    jruoho 
    197       1.1    jruoho 		res.rlim_cur = 2;
    198       1.1    jruoho 		res.rlim_max = 2;
    199       1.1    jruoho 
    200       1.1    jruoho 		if (setrlimit(RLIMIT_FSIZE, &res) != 0)
    201       1.1    jruoho 			_exit(EXIT_FAILURE);
    202       1.1    jruoho 
    203       1.1    jruoho 		if (signal(SIGXFSZ, sighandler) == SIG_ERR)
    204       1.1    jruoho 			_exit(EXIT_FAILURE);
    205       1.1    jruoho 
    206       1.1    jruoho 		/*
    207       1.1    jruoho 		 * The third call should generate a SIGXFSZ.
    208       1.1    jruoho 		 */
    209       1.1    jruoho 		(void)write(fd, "X", 1);
    210       1.1    jruoho 		(void)write(fd, "X", 1);
    211       1.1    jruoho 		(void)write(fd, "X", 1);
    212       1.1    jruoho 
    213       1.1    jruoho 		_exit(EXIT_FAILURE);
    214       1.1    jruoho 	}
    215       1.1    jruoho 
    216       1.1    jruoho 	(void)close(fd);
    217       1.1    jruoho 	(void)wait(&sta);
    218       1.1    jruoho 	(void)unlink(path);
    219       1.1    jruoho 
    220       1.1    jruoho 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
    221       1.1    jruoho 		atf_tc_fail("RLIMIT_FSIZE not enforced");
    222       1.1    jruoho }
    223       1.1    jruoho 
    224       1.1    jruoho ATF_TC_CLEANUP(setrlimit_fsize, tc)
    225       1.1    jruoho {
    226       1.1    jruoho 	(void)unlink(path);
    227       1.1    jruoho }
    228       1.1    jruoho 
    229       1.1    jruoho static void
    230       1.1    jruoho sighandler(int signo)
    231       1.1    jruoho {
    232       1.1    jruoho 
    233       1.1    jruoho 	if (signo != SIGXFSZ)
    234       1.1    jruoho 		_exit(EXIT_FAILURE);
    235       1.1    jruoho 
    236       1.1    jruoho 	_exit(EXIT_SUCCESS);
    237       1.1    jruoho }
    238       1.1    jruoho 
    239       1.1    jruoho ATF_TC(setrlimit_memlock);
    240       1.1    jruoho ATF_TC_HEAD(setrlimit_memlock, tc)
    241       1.1    jruoho {
    242       1.1    jruoho 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_MEMLOCK");
    243       1.1    jruoho }
    244       1.1    jruoho 
    245       1.1    jruoho ATF_TC_BODY(setrlimit_memlock, tc)
    246       1.1    jruoho {
    247       1.1    jruoho 	struct rlimit res;
    248       1.1    jruoho 	void *buf;
    249       1.1    jruoho 	long page;
    250       1.1    jruoho 	pid_t pid;
    251       1.1    jruoho 	int sta;
    252       1.1    jruoho 
    253       1.1    jruoho 	page = sysconf(_SC_PAGESIZE);
    254       1.1    jruoho 	ATF_REQUIRE(page >= 0);
    255       1.1    jruoho 
    256       1.1    jruoho 	buf = malloc(page);
    257       1.1    jruoho 	pid = fork();
    258       1.1    jruoho 
    259       1.1    jruoho 	if (buf == NULL || pid < 0)
    260       1.1    jruoho 		atf_tc_fail("initialization failed");
    261       1.1    jruoho 
    262       1.1    jruoho 	if (pid == 0) {
    263       1.1    jruoho 
    264       1.1    jruoho 		/*
    265       1.1    jruoho 		 * Try to lock a page while
    266       1.1    jruoho 		 * RLIMIT_MEMLOCK is zero.
    267       1.1    jruoho 		 */
    268       1.1    jruoho 		if (mlock(buf, page) != 0)
    269       1.1    jruoho 			_exit(EXIT_FAILURE);
    270       1.1    jruoho 
    271       1.1    jruoho 		if (munlock(buf, page) != 0)
    272       1.1    jruoho 			_exit(EXIT_FAILURE);
    273       1.1    jruoho 
    274       1.1    jruoho 		res.rlim_cur = 0;
    275       1.1    jruoho 		res.rlim_max = 0;
    276       1.1    jruoho 
    277       1.1    jruoho 		if (setrlimit(RLIMIT_MEMLOCK, &res) != 0)
    278       1.1    jruoho 			_exit(EXIT_FAILURE);
    279       1.1    jruoho 
    280       1.1    jruoho 		if (mlock(buf, page) != 0)
    281       1.1    jruoho 			_exit(EXIT_SUCCESS);
    282       1.1    jruoho 
    283       1.1    jruoho 		(void)munlock(buf, page);
    284       1.1    jruoho 
    285       1.1    jruoho 		_exit(EXIT_FAILURE);
    286       1.1    jruoho 	}
    287       1.1    jruoho 
    288       1.1    jruoho 	free(buf);
    289       1.1    jruoho 
    290       1.1    jruoho 	(void)wait(&sta);
    291       1.1    jruoho 
    292       1.1    jruoho 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
    293       1.1    jruoho 		atf_tc_fail("RLIMIT_MEMLOCK not enforced");
    294       1.1    jruoho }
    295       1.1    jruoho 
    296       1.1    jruoho ATF_TC(setrlimit_nofile_1);
    297       1.1    jruoho ATF_TC_HEAD(setrlimit_nofile_1, tc)
    298       1.1    jruoho {
    299       1.1    jruoho 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NOFILE, #1");
    300       1.1    jruoho }
    301       1.1    jruoho 
    302       1.1    jruoho ATF_TC_BODY(setrlimit_nofile_1, tc)
    303       1.1    jruoho {
    304       1.1    jruoho 	struct rlimit res;
    305       1.1    jruoho 	int fd, i, rv, sta;
    306       1.1    jruoho 	pid_t pid;
    307       1.1    jruoho 
    308       1.1    jruoho 	res.rlim_cur = 0;
    309       1.1    jruoho 	res.rlim_max = 0;
    310       1.1    jruoho 
    311       1.1    jruoho 	pid = fork();
    312       1.1    jruoho 	ATF_REQUIRE(pid >= 0);
    313       1.1    jruoho 
    314       1.1    jruoho 	if (pid == 0) {
    315       1.1    jruoho 
    316       1.1    jruoho 		/*
    317       1.1    jruoho 		 * Close all descriptors, set RLIMIT_NOFILE
    318       1.1    jruoho 		 * to zero, and try to open a random file.
    319       1.1    jruoho 		 * This should fail with EMFILE.
    320       1.1    jruoho 		 */
    321       1.1    jruoho 		for (i = 0; i < 1024; i++)
    322       1.1    jruoho 			(void)close(i);
    323       1.1    jruoho 
    324       1.1    jruoho 		rv = setrlimit(RLIMIT_NOFILE, &res);
    325       1.1    jruoho 
    326       1.1    jruoho 		if (rv != 0)
    327       1.1    jruoho 			_exit(EXIT_FAILURE);
    328       1.1    jruoho 
    329       1.1    jruoho 		errno = 0;
    330       1.1    jruoho 		fd = open("/etc/passwd", O_RDONLY);
    331       1.1    jruoho 
    332       1.1    jruoho 		if (fd >= 0 || errno != EMFILE)
    333       1.1    jruoho 			_exit(EXIT_FAILURE);
    334       1.1    jruoho 
    335       1.1    jruoho 		_exit(EXIT_SUCCESS);
    336       1.1    jruoho 	}
    337       1.1    jruoho 
    338       1.1    jruoho 	(void)wait(&sta);
    339       1.1    jruoho 
    340       1.1    jruoho 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
    341       1.1    jruoho 		atf_tc_fail("RLIMIT_NOFILE not enforced");
    342       1.1    jruoho }
    343       1.1    jruoho 
    344       1.1    jruoho ATF_TC(setrlimit_nofile_2);
    345       1.1    jruoho ATF_TC_HEAD(setrlimit_nofile_2, tc)
    346       1.1    jruoho {
    347       1.1    jruoho 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NOFILE, #2");
    348       1.1    jruoho }
    349       1.1    jruoho 
    350       1.1    jruoho ATF_TC_BODY(setrlimit_nofile_2, tc)
    351       1.1    jruoho {
    352       1.1    jruoho 	static const rlim_t lim = 12;
    353       1.1    jruoho 	struct rlimit res;
    354       1.1    jruoho 	int fd, i, rv, sta;
    355       1.1    jruoho 	pid_t pid;
    356       1.1    jruoho 
    357       1.1    jruoho 	/*
    358       1.1    jruoho 	 * See that an arbitrary limit on
    359       1.1    jruoho 	 * open files is being enforced.
    360       1.1    jruoho 	 */
    361       1.1    jruoho 	res.rlim_cur = lim;
    362       1.1    jruoho 	res.rlim_max = lim;
    363       1.1    jruoho 
    364       1.1    jruoho 	pid = fork();
    365       1.1    jruoho 	ATF_REQUIRE(pid >= 0);
    366       1.1    jruoho 
    367       1.1    jruoho 	if (pid == 0) {
    368       1.1    jruoho 
    369       1.1    jruoho 		for (i = 0; i < 1024; i++)
    370       1.1    jruoho 			(void)close(i);
    371       1.1    jruoho 
    372       1.1    jruoho 		rv = setrlimit(RLIMIT_NOFILE, &res);
    373       1.1    jruoho 
    374       1.1    jruoho 		if (rv != 0)
    375       1.1    jruoho 			_exit(EXIT_FAILURE);
    376       1.1    jruoho 
    377       1.1    jruoho 		for (i = 0; i < (int)lim; i++) {
    378       1.1    jruoho 
    379       1.1    jruoho 			fd = open("/etc/passwd", O_RDONLY);
    380       1.1    jruoho 
    381       1.1    jruoho 			if (fd < 0)
    382       1.1    jruoho 				_exit(EXIT_FAILURE);
    383       1.1    jruoho 		}
    384       1.1    jruoho 
    385       1.1    jruoho 		/*
    386       1.1    jruoho 		 * After the limit has been reached,
    387       1.1    jruoho 		 * EMFILE should again follow.
    388       1.1    jruoho 		 */
    389       1.1    jruoho 		fd = open("/etc/passwd", O_RDONLY);
    390       1.1    jruoho 
    391       1.1    jruoho 		if (fd >= 0 || errno != EMFILE)
    392       1.1    jruoho 			_exit(EXIT_FAILURE);
    393       1.1    jruoho 
    394       1.1    jruoho 		_exit(EXIT_SUCCESS);
    395       1.1    jruoho 	}
    396       1.1    jruoho 
    397       1.1    jruoho 	(void)wait(&sta);
    398       1.1    jruoho 
    399       1.1    jruoho 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
    400       1.1    jruoho 		atf_tc_fail("RLIMIT_NOFILE not enforced");
    401       1.1    jruoho }
    402       1.1    jruoho 
    403       1.1    jruoho ATF_TC(setrlimit_nproc);
    404       1.1    jruoho ATF_TC_HEAD(setrlimit_nproc, tc)
    405       1.1    jruoho {
    406       1.1    jruoho 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NPROC");
    407       1.1    jruoho 	atf_tc_set_md_var(tc, "require.user", "unprivileged");
    408       1.1    jruoho }
    409       1.1    jruoho 
    410       1.1    jruoho ATF_TC_BODY(setrlimit_nproc, tc)
    411       1.1    jruoho {
    412       1.1    jruoho 	struct rlimit res;
    413       1.1    jruoho 	pid_t pid, cpid;
    414       1.1    jruoho 	int sta;
    415       1.1    jruoho 
    416       1.1    jruoho 	pid = fork();
    417       1.1    jruoho 	ATF_REQUIRE(pid >= 0);
    418       1.1    jruoho 
    419       1.1    jruoho 	if (pid == 0) {
    420       1.1    jruoho 
    421       1.1    jruoho 		/*
    422       1.1    jruoho 		 * Set RLIMIT_NPROC to zero and try to fork.
    423       1.1    jruoho 		 */
    424       1.1    jruoho 		res.rlim_cur = 0;
    425       1.1    jruoho 		res.rlim_max = 0;
    426       1.1    jruoho 
    427       1.1    jruoho 		if (setrlimit(RLIMIT_NPROC, &res) != 0)
    428       1.1    jruoho 			_exit(EXIT_FAILURE);
    429       1.1    jruoho 
    430       1.1    jruoho 		cpid = fork();
    431       1.1    jruoho 
    432       1.1    jruoho 		if (cpid < 0)
    433       1.1    jruoho 			_exit(EXIT_SUCCESS);
    434       1.1    jruoho 
    435       1.1    jruoho 		_exit(EXIT_FAILURE);
    436       1.1    jruoho 	}
    437       1.1    jruoho 
    438       1.1    jruoho 	(void)waitpid(pid, &sta, 0);
    439       1.1    jruoho 
    440       1.1    jruoho 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
    441       1.1    jruoho 		atf_tc_fail("RLIMIT_NPROC not enforced");
    442       1.1    jruoho }
    443       1.1    jruoho 
    444       1.4  christos ATF_TC(setrlimit_nthr);
    445       1.4  christos ATF_TC_HEAD(setrlimit_nthr, tc)
    446       1.4  christos {
    447       1.4  christos 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NTHR");
    448       1.4  christos 	atf_tc_set_md_var(tc, "require.user", "unprivileged");
    449       1.4  christos }
    450       1.4  christos 
    451       1.4  christos static void
    452       1.4  christos func(lwpid_t *id)
    453       1.4  christos {
    454       1.4  christos 	printf("thread %d\n", *id);
    455       1.4  christos 	fflush(stdout);
    456       1.4  christos 	_lwp_exit();
    457       1.4  christos }
    458       1.4  christos 
    459       1.4  christos ATF_TC_BODY(setrlimit_nthr, tc)
    460       1.4  christos {
    461       1.4  christos 	struct rlimit res;
    462       1.4  christos 	lwpid_t lwpid;
    463       1.4  christos 	ucontext_t c;
    464       1.4  christos 
    465       1.4  christos 	/*
    466       1.4  christos 	 * Set RLIMIT_NTHR to zero and try to create a thread.
    467       1.4  christos 	 */
    468       1.4  christos 	res.rlim_cur = 0;
    469       1.4  christos 	res.rlim_max = 0;
    470       1.4  christos 	ATF_REQUIRE(setrlimit(RLIMIT_NTHR, &res) == 0);
    471       1.4  christos 	ATF_REQUIRE(getcontext(&c) == 0);
    472       1.4  christos 	c.uc_link = NULL;
    473       1.4  christos 	sigemptyset(&c.uc_sigmask);
    474       1.4  christos 	c.uc_stack.ss_flags = 0;
    475       1.4  christos 	c.uc_stack.ss_size = 4096;
    476       1.4  christos 	ATF_REQUIRE((c.uc_stack.ss_sp = malloc(c.uc_stack.ss_size)) != NULL);
    477       1.4  christos 	makecontext(&c, func, 1, &lwpid);
    478       1.4  christos 	ATF_CHECK_ERRNO(EAGAIN, _lwp_create(&c, 0, &lwpid) == -1);
    479       1.4  christos }
    480       1.4  christos 
    481       1.1    jruoho ATF_TC(setrlimit_perm);
    482       1.1    jruoho ATF_TC_HEAD(setrlimit_perm, tc)
    483       1.1    jruoho {
    484       1.1    jruoho 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2) for EPERM");
    485       1.1    jruoho 	atf_tc_set_md_var(tc, "require.user", "unprivileged");
    486       1.1    jruoho }
    487       1.1    jruoho 
    488       1.1    jruoho ATF_TC_BODY(setrlimit_perm, tc)
    489       1.1    jruoho {
    490       1.1    jruoho 	struct rlimit res;
    491       1.1    jruoho 	size_t i;
    492       1.1    jruoho 
    493       1.1    jruoho 	/*
    494       1.1    jruoho 	 * Try to raise the maximum limits as an user.
    495       1.1    jruoho 	 */
    496       1.1    jruoho 	for (i = 0; i < __arraycount(rlimit); i++) {
    497       1.1    jruoho 
    498       1.1    jruoho 		ATF_REQUIRE(getrlimit(rlimit[i], &res) == 0);
    499       1.1    jruoho 
    500       1.1    jruoho 		if (res.rlim_max == UINT64_MAX) /* Overflow. */
    501       1.1    jruoho 			continue;
    502       1.1    jruoho 
    503       1.1    jruoho 		errno = 0;
    504       1.1    jruoho 		res.rlim_max = res.rlim_max + 1;
    505       1.1    jruoho 
    506       1.3     njoly 		ATF_CHECK_ERRNO(EPERM, setrlimit(rlimit[i], &res) != 0);
    507       1.1    jruoho 	}
    508       1.1    jruoho }
    509       1.1    jruoho 
    510       1.5     njoly ATF_TC(setrlimit_stack);
    511       1.5     njoly ATF_TC_HEAD(setrlimit_stack, tc)
    512       1.5     njoly {
    513       1.5     njoly 	atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_STACK");
    514       1.5     njoly 	atf_tc_set_md_var(tc, "require.user", "unprivileged");
    515       1.5     njoly }
    516       1.5     njoly 
    517       1.5     njoly ATF_TC_BODY(setrlimit_stack, tc)
    518       1.5     njoly {
    519       1.5     njoly 	struct rlimit res;
    520       1.5     njoly 
    521       1.5     njoly 	/* Ensure soft limit is not bigger than hard limit */
    522       1.7       rin 	res.rlim_cur = res.rlim_max = 6 * 1024 * 1024;
    523       1.5     njoly 	ATF_REQUIRE(setrlimit(RLIMIT_STACK, &res) == 0);
    524       1.5     njoly 	ATF_REQUIRE(getrlimit(RLIMIT_STACK, &res) == 0);
    525       1.5     njoly 	ATF_CHECK(res.rlim_cur <= res.rlim_max);
    526       1.5     njoly 
    527       1.5     njoly }
    528       1.5     njoly 
    529  1.7.10.1    martin ATF_TC(setrlimit_stack_growshrink);
    530  1.7.10.1    martin ATF_TC_HEAD(setrlimit_stack_growshrink, tc)
    531  1.7.10.1    martin {
    532  1.7.10.1    martin 	atf_tc_set_md_var(tc, "descr",
    533  1.7.10.1    martin 	    "Test that setrlimit(2), RLIMIT_STACK, grows & shrinks the stack");
    534  1.7.10.1    martin }
    535  1.7.10.1    martin 
    536  1.7.10.1    martin /*
    537  1.7.10.1    martin  * checkstack(n, ok)
    538  1.7.10.1    martin  *
    539  1.7.10.1    martin  *	Check whether we can allocate an array of size n on the stack.
    540  1.7.10.1    martin  *
    541  1.7.10.1    martin  *	- If expectsegv, verify that access fails with SIGSEGV.
    542  1.7.10.1    martin  *	- If not expectsegv, verify that access succeeds.
    543  1.7.10.1    martin  *
    544  1.7.10.1    martin  *	Do this in a subprocess rather than with a SIGSEGV handler,
    545  1.7.10.1    martin  *	because once we've allocated an array of size n on the stack,
    546  1.7.10.1    martin  *	in the case where the stack is inaccessible, we have just
    547  1.7.10.1    martin  *	trashed the stack pointer so badly we can't make function calls
    548  1.7.10.1    martin  *	like to a SIGSEGV handler.
    549  1.7.10.1    martin  *
    550  1.7.10.1    martin  *	(We could use an alternate signal stack, but I already wrote it
    551  1.7.10.1    martin  *	this way, and this is a little simpler and more robust than
    552  1.7.10.1    martin  *	juggling signals, setjmp/longjmp, and sigaltstack.)
    553  1.7.10.1    martin  */
    554  1.7.10.1    martin static void
    555  1.7.10.1    martin checkstack(size_t n, int expectsegv)
    556  1.7.10.1    martin {
    557  1.7.10.1    martin 	pid_t forked, waited;
    558  1.7.10.1    martin 	size_t i;
    559  1.7.10.1    martin 	int status;
    560  1.7.10.1    martin 
    561  1.7.10.1    martin 	RL(forked = fork());
    562  1.7.10.1    martin 	if (forked == 0) {	/* child */
    563  1.7.10.1    martin 		volatile char *const x = alloca(n);
    564  1.7.10.1    martin 		for (i = 0; i < n; i++)
    565  1.7.10.1    martin 			x[i] = 0x1a;
    566  1.7.10.1    martin 		_exit(expectsegv);
    567  1.7.10.1    martin 	}
    568  1.7.10.1    martin 
    569  1.7.10.1    martin 	/* parent */
    570  1.7.10.1    martin 	RL(waited = waitpid(forked, &status, 0));
    571  1.7.10.1    martin 	ATF_REQUIRE_EQ_MSG(waited, forked, "waited=%jd forked=%jd",
    572  1.7.10.1    martin 	    (intmax_t)waited, (intmax_t)forked);
    573  1.7.10.1    martin 	if (expectsegv) {
    574  1.7.10.1    martin 		ATF_REQUIRE_MSG(!WIFEXITED(status),
    575  1.7.10.1    martin 		    "expected signal but exited normally with status %d",
    576  1.7.10.1    martin 		    WEXITSTATUS(status));
    577  1.7.10.1    martin 		ATF_REQUIRE_MSG(WIFSIGNALED(status), "status=0x%x", status);
    578  1.7.10.1    martin 		ATF_REQUIRE_EQ_MSG(WTERMSIG(status), SIGSEGV, "termsig=%d",
    579  1.7.10.1    martin 		    WTERMSIG(status));
    580  1.7.10.1    martin 	} else {
    581  1.7.10.1    martin 		ATF_REQUIRE_MSG(!WIFSIGNALED(status),
    582  1.7.10.1    martin 		    "expected normal exit but termintaed on signal %d",
    583  1.7.10.1    martin 		    WTERMSIG(status));
    584  1.7.10.1    martin 		ATF_REQUIRE_MSG(WIFEXITED(status), "status=0x%x", status);
    585  1.7.10.1    martin 		ATF_REQUIRE_EQ_MSG(WEXITSTATUS(status), 0, "exitstatus=%d",
    586  1.7.10.1    martin 		    WEXITSTATUS(status));
    587  1.7.10.1    martin 	}
    588  1.7.10.1    martin }
    589  1.7.10.1    martin 
    590  1.7.10.1    martin ATF_TC_BODY(setrlimit_stack_growshrink, tc)
    591  1.7.10.1    martin {
    592  1.7.10.1    martin 	struct rlimit res;
    593  1.7.10.1    martin 	size_t n;
    594  1.7.10.1    martin 
    595  1.7.10.1    martin 	/*
    596  1.7.10.1    martin 	 * Disable core dumps -- we're going to deliberately cause
    597  1.7.10.1    martin 	 * SIGSEGV to test stack accessibility (which breaks even
    598  1.7.10.1    martin 	 * calling a function so we can't just use a SIGSEGV handler),
    599  1.7.10.1    martin 	 * so let's not waste time dumping core.
    600  1.7.10.1    martin 	 */
    601  1.7.10.1    martin 	res = (struct rlimit){ .rlim_cur = 0, .rlim_max = 0 };
    602  1.7.10.1    martin 	RL(setrlimit(RLIMIT_CORE, &res));
    603  1.7.10.1    martin 
    604  1.7.10.1    martin 	/*
    605  1.7.10.1    martin 	 * Get the current stack size and hard limit.
    606  1.7.10.1    martin 	 */
    607  1.7.10.1    martin 	RL(getrlimit(RLIMIT_STACK, &res));
    608  1.7.10.1    martin 	n = res.rlim_cur;
    609  1.7.10.1    martin 
    610  1.7.10.1    martin 	/*
    611  1.7.10.1    martin 	 * Verify that we can't get at pages past the end of the stack
    612  1.7.10.1    martin 	 * right now.
    613  1.7.10.1    martin 	 */
    614  1.7.10.1    martin 	checkstack(n, /*expectsegv*/1);
    615  1.7.10.1    martin 
    616  1.7.10.1    martin 	/*
    617  1.7.10.1    martin 	 * Stop if the hard limit is too small to test.  Not sure
    618  1.7.10.1    martin 	 * exactly how much more space we need to verify that setrlimit
    619  1.7.10.1    martin 	 * actually expands the stack without examining the current
    620  1.7.10.1    martin 	 * stack pointer relative to the process's stack base, so we'll
    621  1.7.10.1    martin 	 * just double the stack size -- definitely enough to test
    622  1.7.10.1    martin 	 * stack growth -- and hope the hard rlimit is big enough to
    623  1.7.10.1    martin 	 * let us double it.
    624  1.7.10.1    martin 	 */
    625  1.7.10.1    martin 	if (n > res.rlim_max/2)
    626  1.7.10.1    martin 		atf_tc_skip("hard stack rlimit is too small");
    627  1.7.10.1    martin 
    628  1.7.10.1    martin 	/*
    629  1.7.10.1    martin 	 * Double the stack size.  This way we can allocate an array of
    630  1.7.10.1    martin 	 * length equal to the current stack size and be guaranteed
    631  1.7.10.1    martin 	 * that (a) it can be allocated, and (b) access to it requires
    632  1.7.10.1    martin 	 * the stack to have grown.
    633  1.7.10.1    martin 	 */
    634  1.7.10.1    martin 	res.rlim_cur = 2*n;
    635  1.7.10.1    martin 	RL(setrlimit(RLIMIT_STACK, &res));
    636  1.7.10.1    martin 
    637  1.7.10.1    martin 	/*
    638  1.7.10.1    martin 	 * Verify that we can now get at pages past the end of the new
    639  1.7.10.1    martin 	 * stack but not beyond that.
    640  1.7.10.1    martin 	 */
    641  1.7.10.1    martin 	checkstack(n, /*expectsegv*/0);
    642  1.7.10.1    martin 	if (n < SIZE_MAX/2)
    643  1.7.10.1    martin 		checkstack(2*n, /*expectsegv*/1);
    644  1.7.10.1    martin 
    645  1.7.10.1    martin 	/*
    646  1.7.10.1    martin 	 * Restore the stack size and verify that we can no longer
    647  1.7.10.1    martin 	 * access an array of length equal to the whole stack size.
    648  1.7.10.1    martin 	 */
    649  1.7.10.1    martin 	res.rlim_cur = n;
    650  1.7.10.1    martin 	RL(setrlimit(RLIMIT_STACK, &res));
    651  1.7.10.1    martin 	checkstack(n, /*expectsegv*/1);
    652  1.7.10.1    martin }
    653  1.7.10.1    martin 
    654       1.1    jruoho ATF_TP_ADD_TCS(tp)
    655       1.1    jruoho {
    656       1.1    jruoho 
    657       1.1    jruoho 	ATF_TP_ADD_TC(tp, setrlimit_basic);
    658       1.1    jruoho 	ATF_TP_ADD_TC(tp, setrlimit_current);
    659       1.1    jruoho 	ATF_TP_ADD_TC(tp, setrlimit_err);
    660       1.1    jruoho 	ATF_TP_ADD_TC(tp, setrlimit_fsize);
    661       1.1    jruoho 	ATF_TP_ADD_TC(tp, setrlimit_memlock);
    662       1.1    jruoho 	ATF_TP_ADD_TC(tp, setrlimit_nofile_1);
    663       1.1    jruoho 	ATF_TP_ADD_TC(tp, setrlimit_nofile_2);
    664       1.1    jruoho 	ATF_TP_ADD_TC(tp, setrlimit_nproc);
    665       1.1    jruoho 	ATF_TP_ADD_TC(tp, setrlimit_perm);
    666       1.4  christos 	ATF_TP_ADD_TC(tp, setrlimit_nthr);
    667       1.5     njoly 	ATF_TP_ADD_TC(tp, setrlimit_stack);
    668  1.7.10.1    martin 	ATF_TP_ADD_TC(tp, setrlimit_stack_growshrink);
    669       1.1    jruoho 
    670       1.1    jruoho 	return atf_no_error();
    671       1.1    jruoho }
    672