t_setrlimit.c revision 313498
1/* $NetBSD: t_setrlimit.c,v 1.5 2016/07/13 09:53:16 njoly Exp $ */ 2 3/*- 4 * Copyright (c) 2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jukka Ruohonen. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31#include <sys/cdefs.h> 32__RCSID("$NetBSD: t_setrlimit.c,v 1.5 2016/07/13 09:53:16 njoly Exp $"); 33 34#include <sys/resource.h> 35#include <sys/mman.h> 36#include <sys/wait.h> 37 38#include <atf-c.h> 39#include <errno.h> 40#include <fcntl.h> 41#include <limits.h> 42#ifdef __NetBSD__ 43#include <lwp.h> 44#endif 45#include <signal.h> 46#include <stdint.h> 47#include <stdio.h> 48#include <stdlib.h> 49#include <string.h> 50#include <ucontext.h> 51#include <unistd.h> 52 53static void sighandler(int); 54static const char path[] = "setrlimit"; 55 56static const int rlimit[] = { 57 RLIMIT_AS, 58 RLIMIT_CORE, 59 RLIMIT_CPU, 60 RLIMIT_DATA, 61 RLIMIT_FSIZE, 62 RLIMIT_MEMLOCK, 63 RLIMIT_NOFILE, 64 RLIMIT_NPROC, 65 RLIMIT_RSS, 66 RLIMIT_SBSIZE, 67 RLIMIT_STACK 68}; 69 70ATF_TC(setrlimit_basic); 71ATF_TC_HEAD(setrlimit_basic, tc) 72{ 73 atf_tc_set_md_var(tc, "descr", "A basic soft limit test"); 74} 75 76ATF_TC_BODY(setrlimit_basic, tc) 77{ 78 struct rlimit res; 79 int *buf, lim; 80 size_t i; 81 82 buf = calloc(__arraycount(rlimit), sizeof(int)); 83 84 if (buf == NULL) 85 atf_tc_fail("initialization failed"); 86 87 for (i = lim = 0; i < __arraycount(rlimit); i++) { 88 89 (void)memset(&res, 0, sizeof(struct rlimit)); 90 91 if (getrlimit(rlimit[i], &res) != 0) 92 continue; 93 94 if (res.rlim_cur == RLIM_INFINITY || res.rlim_cur == 0) 95 continue; 96 97 if (res.rlim_cur == res.rlim_max) /* An unprivileged run. */ 98 continue; 99 100 buf[i] = res.rlim_cur; 101 res.rlim_cur = res.rlim_cur - 1; 102 103 if (setrlimit(rlimit[i], &res) != 0) { 104 lim = rlimit[i]; 105 goto out; 106 } 107 } 108 109out: 110 for (i = 0; i < __arraycount(rlimit); i++) { 111 112 (void)memset(&res, 0, sizeof(struct rlimit)); 113 114 if (buf[i] == 0) 115 continue; 116 117 if (getrlimit(rlimit[i], &res) != 0) 118 continue; 119 120 res.rlim_cur = buf[i]; 121 122 (void)setrlimit(rlimit[i], &res); 123 } 124 125 if (lim != 0) 126 atf_tc_fail("failed to set limit (%d)", lim); 127#ifdef __FreeBSD__ 128 free(buf); 129#endif 130} 131 132ATF_TC(setrlimit_current); 133ATF_TC_HEAD(setrlimit_current, tc) 134{ 135 atf_tc_set_md_var(tc, "descr", "setrlimit(3) with current limits"); 136} 137 138ATF_TC_BODY(setrlimit_current, tc) 139{ 140 struct rlimit res; 141 size_t i; 142 143 for (i = 0; i < __arraycount(rlimit); i++) { 144 145 (void)memset(&res, 0, sizeof(struct rlimit)); 146 147 ATF_REQUIRE(getrlimit(rlimit[i], &res) == 0); 148 ATF_REQUIRE(setrlimit(rlimit[i], &res) == 0); 149 } 150} 151 152ATF_TC(setrlimit_err); 153ATF_TC_HEAD(setrlimit_err, tc) 154{ 155 atf_tc_set_md_var(tc, "descr", "Test error conditions"); 156} 157 158ATF_TC_BODY(setrlimit_err, tc) 159{ 160 struct rlimit res; 161 size_t i; 162 163 for (i = 0; i < __arraycount(rlimit); i++) { 164 165 errno = 0; 166 167 ATF_REQUIRE(getrlimit(rlimit[i], (void *)0) != 0); 168 ATF_REQUIRE(errno == EFAULT); 169 } 170 171 errno = 0; 172 173 ATF_REQUIRE(getrlimit(INT_MAX, &res) != 0); 174 ATF_REQUIRE(errno == EINVAL); 175} 176 177ATF_TC_WITH_CLEANUP(setrlimit_fsize); 178ATF_TC_HEAD(setrlimit_fsize, tc) 179{ 180 atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_FSIZE"); 181} 182 183ATF_TC_BODY(setrlimit_fsize, tc) 184{ 185 struct rlimit res; 186 int fd, sta; 187 pid_t pid; 188 189 fd = open(path, O_RDWR | O_CREAT, 0700); 190 191 if (fd < 0) 192 atf_tc_fail("initialization failed"); 193 194 pid = fork(); 195 ATF_REQUIRE(pid >= 0); 196 197 if (pid == 0) { 198 199 res.rlim_cur = 2; 200 res.rlim_max = 2; 201 202 if (setrlimit(RLIMIT_FSIZE, &res) != 0) 203 _exit(EXIT_FAILURE); 204 205 if (signal(SIGXFSZ, sighandler) == SIG_ERR) 206 _exit(EXIT_FAILURE); 207 208 /* 209 * The third call should generate a SIGXFSZ. 210 */ 211 (void)write(fd, "X", 1); 212 (void)write(fd, "X", 1); 213 (void)write(fd, "X", 1); 214 215 _exit(EXIT_FAILURE); 216 } 217 218 (void)close(fd); 219 (void)wait(&sta); 220 (void)unlink(path); 221 222 if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) 223 atf_tc_fail("RLIMIT_FSIZE not enforced"); 224} 225 226ATF_TC_CLEANUP(setrlimit_fsize, tc) 227{ 228 (void)unlink(path); 229} 230 231static void 232sighandler(int signo) 233{ 234 235 if (signo != SIGXFSZ) 236 _exit(EXIT_FAILURE); 237 238 _exit(EXIT_SUCCESS); 239} 240 241ATF_TC(setrlimit_memlock); 242ATF_TC_HEAD(setrlimit_memlock, tc) 243{ 244 atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_MEMLOCK"); 245} 246 247ATF_TC_BODY(setrlimit_memlock, tc) 248{ 249 struct rlimit res; 250 void *buf; 251 long page; 252 pid_t pid; 253 int sta; 254 255 page = sysconf(_SC_PAGESIZE); 256 ATF_REQUIRE(page >= 0); 257 258 buf = malloc(page); 259 pid = fork(); 260 261 if (buf == NULL || pid < 0) 262 atf_tc_fail("initialization failed"); 263 264 if (pid == 0) { 265 266 /* 267 * Try to lock a page while 268 * RLIMIT_MEMLOCK is zero. 269 */ 270 if (mlock(buf, page) != 0) 271 _exit(EXIT_FAILURE); 272 273 if (munlock(buf, page) != 0) 274 _exit(EXIT_FAILURE); 275 276 res.rlim_cur = 0; 277 res.rlim_max = 0; 278 279 if (setrlimit(RLIMIT_MEMLOCK, &res) != 0) 280 _exit(EXIT_FAILURE); 281 282 if (mlock(buf, page) != 0) 283 _exit(EXIT_SUCCESS); 284 285 (void)munlock(buf, page); 286 287 _exit(EXIT_FAILURE); 288 } 289 290 free(buf); 291 292 (void)wait(&sta); 293 294 if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) 295 atf_tc_fail("RLIMIT_MEMLOCK not enforced"); 296} 297 298ATF_TC(setrlimit_nofile_1); 299ATF_TC_HEAD(setrlimit_nofile_1, tc) 300{ 301 atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NOFILE, #1"); 302} 303 304ATF_TC_BODY(setrlimit_nofile_1, tc) 305{ 306 struct rlimit res; 307 int fd, i, rv, sta; 308 pid_t pid; 309 310 res.rlim_cur = 0; 311 res.rlim_max = 0; 312 313 pid = fork(); 314 ATF_REQUIRE(pid >= 0); 315 316 if (pid == 0) { 317 318 /* 319 * Close all descriptors, set RLIMIT_NOFILE 320 * to zero, and try to open a random file. 321 * This should fail with EMFILE. 322 */ 323 for (i = 0; i < 1024; i++) 324 (void)close(i); 325 326 rv = setrlimit(RLIMIT_NOFILE, &res); 327 328 if (rv != 0) 329 _exit(EXIT_FAILURE); 330 331 errno = 0; 332 fd = open("/etc/passwd", O_RDONLY); 333 334 if (fd >= 0 || errno != EMFILE) 335 _exit(EXIT_FAILURE); 336 337 _exit(EXIT_SUCCESS); 338 } 339 340 (void)wait(&sta); 341 342 if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) 343 atf_tc_fail("RLIMIT_NOFILE not enforced"); 344} 345 346ATF_TC(setrlimit_nofile_2); 347ATF_TC_HEAD(setrlimit_nofile_2, tc) 348{ 349 atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NOFILE, #2"); 350} 351 352ATF_TC_BODY(setrlimit_nofile_2, tc) 353{ 354 static const rlim_t lim = 12; 355 struct rlimit res; 356 int fd, i, rv, sta; 357 pid_t pid; 358 359 /* 360 * See that an arbitrary limit on 361 * open files is being enforced. 362 */ 363 res.rlim_cur = lim; 364 res.rlim_max = lim; 365 366 pid = fork(); 367 ATF_REQUIRE(pid >= 0); 368 369 if (pid == 0) { 370 371 for (i = 0; i < 1024; i++) 372 (void)close(i); 373 374 rv = setrlimit(RLIMIT_NOFILE, &res); 375 376 if (rv != 0) 377 _exit(EXIT_FAILURE); 378 379 for (i = 0; i < (int)lim; i++) { 380 381 fd = open("/etc/passwd", O_RDONLY); 382 383 if (fd < 0) 384 _exit(EXIT_FAILURE); 385 } 386 387 /* 388 * After the limit has been reached, 389 * EMFILE should again follow. 390 */ 391 fd = open("/etc/passwd", O_RDONLY); 392 393 if (fd >= 0 || errno != EMFILE) 394 _exit(EXIT_FAILURE); 395 396 _exit(EXIT_SUCCESS); 397 } 398 399 (void)wait(&sta); 400 401 if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) 402 atf_tc_fail("RLIMIT_NOFILE not enforced"); 403} 404 405ATF_TC(setrlimit_nproc); 406ATF_TC_HEAD(setrlimit_nproc, tc) 407{ 408 atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NPROC"); 409 atf_tc_set_md_var(tc, "require.user", "unprivileged"); 410} 411 412ATF_TC_BODY(setrlimit_nproc, tc) 413{ 414 struct rlimit res; 415 pid_t pid, cpid; 416 int sta; 417 418 pid = fork(); 419 ATF_REQUIRE(pid >= 0); 420 421 if (pid == 0) { 422 423 /* 424 * Set RLIMIT_NPROC to zero and try to fork. 425 */ 426 res.rlim_cur = 0; 427 res.rlim_max = 0; 428 429 if (setrlimit(RLIMIT_NPROC, &res) != 0) 430 _exit(EXIT_FAILURE); 431 432 cpid = fork(); 433 434 if (cpid < 0) 435 _exit(EXIT_SUCCESS); 436 437 _exit(EXIT_FAILURE); 438 } 439 440 (void)waitpid(pid, &sta, 0); 441 442 if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) 443 atf_tc_fail("RLIMIT_NPROC not enforced"); 444} 445 446#ifdef __NetBSD__ 447ATF_TC(setrlimit_nthr); 448ATF_TC_HEAD(setrlimit_nthr, tc) 449{ 450 atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NTHR"); 451 atf_tc_set_md_var(tc, "require.user", "unprivileged"); 452} 453 454static void 455func(lwpid_t *id) 456{ 457 printf("thread %d\n", *id); 458 fflush(stdout); 459 _lwp_exit(); 460} 461 462ATF_TC_BODY(setrlimit_nthr, tc) 463{ 464 struct rlimit res; 465 lwpid_t lwpid; 466 ucontext_t c; 467 468 /* 469 * Set RLIMIT_NTHR to zero and try to create a thread. 470 */ 471 res.rlim_cur = 0; 472 res.rlim_max = 0; 473 ATF_REQUIRE(setrlimit(RLIMIT_NTHR, &res) == 0); 474 ATF_REQUIRE(getcontext(&c) == 0); 475 c.uc_link = NULL; 476 sigemptyset(&c.uc_sigmask); 477 c.uc_stack.ss_flags = 0; 478 c.uc_stack.ss_size = 4096; 479 ATF_REQUIRE((c.uc_stack.ss_sp = malloc(c.uc_stack.ss_size)) != NULL); 480 makecontext(&c, func, 1, &lwpid); 481 ATF_CHECK_ERRNO(EAGAIN, _lwp_create(&c, 0, &lwpid) == -1); 482} 483#endif 484 485ATF_TC(setrlimit_perm); 486ATF_TC_HEAD(setrlimit_perm, tc) 487{ 488 atf_tc_set_md_var(tc, "descr", "Test setrlimit(2) for EPERM"); 489 atf_tc_set_md_var(tc, "require.user", "unprivileged"); 490} 491 492ATF_TC_BODY(setrlimit_perm, tc) 493{ 494 struct rlimit res; 495 size_t i; 496 497 /* 498 * Try to raise the maximum limits as an user. 499 */ 500 for (i = 0; i < __arraycount(rlimit); i++) { 501 502 ATF_REQUIRE(getrlimit(rlimit[i], &res) == 0); 503 504#ifdef __FreeBSD__ 505 if (res.rlim_max == INT64_MAX) /* Overflow. */ 506#else 507 if (res.rlim_max == UINT64_MAX) /* Overflow. */ 508#endif 509 continue; 510 511 errno = 0; 512 res.rlim_max = res.rlim_max + 1; 513 514 ATF_CHECK_ERRNO(EPERM, setrlimit(rlimit[i], &res) != 0); 515 } 516} 517 518ATF_TC(setrlimit_stack); 519ATF_TC_HEAD(setrlimit_stack, tc) 520{ 521 atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_STACK"); 522 atf_tc_set_md_var(tc, "require.user", "unprivileged"); 523} 524 525ATF_TC_BODY(setrlimit_stack, tc) 526{ 527 struct rlimit res; 528 529 /* Ensure soft limit is not bigger than hard limit */ 530 res.rlim_cur = res.rlim_max = 4192256; 531 ATF_REQUIRE(setrlimit(RLIMIT_STACK, &res) == 0); 532 ATF_REQUIRE(getrlimit(RLIMIT_STACK, &res) == 0); 533 ATF_CHECK(res.rlim_cur <= res.rlim_max); 534 535} 536 537ATF_TP_ADD_TCS(tp) 538{ 539 540 ATF_TP_ADD_TC(tp, setrlimit_basic); 541 ATF_TP_ADD_TC(tp, setrlimit_current); 542 ATF_TP_ADD_TC(tp, setrlimit_err); 543 ATF_TP_ADD_TC(tp, setrlimit_fsize); 544 ATF_TP_ADD_TC(tp, setrlimit_memlock); 545 ATF_TP_ADD_TC(tp, setrlimit_nofile_1); 546 ATF_TP_ADD_TC(tp, setrlimit_nofile_2); 547 ATF_TP_ADD_TC(tp, setrlimit_nproc); 548 ATF_TP_ADD_TC(tp, setrlimit_perm); 549#ifdef __NetBSD__ 550 ATF_TP_ADD_TC(tp, setrlimit_nthr); 551#endif 552 ATF_TP_ADD_TC(tp, setrlimit_stack); 553 554 return atf_no_error(); 555} 556