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