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