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