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