t_setrlimit.c revision 1.5.2.1 1 /* $NetBSD: t_setrlimit.c,v 1.5.2.1 2017/03/20 06:57:59 pgoyette 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.2.1 2017/03/20 06:57:59 pgoyette 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