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