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