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