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