Home | History | Annotate | Line # | Download | only in sys
t_setrlimit.c revision 1.11
      1  1.11  riastrad /* $NetBSD: t_setrlimit.c,v 1.11 2023/12/07 16:54:44 riastradh 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.11  riastrad __RCSID("$NetBSD: t_setrlimit.c,v 1.11 2023/12/07 16:54:44 riastradh 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.8  riastrad #include "h_macros.h"
     52   1.8  riastrad 
     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.8  riastrad ATF_TC(setrlimit_stack_growshrink);
    530   1.8  riastrad ATF_TC_HEAD(setrlimit_stack_growshrink, tc)
    531   1.8  riastrad {
    532   1.8  riastrad 	atf_tc_set_md_var(tc, "descr",
    533   1.8  riastrad 	    "Test that setrlimit(2), RLIMIT_STACK, grows & shrinks the stack");
    534   1.8  riastrad }
    535   1.8  riastrad 
    536   1.8  riastrad /*
    537  1.11  riastrad  * checkstackchild(n)
    538  1.11  riastrad  *
    539  1.11  riastrad  *	Allocate an array of size n on the stack, and verify it can be
    540  1.11  riastrad  *	used.  If it can't be used, this will crash with SIGSEGV,
    541  1.11  riastrad  *	deliberately.
    542  1.11  riastrad  */
    543  1.11  riastrad _Pragma("GCC diagnostic push")
    544  1.11  riastrad _Pragma("GCC diagnostic ignored \"-Wstack-protector\"")
    545  1.11  riastrad static void
    546  1.11  riastrad checkstackchild(size_t n)
    547  1.11  riastrad {
    548  1.11  riastrad 	volatile char *const x = alloca(n);
    549  1.11  riastrad 	size_t i;
    550  1.11  riastrad 
    551  1.11  riastrad 	for (i = 0; i < n; i++)
    552  1.11  riastrad 		x[i] = 0x1a;
    553  1.11  riastrad }
    554  1.11  riastrad _Pragma("GCC diagnostic pop")
    555  1.11  riastrad 
    556  1.11  riastrad /*
    557  1.10  riastrad  * checkstack(n, expectsegv)
    558   1.8  riastrad  *
    559   1.8  riastrad  *	Check whether we can allocate an array of size n on the stack.
    560   1.8  riastrad  *
    561   1.8  riastrad  *	- If expectsegv, verify that access fails with SIGSEGV.
    562   1.8  riastrad  *	- If not expectsegv, verify that access succeeds.
    563   1.8  riastrad  *
    564   1.8  riastrad  *	Do this in a subprocess rather than with a SIGSEGV handler,
    565   1.8  riastrad  *	because once we've allocated an array of size n on the stack,
    566   1.8  riastrad  *	in the case where the stack is inaccessible, we have just
    567   1.8  riastrad  *	trashed the stack pointer so badly we can't make function calls
    568   1.8  riastrad  *	like to a SIGSEGV handler.
    569   1.8  riastrad  *
    570   1.8  riastrad  *	(We could use an alternate signal stack, but I already wrote it
    571   1.8  riastrad  *	this way, and this is a little simpler and more robust than
    572   1.8  riastrad  *	juggling signals, setjmp/longjmp, and sigaltstack.)
    573   1.8  riastrad  */
    574   1.8  riastrad static void
    575   1.8  riastrad checkstack(size_t n, int expectsegv)
    576   1.8  riastrad {
    577   1.8  riastrad 	pid_t forked, waited;
    578   1.8  riastrad 	int status;
    579   1.8  riastrad 
    580   1.8  riastrad 	RL(forked = fork());
    581   1.8  riastrad 	if (forked == 0) {	/* child */
    582  1.11  riastrad 		checkstackchild(n);
    583   1.8  riastrad 		_exit(expectsegv);
    584   1.8  riastrad 	}
    585   1.8  riastrad 
    586   1.8  riastrad 	/* parent */
    587   1.8  riastrad 	RL(waited = waitpid(forked, &status, 0));
    588   1.8  riastrad 	ATF_REQUIRE_EQ_MSG(waited, forked, "waited=%jd forked=%jd",
    589   1.8  riastrad 	    (intmax_t)waited, (intmax_t)forked);
    590   1.8  riastrad 	if (expectsegv) {
    591   1.8  riastrad 		ATF_REQUIRE_MSG(!WIFEXITED(status),
    592   1.8  riastrad 		    "expected signal but exited normally with status %d",
    593   1.8  riastrad 		    WEXITSTATUS(status));
    594   1.8  riastrad 		ATF_REQUIRE_MSG(WIFSIGNALED(status), "status=0x%x", status);
    595   1.8  riastrad 		ATF_REQUIRE_EQ_MSG(WTERMSIG(status), SIGSEGV, "termsig=%d",
    596   1.8  riastrad 		    WTERMSIG(status));
    597   1.8  riastrad 	} else {
    598   1.8  riastrad 		ATF_REQUIRE_MSG(!WIFSIGNALED(status),
    599  1.10  riastrad 		    "expected normal exit but terminated on signal %d",
    600   1.8  riastrad 		    WTERMSIG(status));
    601   1.8  riastrad 		ATF_REQUIRE_MSG(WIFEXITED(status), "status=0x%x", status);
    602   1.8  riastrad 		ATF_REQUIRE_EQ_MSG(WEXITSTATUS(status), 0, "exitstatus=%d",
    603   1.8  riastrad 		    WEXITSTATUS(status));
    604   1.8  riastrad 	}
    605   1.8  riastrad }
    606   1.8  riastrad 
    607   1.8  riastrad ATF_TC_BODY(setrlimit_stack_growshrink, tc)
    608   1.8  riastrad {
    609   1.8  riastrad 	struct rlimit res;
    610   1.8  riastrad 	size_t n;
    611   1.8  riastrad 
    612   1.8  riastrad 	/*
    613   1.8  riastrad 	 * Disable core dumps -- we're going to deliberately cause
    614   1.8  riastrad 	 * SIGSEGV to test stack accessibility (which breaks even
    615   1.8  riastrad 	 * calling a function so we can't just use a SIGSEGV handler),
    616   1.8  riastrad 	 * so let's not waste time dumping core.
    617   1.8  riastrad 	 */
    618   1.8  riastrad 	res = (struct rlimit){ .rlim_cur = 0, .rlim_max = 0 };
    619   1.8  riastrad 	RL(setrlimit(RLIMIT_CORE, &res));
    620   1.8  riastrad 
    621   1.8  riastrad 	/*
    622   1.8  riastrad 	 * Get the current stack size and hard limit.
    623   1.8  riastrad 	 */
    624   1.8  riastrad 	RL(getrlimit(RLIMIT_STACK, &res));
    625   1.8  riastrad 	n = res.rlim_cur;
    626   1.8  riastrad 
    627   1.8  riastrad 	/*
    628   1.8  riastrad 	 * Verify that we can't get at pages past the end of the stack
    629   1.8  riastrad 	 * right now.
    630   1.8  riastrad 	 */
    631   1.8  riastrad 	checkstack(n, /*expectsegv*/1);
    632   1.8  riastrad 
    633   1.8  riastrad 	/*
    634   1.8  riastrad 	 * Stop if the hard limit is too small to test.  Not sure
    635   1.8  riastrad 	 * exactly how much more space we need to verify that setrlimit
    636   1.8  riastrad 	 * actually expands the stack without examining the current
    637   1.8  riastrad 	 * stack pointer relative to the process's stack base, so we'll
    638   1.8  riastrad 	 * just double the stack size -- definitely enough to test
    639   1.8  riastrad 	 * stack growth -- and hope the hard rlimit is big enough to
    640   1.8  riastrad 	 * let us double it.
    641   1.8  riastrad 	 */
    642   1.8  riastrad 	if (n > res.rlim_max/2)
    643   1.8  riastrad 		atf_tc_skip("hard stack rlimit is too small");
    644   1.8  riastrad 
    645   1.8  riastrad 	/*
    646   1.8  riastrad 	 * Double the stack size.  This way we can allocate an array of
    647   1.8  riastrad 	 * length equal to the current stack size and be guaranteed
    648   1.8  riastrad 	 * that (a) it can be allocated, and (b) access to it requires
    649   1.8  riastrad 	 * the stack to have grown.
    650   1.8  riastrad 	 */
    651   1.8  riastrad 	res.rlim_cur = 2*n;
    652   1.8  riastrad 	RL(setrlimit(RLIMIT_STACK, &res));
    653   1.8  riastrad 
    654   1.8  riastrad 	/*
    655   1.8  riastrad 	 * Verify that we can now get at pages past the end of the new
    656   1.8  riastrad 	 * stack but not beyond that.
    657   1.8  riastrad 	 */
    658   1.8  riastrad 	checkstack(n, /*expectsegv*/0);
    659   1.8  riastrad 	if (n < SIZE_MAX/2)
    660   1.8  riastrad 		checkstack(2*n, /*expectsegv*/1);
    661   1.8  riastrad 
    662   1.8  riastrad 	/*
    663   1.8  riastrad 	 * Restore the stack size and verify that we can no longer
    664   1.8  riastrad 	 * access an array of length equal to the whole stack size.
    665   1.8  riastrad 	 */
    666   1.8  riastrad 	res.rlim_cur = n;
    667   1.8  riastrad 	RL(setrlimit(RLIMIT_STACK, &res));
    668   1.8  riastrad 	checkstack(n, /*expectsegv*/1);
    669   1.8  riastrad }
    670   1.8  riastrad 
    671   1.1    jruoho ATF_TP_ADD_TCS(tp)
    672   1.1    jruoho {
    673   1.1    jruoho 
    674   1.1    jruoho 	ATF_TP_ADD_TC(tp, setrlimit_basic);
    675   1.1    jruoho 	ATF_TP_ADD_TC(tp, setrlimit_current);
    676   1.1    jruoho 	ATF_TP_ADD_TC(tp, setrlimit_err);
    677   1.1    jruoho 	ATF_TP_ADD_TC(tp, setrlimit_fsize);
    678   1.1    jruoho 	ATF_TP_ADD_TC(tp, setrlimit_memlock);
    679   1.1    jruoho 	ATF_TP_ADD_TC(tp, setrlimit_nofile_1);
    680   1.1    jruoho 	ATF_TP_ADD_TC(tp, setrlimit_nofile_2);
    681   1.1    jruoho 	ATF_TP_ADD_TC(tp, setrlimit_nproc);
    682   1.1    jruoho 	ATF_TP_ADD_TC(tp, setrlimit_perm);
    683   1.4  christos 	ATF_TP_ADD_TC(tp, setrlimit_nthr);
    684   1.5     njoly 	ATF_TP_ADD_TC(tp, setrlimit_stack);
    685   1.8  riastrad 	ATF_TP_ADD_TC(tp, setrlimit_stack_growshrink);
    686   1.1    jruoho 
    687   1.1    jruoho 	return atf_no_error();
    688   1.1    jruoho }
    689