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