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