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