projects/linux·blob master · refs

1617 lines · 38.7 KiB

1// SPDX-License-Identifier: GPL-2.0
2
3#define _GNU_SOURCE
4#include <errno.h>
5#include <fcntl.h>
6#include <linux/kernel.h>
7#include <limits.h>
8#include <stdbool.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <syscall.h>
13#include <unistd.h>
14#include <sys/resource.h>
15#include <linux/close_range.h>
16
17#include "kselftest_harness.h"
18#include "../clone3/clone3_selftests.h"
19
20
21#ifndef F_LINUX_SPECIFIC_BASE
22#define F_LINUX_SPECIFIC_BASE 1024
23#endif
24
25#ifndef F_DUPFD_QUERY
26#define F_DUPFD_QUERY (F_LINUX_SPECIFIC_BASE + 3)
27#endif
28
29#ifndef F_CREATED_QUERY
30#define F_CREATED_QUERY (F_LINUX_SPECIFIC_BASE + 4)
31#endif
32
33static inline int sys_close_range(unsigned int fd, unsigned int max_fd,
34 unsigned int flags)
35{
36 return syscall(__NR_close_range, fd, max_fd, flags);
37}
38
39static void clear_cloexec(const int *fds, size_t n)
40{
41 size_t i;
42
43 for (i = 0; i < n; i++)
44 fcntl(fds[i], F_SETFD, 0);
45}
46
47TEST(core_close_range)
48{
49 int i, ret;
50 int open_fds[101];
51
52 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
53 int fd;
54
55 fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
56 ASSERT_GE(fd, 0) {
57 if (errno == ENOENT)
58 SKIP(return, "Skipping test since /dev/null does not exist");
59 }
60
61 open_fds[i] = fd;
62 }
63
64 EXPECT_EQ(-1, sys_close_range(open_fds[0], open_fds[100], -1)) {
65 if (errno == ENOSYS)
66 SKIP(return, "close_range() syscall not supported");
67 }
68
69 for (i = 0; i < 100; i++) {
70 ret = fcntl(open_fds[i], F_DUPFD_QUERY, open_fds[i + 1]);
71 if (ret < 0) {
72 EXPECT_EQ(errno, EINVAL);
73 } else {
74 EXPECT_EQ(ret, 0);
75 }
76 }
77
78 EXPECT_EQ(0, sys_close_range(open_fds[0], open_fds[50], 0));
79
80 for (i = 0; i <= 50; i++)
81 EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
82
83 for (i = 51; i <= 100; i++)
84 EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
85
86 /* create a couple of gaps */
87 close(57);
88 close(78);
89 close(81);
90 close(82);
91 close(84);
92 close(90);
93
94 EXPECT_EQ(0, sys_close_range(open_fds[51], open_fds[92], 0));
95
96 for (i = 51; i <= 92; i++)
97 EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
98
99 for (i = 93; i <= 100; i++)
100 EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
101
102 /* test that the kernel caps and still closes all fds */
103 EXPECT_EQ(0, sys_close_range(open_fds[93], open_fds[99], 0));
104
105 for (i = 93; i <= 99; i++)
106 EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
107
108 EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
109
110 EXPECT_EQ(0, sys_close_range(open_fds[100], open_fds[100], 0));
111
112 EXPECT_EQ(-1, fcntl(open_fds[100], F_GETFL));
113}
114
115TEST(close_range_unshare)
116{
117 int i, ret, status;
118 pid_t pid;
119 int open_fds[101];
120 struct __clone_args args = {
121 .flags = CLONE_FILES,
122 .exit_signal = SIGCHLD,
123 };
124
125 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
126 int fd;
127
128 fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
129 ASSERT_GE(fd, 0) {
130 if (errno == ENOENT)
131 SKIP(return, "Skipping test since /dev/null does not exist");
132 }
133
134 open_fds[i] = fd;
135 }
136
137 pid = sys_clone3(&args, sizeof(args));
138 ASSERT_GE(pid, 0);
139
140 if (pid == 0) {
141 ret = sys_close_range(open_fds[0], open_fds[50],
142 CLOSE_RANGE_UNSHARE);
143 if (ret)
144 exit(EXIT_FAILURE);
145
146 for (i = 0; i <= 50; i++)
147 if (fcntl(open_fds[i], F_GETFL) != -1)
148 exit(EXIT_FAILURE);
149
150 for (i = 51; i <= 100; i++)
151 if (fcntl(open_fds[i], F_GETFL) == -1)
152 exit(EXIT_FAILURE);
153
154 /* create a couple of gaps */
155 close(57);
156 close(78);
157 close(81);
158 close(82);
159 close(84);
160 close(90);
161
162 ret = sys_close_range(open_fds[51], open_fds[92],
163 CLOSE_RANGE_UNSHARE);
164 if (ret)
165 exit(EXIT_FAILURE);
166
167 for (i = 51; i <= 92; i++)
168 if (fcntl(open_fds[i], F_GETFL) != -1)
169 exit(EXIT_FAILURE);
170
171 for (i = 93; i <= 100; i++)
172 if (fcntl(open_fds[i], F_GETFL) == -1)
173 exit(EXIT_FAILURE);
174
175 /* test that the kernel caps and still closes all fds */
176 ret = sys_close_range(open_fds[93], open_fds[99],
177 CLOSE_RANGE_UNSHARE);
178 if (ret)
179 exit(EXIT_FAILURE);
180
181 for (i = 93; i <= 99; i++)
182 if (fcntl(open_fds[i], F_GETFL) != -1)
183 exit(EXIT_FAILURE);
184
185 if (fcntl(open_fds[100], F_GETFL) == -1)
186 exit(EXIT_FAILURE);
187
188 ret = sys_close_range(open_fds[100], open_fds[100],
189 CLOSE_RANGE_UNSHARE);
190 if (ret)
191 exit(EXIT_FAILURE);
192
193 if (fcntl(open_fds[100], F_GETFL) != -1)
194 exit(EXIT_FAILURE);
195
196 exit(EXIT_SUCCESS);
197 }
198
199 EXPECT_EQ(waitpid(pid, &status, 0), pid);
200 EXPECT_EQ(true, WIFEXITED(status));
201 EXPECT_EQ(0, WEXITSTATUS(status));
202}
203
204TEST(close_range_unshare_capped)
205{
206 int i, ret, status;
207 pid_t pid;
208 int open_fds[101];
209 struct __clone_args args = {
210 .flags = CLONE_FILES,
211 .exit_signal = SIGCHLD,
212 };
213
214 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
215 int fd;
216
217 fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
218 ASSERT_GE(fd, 0) {
219 if (errno == ENOENT)
220 SKIP(return, "Skipping test since /dev/null does not exist");
221 }
222
223 open_fds[i] = fd;
224 }
225
226 pid = sys_clone3(&args, sizeof(args));
227 ASSERT_GE(pid, 0);
228
229 if (pid == 0) {
230 ret = sys_close_range(open_fds[0], UINT_MAX,
231 CLOSE_RANGE_UNSHARE);
232 if (ret)
233 exit(EXIT_FAILURE);
234
235 for (i = 0; i <= 100; i++)
236 if (fcntl(open_fds[i], F_GETFL) != -1)
237 exit(EXIT_FAILURE);
238
239 exit(EXIT_SUCCESS);
240 }
241
242 EXPECT_EQ(waitpid(pid, &status, 0), pid);
243 EXPECT_EQ(true, WIFEXITED(status));
244 EXPECT_EQ(0, WEXITSTATUS(status));
245}
246
247TEST(close_range_unshare_hole)
248{
249 int i, status;
250 pid_t pid;
251 struct __clone_args args = {
252 .flags = CLONE_FILES,
253 .exit_signal = SIGCHLD,
254 };
255
256 /* Fill the first two words of the table. */
257 for (i = 3; i < 128; i++)
258 ASSERT_GE(dup2(0, i), 0);
259
260 pid = sys_clone3(&args, sizeof(args));
261 ASSERT_GE(pid, 0);
262
263 if (pid == 0) {
264 /* Punch a hole into the second word, behind a full first one. */
265 if (sys_close_range(70, 80, CLOSE_RANGE_UNSHARE))
266 exit(EXIT_FAILURE);
267
268 for (i = 3; i < 128; i++) {
269 bool closed = i >= 70 && i <= 80;
270
271 if (closed == (fcntl(i, F_GETFD) != -1))
272 exit(EXIT_FAILURE);
273 }
274
275 /* A stale full bit on word 1 would hand out 128, not 70. */
276 if (dup(0) != 70)
277 exit(EXIT_FAILURE);
278
279 exit(EXIT_SUCCESS);
280 }
281
282 EXPECT_EQ(waitpid(pid, &status, 0), pid);
283 EXPECT_EQ(true, WIFEXITED(status));
284 EXPECT_EQ(0, WEXITSTATUS(status));
285
286 /* The shared table the child unshared from is untouched. */
287 for (i = 3; i < 128; i++)
288 EXPECT_NE(-1, fcntl(i, F_GETFD));
289}
290
291TEST(close_range_cloexec)
292{
293 int i, ret;
294 int open_fds[101];
295 struct rlimit rlimit;
296
297 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
298 int fd;
299
300 fd = open("/dev/null", O_RDONLY);
301 ASSERT_GE(fd, 0) {
302 if (errno == ENOENT)
303 SKIP(return, "Skipping test since /dev/null does not exist");
304 }
305
306 open_fds[i] = fd;
307 }
308
309 ret = sys_close_range(1000, 1000, CLOSE_RANGE_CLOEXEC);
310 if (ret < 0) {
311 if (errno == ENOSYS)
312 SKIP(return, "close_range() syscall not supported");
313 if (errno == EINVAL)
314 SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC");
315 }
316
317 /* Ensure the FD_CLOEXEC bit is set also with a resource limit in place. */
318 ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit));
319 rlimit.rlim_cur = 25;
320 ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlimit));
321
322 /* Set close-on-exec for two ranges: [0-50] and [75-100]. */
323 ret = sys_close_range(open_fds[0], open_fds[50], CLOSE_RANGE_CLOEXEC);
324 ASSERT_EQ(0, ret);
325 ret = sys_close_range(open_fds[75], open_fds[100], CLOSE_RANGE_CLOEXEC);
326 ASSERT_EQ(0, ret);
327
328 for (i = 0; i <= 50; i++) {
329 int flags = fcntl(open_fds[i], F_GETFD);
330
331 EXPECT_GT(flags, -1);
332 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
333 }
334
335 for (i = 51; i <= 74; i++) {
336 int flags = fcntl(open_fds[i], F_GETFD);
337
338 EXPECT_GT(flags, -1);
339 EXPECT_EQ(flags & FD_CLOEXEC, 0);
340 }
341
342 for (i = 75; i <= 100; i++) {
343 int flags = fcntl(open_fds[i], F_GETFD);
344
345 EXPECT_GT(flags, -1);
346 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
347 }
348
349 /* Test a common pattern. */
350 ret = sys_close_range(3, UINT_MAX, CLOSE_RANGE_CLOEXEC);
351 for (i = 0; i <= 100; i++) {
352 int flags = fcntl(open_fds[i], F_GETFD);
353
354 EXPECT_GT(flags, -1);
355 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
356 }
357}
358
359TEST(close_range_cloexec_unshare)
360{
361 int i, ret;
362 int open_fds[101];
363 struct rlimit rlimit;
364
365 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
366 int fd;
367
368 fd = open("/dev/null", O_RDONLY);
369 ASSERT_GE(fd, 0) {
370 if (errno == ENOENT)
371 SKIP(return, "Skipping test since /dev/null does not exist");
372 }
373
374 open_fds[i] = fd;
375 }
376
377 ret = sys_close_range(1000, 1000, CLOSE_RANGE_CLOEXEC);
378 if (ret < 0) {
379 if (errno == ENOSYS)
380 SKIP(return, "close_range() syscall not supported");
381 if (errno == EINVAL)
382 SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC");
383 }
384
385 /* Ensure the FD_CLOEXEC bit is set also with a resource limit in place. */
386 ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit));
387 rlimit.rlim_cur = 25;
388 ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlimit));
389
390 /* Set close-on-exec for two ranges: [0-50] and [75-100]. */
391 ret = sys_close_range(open_fds[0], open_fds[50],
392 CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
393 ASSERT_EQ(0, ret);
394 ret = sys_close_range(open_fds[75], open_fds[100],
395 CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
396 ASSERT_EQ(0, ret);
397
398 for (i = 0; i <= 50; i++) {
399 int flags = fcntl(open_fds[i], F_GETFD);
400
401 EXPECT_GT(flags, -1);
402 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
403 }
404
405 for (i = 51; i <= 74; i++) {
406 int flags = fcntl(open_fds[i], F_GETFD);
407
408 EXPECT_GT(flags, -1);
409 EXPECT_EQ(flags & FD_CLOEXEC, 0);
410 }
411
412 for (i = 75; i <= 100; i++) {
413 int flags = fcntl(open_fds[i], F_GETFD);
414
415 EXPECT_GT(flags, -1);
416 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
417 }
418
419 /* Test a common pattern. */
420 ret = sys_close_range(3, UINT_MAX,
421 CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
422 for (i = 0; i <= 100; i++) {
423 int flags = fcntl(open_fds[i], F_GETFD);
424
425 EXPECT_GT(flags, -1);
426 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
427 }
428}
429
430/*
431 * Regression test for [email protected]
432 */
433TEST(close_range_cloexec_syzbot)
434{
435 int fd1, fd2, fd3, fd4, flags, ret, status;
436 pid_t pid;
437 struct __clone_args args = {
438 .flags = CLONE_FILES,
439 .exit_signal = SIGCHLD,
440 };
441
442 /* Create a huge gap in the fd table. */
443 fd1 = open("/dev/null", O_RDWR);
444 EXPECT_GT(fd1, 0);
445
446 fd2 = dup2(fd1, 1000);
447 EXPECT_GT(fd2, 0);
448
449 flags = fcntl(fd1, F_DUPFD_QUERY, fd2);
450 if (flags < 0) {
451 EXPECT_EQ(errno, EINVAL);
452 } else {
453 EXPECT_EQ(flags, 1);
454 }
455
456 pid = sys_clone3(&args, sizeof(args));
457 ASSERT_GE(pid, 0);
458
459 if (pid == 0) {
460 ret = sys_close_range(3, ~0U, CLOSE_RANGE_CLOEXEC);
461 if (ret)
462 exit(EXIT_FAILURE);
463
464 /*
465 * We now have a private file descriptor table and all
466 * our open fds should still be open but made
467 * close-on-exec.
468 */
469 flags = fcntl(fd1, F_GETFD);
470 EXPECT_GT(flags, -1);
471 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
472
473 flags = fcntl(fd2, F_GETFD);
474 EXPECT_GT(flags, -1);
475 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
476
477 fd3 = dup2(fd1, 42);
478 EXPECT_GT(fd3, 0);
479
480 flags = fcntl(fd1, F_DUPFD_QUERY, fd3);
481 if (flags < 0) {
482 EXPECT_EQ(errno, EINVAL);
483 } else {
484 EXPECT_EQ(flags, 1);
485 }
486
487
488
489 /*
490 * Duplicating the file descriptor must remove the
491 * FD_CLOEXEC flag.
492 */
493 flags = fcntl(fd3, F_GETFD);
494 EXPECT_GT(flags, -1);
495 EXPECT_EQ(flags & FD_CLOEXEC, 0);
496
497 exit(EXIT_SUCCESS);
498 }
499
500 EXPECT_EQ(waitpid(pid, &status, 0), pid);
501 EXPECT_EQ(true, WIFEXITED(status));
502 EXPECT_EQ(0, WEXITSTATUS(status));
503
504 /*
505 * We had a shared file descriptor table before along with requesting
506 * close-on-exec so the original fds must not be close-on-exec.
507 */
508 flags = fcntl(fd1, F_GETFD);
509 EXPECT_GT(flags, -1);
510 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
511
512 flags = fcntl(fd2, F_GETFD);
513 EXPECT_GT(flags, -1);
514 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
515
516 fd3 = dup2(fd1, 42);
517 EXPECT_GT(fd3, 0);
518
519 flags = fcntl(fd1, F_DUPFD_QUERY, fd3);
520 if (flags < 0) {
521 EXPECT_EQ(errno, EINVAL);
522 } else {
523 EXPECT_EQ(flags, 1);
524 }
525
526 fd4 = open("/dev/null", O_RDWR);
527 EXPECT_GT(fd4, 0);
528
529 /* Same inode, different file pointers. */
530 flags = fcntl(fd1, F_DUPFD_QUERY, fd4);
531 if (flags < 0) {
532 EXPECT_EQ(errno, EINVAL);
533 } else {
534 EXPECT_EQ(flags, 0);
535 }
536
537 flags = fcntl(fd3, F_GETFD);
538 EXPECT_GT(flags, -1);
539 EXPECT_EQ(flags & FD_CLOEXEC, 0);
540
541 EXPECT_EQ(close(fd1), 0);
542 EXPECT_EQ(close(fd2), 0);
543 EXPECT_EQ(close(fd3), 0);
544 EXPECT_EQ(close(fd4), 0);
545}
546
547/*
548 * Regression test for [email protected]
549 */
550TEST(close_range_cloexec_unshare_syzbot)
551{
552 int i, fd1, fd2, fd3, flags, ret, status;
553 pid_t pid;
554 struct __clone_args args = {
555 .flags = CLONE_FILES,
556 .exit_signal = SIGCHLD,
557 };
558
559 /*
560 * Create a huge gap in the fd table. When we now call
561 * CLOSE_RANGE_UNSHARE with a shared fd table and and with ~0U as upper
562 * bound the kernel will only copy up to fd1 file descriptors into the
563 * new fd table. If the kernel is buggy and doesn't handle
564 * CLOSE_RANGE_CLOEXEC correctly it will not have copied all file
565 * descriptors and we will oops!
566 *
567 * On a buggy kernel this should immediately oops. But let's loop just
568 * to be sure.
569 */
570 fd1 = open("/dev/null", O_RDWR);
571 EXPECT_GT(fd1, 0);
572
573 fd2 = dup2(fd1, 1000);
574 EXPECT_GT(fd2, 0);
575
576 for (i = 0; i < 100; i++) {
577
578 pid = sys_clone3(&args, sizeof(args));
579 ASSERT_GE(pid, 0);
580
581 if (pid == 0) {
582 ret = sys_close_range(3, ~0U, CLOSE_RANGE_UNSHARE |
583 CLOSE_RANGE_CLOEXEC);
584 if (ret)
585 exit(EXIT_FAILURE);
586
587 /*
588 * We now have a private file descriptor table and all
589 * our open fds should still be open but made
590 * close-on-exec.
591 */
592 flags = fcntl(fd1, F_GETFD);
593 EXPECT_GT(flags, -1);
594 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
595
596 flags = fcntl(fd2, F_GETFD);
597 EXPECT_GT(flags, -1);
598 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
599
600 fd3 = dup2(fd1, 42);
601 EXPECT_GT(fd3, 0);
602
603 /*
604 * Duplicating the file descriptor must remove the
605 * FD_CLOEXEC flag.
606 */
607 flags = fcntl(fd3, F_GETFD);
608 EXPECT_GT(flags, -1);
609 EXPECT_EQ(flags & FD_CLOEXEC, 0);
610
611 EXPECT_EQ(close(fd1), 0);
612 EXPECT_EQ(close(fd2), 0);
613 EXPECT_EQ(close(fd3), 0);
614
615 exit(EXIT_SUCCESS);
616 }
617
618 EXPECT_EQ(waitpid(pid, &status, 0), pid);
619 EXPECT_EQ(true, WIFEXITED(status));
620 EXPECT_EQ(0, WEXITSTATUS(status));
621 }
622
623 /*
624 * We created a private file descriptor table before along with
625 * requesting close-on-exec so the original fds must not be
626 * close-on-exec.
627 */
628 flags = fcntl(fd1, F_GETFD);
629 EXPECT_GT(flags, -1);
630 EXPECT_EQ(flags & FD_CLOEXEC, 0);
631
632 flags = fcntl(fd2, F_GETFD);
633 EXPECT_GT(flags, -1);
634 EXPECT_EQ(flags & FD_CLOEXEC, 0);
635
636 fd3 = dup2(fd1, 42);
637 EXPECT_GT(fd3, 0);
638
639 flags = fcntl(fd3, F_GETFD);
640 EXPECT_GT(flags, -1);
641 EXPECT_EQ(flags & FD_CLOEXEC, 0);
642
643 EXPECT_EQ(close(fd1), 0);
644 EXPECT_EQ(close(fd2), 0);
645 EXPECT_EQ(close(fd3), 0);
646}
647
648TEST(close_range_except)
649{
650 int i, ret, status;
651 pid_t pid;
652 int open_fds[101];
653 struct __clone_args args = {
654 .exit_signal = SIGCHLD,
655 };
656
657 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
658 int fd;
659
660 fd = open("/dev/null", O_RDONLY);
661 ASSERT_GE(fd, 0) {
662 if (errno == ENOENT)
663 SKIP(return, "Skipping test since /dev/null does not exist");
664 }
665
666 open_fds[i] = fd;
667 }
668
669 /* A range covering everything keeps everything. */
670 ret = sys_close_range(0, UINT_MAX, CLOSE_RANGE_EXCEPT);
671 if (ret < 0) {
672 if (errno == ENOSYS)
673 SKIP(return, "close_range() syscall not supported");
674 if (errno == EINVAL)
675 SKIP(return, "close_range() doesn't support CLOSE_RANGE_EXCEPT");
676 }
677 ASSERT_EQ(0, ret);
678
679 for (i = 0; i < ARRAY_SIZE(open_fds); i++)
680 EXPECT_NE(-1, fcntl(open_fds[i], F_GETFD));
681
682 /* The bounds are checked before the range is turned around. */
683 EXPECT_EQ(-1, sys_close_range(open_fds[20], open_fds[10],
684 CLOSE_RANGE_EXCEPT));
685 EXPECT_EQ(EINVAL, errno);
686
687 /* Everything above open_fds[50] goes. */
688 ASSERT_EQ(0, sys_close_range(0, open_fds[50], CLOSE_RANGE_EXCEPT));
689
690 for (i = 0; i < ARRAY_SIZE(open_fds); i++)
691 EXPECT_EQ(i <= 50, fcntl(open_fds[i], F_GETFD) != -1);
692
693 /* A window in the middle takes stdio with it, so do that in a fork. */
694 pid = sys_clone3(&args, sizeof(args));
695 ASSERT_GE(pid, 0);
696
697 if (pid == 0) {
698 ret = sys_close_range(open_fds[10], open_fds[20],
699 CLOSE_RANGE_EXCEPT);
700 if (ret)
701 exit(EXIT_FAILURE);
702
703 for (i = 0; i <= 50; i++) {
704 bool kept = i >= 10 && i <= 20;
705
706 if (kept != (fcntl(open_fds[i], F_GETFD) != -1))
707 exit(EXIT_FAILURE);
708 }
709
710 if (fcntl(STDERR_FILENO, F_GETFD) != -1)
711 exit(EXIT_FAILURE);
712
713 exit(EXIT_SUCCESS);
714 }
715
716 EXPECT_EQ(waitpid(pid, &status, 0), pid);
717 EXPECT_EQ(true, WIFEXITED(status));
718 EXPECT_EQ(0, WEXITSTATUS(status));
719
720 /* The fork had a table of its own. */
721 for (i = 0; i <= 50; i++)
722 EXPECT_NE(-1, fcntl(open_fds[i], F_GETFD));
723}
724
725TEST(close_range_except_cloexec)
726{
727 int i, ret;
728 int open_fds[101];
729
730 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
731 int fd;
732
733 fd = open("/dev/null", O_RDONLY);
734 ASSERT_GE(fd, 0) {
735 if (errno == ENOENT)
736 SKIP(return, "Skipping test since /dev/null does not exist");
737 }
738
739 open_fds[i] = fd;
740 }
741
742 ret = sys_close_range(open_fds[10], open_fds[20],
743 CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_EXCEPT);
744 if (ret < 0) {
745 if (errno == ENOSYS)
746 SKIP(return, "close_range() syscall not supported");
747 if (errno == EINVAL)
748 SKIP(return, "close_range() doesn't support CLOSE_RANGE_EXCEPT");
749 }
750 ASSERT_EQ(0, ret);
751
752 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
753 bool inside = i >= 10 && i <= 20;
754 int flags = fcntl(open_fds[i], F_GETFD);
755
756 EXPECT_NE(-1, flags);
757 EXPECT_EQ(inside ? 0 : FD_CLOEXEC, flags & FD_CLOEXEC);
758 }
759
760 /* stdio sits outside of the window too. */
761 EXPECT_EQ(FD_CLOEXEC, fcntl(STDERR_FILENO, F_GETFD) & FD_CLOEXEC);
762
763 /* A window that starts at 0 marks only what lies above it. */
764 clear_cloexec(open_fds, ARRAY_SIZE(open_fds));
765 ASSERT_EQ(0, fcntl(STDERR_FILENO, F_SETFD, 0));
766 ASSERT_EQ(0, sys_close_range(0, open_fds[20],
767 CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_EXCEPT));
768
769 for (i = 0; i < ARRAY_SIZE(open_fds); i++)
770 EXPECT_EQ(i <= 20 ? 0 : FD_CLOEXEC,
771 fcntl(open_fds[i], F_GETFD) & FD_CLOEXEC);
772 EXPECT_EQ(0, fcntl(STDERR_FILENO, F_GETFD) & FD_CLOEXEC);
773
774 /* One at the top marks only what lies below it, stdio included. */
775 clear_cloexec(open_fds, ARRAY_SIZE(open_fds));
776 ASSERT_EQ(0, sys_close_range(open_fds[80], UINT_MAX,
777 CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_EXCEPT));
778
779 for (i = 0; i < ARRAY_SIZE(open_fds); i++)
780 EXPECT_EQ(i < 80 ? FD_CLOEXEC : 0,
781 fcntl(open_fds[i], F_GETFD) & FD_CLOEXEC);
782 EXPECT_EQ(FD_CLOEXEC, fcntl(STDERR_FILENO, F_GETFD) & FD_CLOEXEC);
783
784 /* One that cannot hold a descriptor marks everything. */
785 clear_cloexec(open_fds, ARRAY_SIZE(open_fds));
786 ASSERT_EQ(0, fcntl(STDERR_FILENO, F_SETFD, 0));
787 ASSERT_EQ(0, sys_close_range(UINT_MAX, UINT_MAX,
788 CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_EXCEPT));
789
790 for (i = 0; i < ARRAY_SIZE(open_fds); i++)
791 EXPECT_EQ(FD_CLOEXEC, fcntl(open_fds[i], F_GETFD) & FD_CLOEXEC);
792 EXPECT_EQ(FD_CLOEXEC, fcntl(STDERR_FILENO, F_GETFD) & FD_CLOEXEC);
793}
794
795TEST(close_range_except_cloexec_unshare)
796{
797 int i, ret, status;
798 pid_t pid;
799 int open_fds[101];
800 struct __clone_args args = {
801 .flags = CLONE_FILES,
802 .exit_signal = SIGCHLD,
803 };
804
805 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
806 int fd;
807
808 fd = open("/dev/null", O_RDONLY);
809 ASSERT_GE(fd, 0) {
810 if (errno == ENOENT)
811 SKIP(return, "Skipping test since /dev/null does not exist");
812 }
813
814 open_fds[i] = fd;
815 }
816
817 /* A range covering everything marks nothing. */
818 ret = sys_close_range(0, UINT_MAX,
819 CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_EXCEPT);
820 if (ret < 0) {
821 if (errno == ENOSYS)
822 SKIP(return, "close_range() syscall not supported");
823 if (errno == EINVAL)
824 SKIP(return, "close_range() doesn't support CLOSE_RANGE_EXCEPT");
825 }
826 ASSERT_EQ(0, ret);
827
828 for (i = 0; i < ARRAY_SIZE(open_fds); i++)
829 EXPECT_EQ(0, fcntl(open_fds[i], F_GETFD) & FD_CLOEXEC);
830
831 pid = sys_clone3(&args, sizeof(args));
832 ASSERT_GE(pid, 0);
833
834 if (pid == 0) {
835 ret = sys_close_range(open_fds[10], open_fds[20],
836 CLOSE_RANGE_UNSHARE | CLOSE_RANGE_CLOEXEC |
837 CLOSE_RANGE_EXCEPT);
838 if (ret)
839 exit(EXIT_FAILURE);
840
841 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
842 bool inside = i >= 10 && i <= 20;
843 int flags = fcntl(open_fds[i], F_GETFD);
844
845 if (flags == -1)
846 exit(EXIT_FAILURE);
847 if ((flags & FD_CLOEXEC) != (inside ? 0 : FD_CLOEXEC))
848 exit(EXIT_FAILURE);
849 }
850
851 exit(EXIT_SUCCESS);
852 }
853
854 EXPECT_EQ(waitpid(pid, &status, 0), pid);
855 EXPECT_EQ(true, WIFEXITED(status));
856 EXPECT_EQ(0, WEXITSTATUS(status));
857
858 /* The shared table the child unshared from is untouched. */
859 for (i = 0; i < ARRAY_SIZE(open_fds); i++)
860 EXPECT_EQ(0, fcntl(open_fds[i], F_GETFD) & FD_CLOEXEC);
861}
862
863TEST(close_range_except_bounds)
864{
865 int i, c, ret, status;
866 pid_t pid;
867 int open_fds[101];
868 struct __clone_args args = {
869 .exit_signal = SIGCHLD,
870 };
871
872 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
873 int fd;
874
875 fd = open("/dev/null", O_RDONLY);
876 ASSERT_GE(fd, 0) {
877 if (errno == ENOENT)
878 SKIP(return, "Skipping test since /dev/null does not exist");
879 }
880
881 open_fds[i] = fd;
882 }
883
884 /* A range covering everything keeps everything. */
885 ret = sys_close_range(0, UINT_MAX, CLOSE_RANGE_EXCEPT);
886 if (ret < 0) {
887 if (errno == ENOSYS)
888 SKIP(return, "close_range() syscall not supported");
889 if (errno == EINVAL)
890 SKIP(return, "close_range() doesn't support CLOSE_RANGE_EXCEPT");
891 }
892 ASSERT_EQ(0, ret);
893
894 struct {
895 unsigned int fd, max_fd, flags;
896 } cases[] = {
897 /* A window at the top drops everything below it. */
898 { open_fds[50], UINT_MAX, CLOSE_RANGE_EXCEPT },
899 /* One that cannot hold a descriptor keeps nothing. */
900 { UINT_MAX, UINT_MAX, CLOSE_RANGE_EXCEPT },
901 /* One of a single descriptor keeps just that. */
902 { open_fds[30], open_fds[30], CLOSE_RANGE_EXCEPT },
903 /* The unshare form on a table that is not shared acts in place. */
904 { open_fds[10], open_fds[20],
905 CLOSE_RANGE_UNSHARE | CLOSE_RANGE_EXCEPT },
906 };
907
908 /* Each of them takes stdio with it, so do that in a fork. */
909 for (c = 0; c < ARRAY_SIZE(cases); c++) {
910 pid = sys_clone3(&args, sizeof(args));
911 ASSERT_GE(pid, 0);
912
913 if (pid == 0) {
914 ret = sys_close_range(cases[c].fd, cases[c].max_fd,
915 cases[c].flags);
916 if (ret)
917 exit(EXIT_FAILURE);
918
919 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
920 unsigned int fd = open_fds[i];
921 bool kept = fd >= cases[c].fd &&
922 fd <= cases[c].max_fd;
923
924 if (kept != (fcntl(fd, F_GETFD) != -1))
925 exit(EXIT_FAILURE);
926 }
927
928 if (fcntl(STDERR_FILENO, F_GETFD) != -1)
929 exit(EXIT_FAILURE);
930
931 exit(EXIT_SUCCESS);
932 }
933
934 EXPECT_EQ(waitpid(pid, &status, 0), pid);
935 EXPECT_EQ(true, WIFEXITED(status));
936 EXPECT_EQ(0, WEXITSTATUS(status));
937 }
938
939 /* Each fork had a table of its own. */
940 for (i = 0; i < ARRAY_SIZE(open_fds); i++)
941 EXPECT_NE(-1, fcntl(open_fds[i], F_GETFD));
942}
943
944TEST(close_range_except_unshare)
945{
946 int i, ret, status;
947 pid_t pid;
948 int open_fds[200];
949 struct __clone_args args = {
950 .flags = CLONE_FILES,
951 .exit_signal = SIGCHLD,
952 };
953
954 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
955 int fd;
956
957 /* Odd slots are close-on-exec, which makes no difference here. */
958 fd = open("/dev/null", O_RDONLY | (i % 2 ? O_CLOEXEC : 0));
959 ASSERT_GE(fd, 0) {
960 if (errno == ENOENT)
961 SKIP(return, "Skipping test since /dev/null does not exist");
962 }
963
964 open_fds[i] = fd;
965 }
966
967 /* A range covering everything keeps everything. */
968 ret = sys_close_range(0, UINT_MAX, CLOSE_RANGE_EXCEPT);
969 if (ret < 0) {
970 if (errno == ENOSYS)
971 SKIP(return, "close_range() syscall not supported");
972 if (errno == EINVAL)
973 SKIP(return, "close_range() doesn't support CLOSE_RANGE_EXCEPT");
974 }
975 ASSERT_EQ(0, ret);
976
977 pid = sys_clone3(&args, sizeof(args));
978 ASSERT_GE(pid, 0);
979
980 if (pid == 0) {
981 /* The window sits near the top, so the clone is sized off its end. */
982 ret = sys_close_range(open_fds[150], open_fds[160],
983 CLOSE_RANGE_UNSHARE | CLOSE_RANGE_EXCEPT);
984 if (ret)
985 exit(EXIT_FAILURE);
986
987 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
988 bool kept = i >= 150 && i <= 160;
989
990 if (kept != (fcntl(open_fds[i], F_GETFD) != -1))
991 exit(EXIT_FAILURE);
992 }
993
994 if (fcntl(STDERR_FILENO, F_GETFD) != -1)
995 exit(EXIT_FAILURE);
996
997 /* What was left behind is handed out again, from the bottom. */
998 if (dup(open_fds[150]) != 0)
999 exit(EXIT_FAILURE);
1000
1001 exit(EXIT_SUCCESS);
1002 }
1003
1004 EXPECT_EQ(waitpid(pid, &status, 0), pid);
1005 EXPECT_EQ(true, WIFEXITED(status));
1006 EXPECT_EQ(0, WEXITSTATUS(status));
1007
1008 /* A window at the bottom keeps just that, stdio included. */
1009 pid = sys_clone3(&args, sizeof(args));
1010 ASSERT_GE(pid, 0);
1011
1012 if (pid == 0) {
1013 ret = sys_close_range(0, open_fds[10],
1014 CLOSE_RANGE_UNSHARE | CLOSE_RANGE_EXCEPT);
1015 if (ret)
1016 exit(EXIT_FAILURE);
1017
1018 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
1019 if ((i <= 10) != (fcntl(open_fds[i], F_GETFD) != -1))
1020 exit(EXIT_FAILURE);
1021 }
1022
1023 if (fcntl(STDERR_FILENO, F_GETFD) == -1)
1024 exit(EXIT_FAILURE);
1025
1026 /* The first slot left behind is the next one handed out. */
1027 if (dup(0) != open_fds[10] + 1)
1028 exit(EXIT_FAILURE);
1029
1030 exit(EXIT_SUCCESS);
1031 }
1032
1033 EXPECT_EQ(waitpid(pid, &status, 0), pid);
1034 EXPECT_EQ(true, WIFEXITED(status));
1035 EXPECT_EQ(0, WEXITSTATUS(status));
1036
1037 /* A window that cannot hold a descriptor keeps nothing. */
1038 pid = sys_clone3(&args, sizeof(args));
1039 ASSERT_GE(pid, 0);
1040
1041 if (pid == 0) {
1042 ret = sys_close_range(UINT_MAX, UINT_MAX,
1043 CLOSE_RANGE_UNSHARE | CLOSE_RANGE_EXCEPT);
1044 if (ret)
1045 exit(EXIT_FAILURE);
1046
1047 for (i = 0; i < ARRAY_SIZE(open_fds); i++)
1048 if (fcntl(open_fds[i], F_GETFD) != -1)
1049 exit(EXIT_FAILURE);
1050
1051 if (fcntl(STDERR_FILENO, F_GETFD) != -1)
1052 exit(EXIT_FAILURE);
1053
1054 exit(EXIT_SUCCESS);
1055 }
1056
1057 EXPECT_EQ(waitpid(pid, &status, 0), pid);
1058 EXPECT_EQ(true, WIFEXITED(status));
1059 EXPECT_EQ(0, WEXITSTATUS(status));
1060
1061 /* The shared table the child unshared from is untouched. */
1062 for (i = 0; i < ARRAY_SIZE(open_fds); i++)
1063 EXPECT_NE(-1, fcntl(open_fds[i], F_GETFD));
1064}
1065
1066TEST(close_range_cloexec_only)
1067{
1068 int i, ret;
1069 int open_fds[101];
1070
1071 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
1072 int fd;
1073
1074 /* Odd slots are close-on-exec, even ones are not. */
1075 fd = open("/dev/null", O_RDONLY | (i % 2 ? O_CLOEXEC : 0));
1076 ASSERT_GE(fd, 0) {
1077 if (errno == ENOENT)
1078 SKIP(return, "Skipping test since /dev/null does not exist");
1079 }
1080
1081 open_fds[i] = fd;
1082 }
1083
1084 ret = sys_close_range(open_fds[10], open_fds[20],
1085 CLOSE_RANGE_CLOEXEC_ONLY);
1086 if (ret < 0) {
1087 if (errno == ENOSYS)
1088 SKIP(return, "close_range() syscall not supported");
1089 if (errno == EINVAL)
1090 SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC_ONLY");
1091 }
1092 ASSERT_EQ(0, ret);
1093
1094 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
1095 bool closed = i % 2 && i >= 10 && i <= 20;
1096
1097 EXPECT_EQ(!closed, fcntl(open_fds[i], F_GETFD) != -1);
1098 }
1099
1100 /* A range above the table closes nothing. */
1101 ASSERT_EQ(0, sys_close_range(UINT_MAX, UINT_MAX,
1102 CLOSE_RANGE_CLOEXEC_ONLY));
1103
1104 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
1105 bool closed = i % 2 && i >= 10 && i <= 20;
1106
1107 EXPECT_EQ(!closed, fcntl(open_fds[i], F_GETFD) != -1);
1108 }
1109
1110 /* Do what an exec would do to the rest. */
1111 ASSERT_EQ(0, sys_close_range(0, UINT_MAX, CLOSE_RANGE_CLOEXEC_ONLY));
1112
1113 for (i = 0; i < ARRAY_SIZE(open_fds); i++)
1114 EXPECT_EQ(!(i % 2), fcntl(open_fds[i], F_GETFD) != -1);
1115}
1116
1117TEST(close_range_cloexec_only_except)
1118{
1119 int i, ret;
1120 int open_fds[101];
1121
1122 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
1123 int fd;
1124
1125 fd = open("/dev/null", O_RDONLY | (i % 2 ? O_CLOEXEC : 0));
1126 ASSERT_GE(fd, 0) {
1127 if (errno == ENOENT)
1128 SKIP(return, "Skipping test since /dev/null does not exist");
1129 }
1130
1131 open_fds[i] = fd;
1132 }
1133
1134 ret = sys_close_range(open_fds[10], open_fds[20],
1135 CLOSE_RANGE_CLOEXEC_ONLY | CLOSE_RANGE_EXCEPT);
1136 if (ret < 0) {
1137 if (errno == ENOSYS)
1138 SKIP(return, "close_range() syscall not supported");
1139 if (errno == EINVAL)
1140 SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC_ONLY");
1141 }
1142 ASSERT_EQ(0, ret);
1143
1144 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
1145 bool kept = !(i % 2) || (i >= 10 && i <= 20);
1146 int flags = i % 2 ? FD_CLOEXEC : 0;
1147
1148 /* The kept ones keep their flag, so exec still drops them. */
1149 EXPECT_EQ(kept ? flags : -1, fcntl(open_fds[i], F_GETFD));
1150 }
1151
1152 /* A range that cannot hold an open descriptor keeps nothing. */
1153 ASSERT_EQ(0, sys_close_range(UINT_MAX, UINT_MAX,
1154 CLOSE_RANGE_CLOEXEC_ONLY |
1155 CLOSE_RANGE_EXCEPT));
1156
1157 for (i = 0; i < ARRAY_SIZE(open_fds); i++)
1158 EXPECT_EQ(!(i % 2), fcntl(open_fds[i], F_GETFD) != -1);
1159}
1160
1161TEST(close_range_cloexec_only_except_bounds)
1162{
1163 int i, c, ret, status;
1164 pid_t pid;
1165 int open_fds[101];
1166 struct __clone_args args = {
1167 .exit_signal = SIGCHLD,
1168 };
1169
1170 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
1171 int fd;
1172
1173 fd = open("/dev/null", O_RDONLY | (i % 2 ? O_CLOEXEC : 0));
1174 ASSERT_GE(fd, 0) {
1175 if (errno == ENOENT)
1176 SKIP(return, "Skipping test since /dev/null does not exist");
1177 }
1178
1179 open_fds[i] = fd;
1180 }
1181
1182 /* A range covering everything keeps everything. */
1183 ret = sys_close_range(0, UINT_MAX,
1184 CLOSE_RANGE_CLOEXEC_ONLY | CLOSE_RANGE_EXCEPT);
1185 if (ret < 0) {
1186 if (errno == ENOSYS)
1187 SKIP(return, "close_range() syscall not supported");
1188 if (errno == EINVAL)
1189 SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC_ONLY");
1190 }
1191 ASSERT_EQ(0, ret);
1192
1193 struct {
1194 unsigned int fd, max_fd;
1195 } cases[] = {
1196 /* A window at the top keeps the marked ones in it. */
1197 { open_fds[80], UINT_MAX },
1198 /* One at the bottom keeps the marked ones in it. */
1199 { 0, open_fds[20] },
1200 /* One that cannot hold a descriptor keeps none of them. */
1201 { UINT_MAX, UINT_MAX },
1202 };
1203
1204 for (c = 0; c < ARRAY_SIZE(cases); c++) {
1205 pid = sys_clone3(&args, sizeof(args));
1206 ASSERT_GE(pid, 0);
1207
1208 if (pid == 0) {
1209 ret = sys_close_range(cases[c].fd, cases[c].max_fd,
1210 CLOSE_RANGE_CLOEXEC_ONLY |
1211 CLOSE_RANGE_EXCEPT);
1212 if (ret)
1213 exit(EXIT_FAILURE);
1214
1215 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
1216 unsigned int fd = open_fds[i];
1217 bool kept = !(i % 2) || (fd >= cases[c].fd &&
1218 fd <= cases[c].max_fd);
1219 int flags = i % 2 ? FD_CLOEXEC : 0;
1220
1221 if (fcntl(fd, F_GETFD) != (kept ? flags : -1))
1222 exit(EXIT_FAILURE);
1223 }
1224
1225 /* stdio is neither marked nor gone. */
1226 if (fcntl(STDERR_FILENO, F_GETFD) & FD_CLOEXEC)
1227 exit(EXIT_FAILURE);
1228
1229 exit(EXIT_SUCCESS);
1230 }
1231
1232 EXPECT_EQ(waitpid(pid, &status, 0), pid);
1233 EXPECT_EQ(true, WIFEXITED(status));
1234 EXPECT_EQ(0, WEXITSTATUS(status));
1235 }
1236
1237 /* Each fork had a table of its own. */
1238 for (i = 0; i < ARRAY_SIZE(open_fds); i++)
1239 EXPECT_NE(-1, fcntl(open_fds[i], F_GETFD));
1240}
1241
1242TEST(close_range_cloexec_only_unshare)
1243{
1244 int i, ret, status;
1245 pid_t pid;
1246 int open_fds[101];
1247 struct __clone_args args = {
1248 .flags = CLONE_FILES,
1249 .exit_signal = SIGCHLD,
1250 };
1251
1252 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
1253 int fd;
1254
1255 fd = open("/dev/null", O_RDONLY | (i % 2 ? O_CLOEXEC : 0));
1256 ASSERT_GE(fd, 0) {
1257 if (errno == ENOENT)
1258 SKIP(return, "Skipping test since /dev/null does not exist");
1259 }
1260
1261 open_fds[i] = fd;
1262 }
1263
1264 /* A range covering everything keeps everything. */
1265 ret = sys_close_range(0, UINT_MAX,
1266 CLOSE_RANGE_CLOEXEC_ONLY | CLOSE_RANGE_EXCEPT);
1267 if (ret < 0) {
1268 if (errno == ENOSYS)
1269 SKIP(return, "close_range() syscall not supported");
1270 if (errno == EINVAL)
1271 SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC_ONLY");
1272 }
1273 ASSERT_EQ(0, ret);
1274
1275 for (i = 0; i < ARRAY_SIZE(open_fds); i++)
1276 ASSERT_NE(-1, fcntl(open_fds[i], F_GETFD));
1277
1278 pid = sys_clone3(&args, sizeof(args));
1279 ASSERT_GE(pid, 0);
1280
1281 if (pid == 0) {
1282 ret = sys_close_range(open_fds[10], open_fds[20],
1283 CLOSE_RANGE_UNSHARE |
1284 CLOSE_RANGE_CLOEXEC_ONLY);
1285 if (ret)
1286 exit(EXIT_FAILURE);
1287
1288 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
1289 bool closed = i % 2 && i >= 10 && i <= 20;
1290
1291 if (closed == (fcntl(open_fds[i], F_GETFD) != -1))
1292 exit(EXIT_FAILURE);
1293 }
1294
1295 exit(EXIT_SUCCESS);
1296 }
1297
1298 EXPECT_EQ(waitpid(pid, &status, 0), pid);
1299 EXPECT_EQ(true, WIFEXITED(status));
1300 EXPECT_EQ(0, WEXITSTATUS(status));
1301
1302 /* A range at the top keeps the descriptors without the flag in it. */
1303 pid = sys_clone3(&args, sizeof(args));
1304 ASSERT_GE(pid, 0);
1305
1306 if (pid == 0) {
1307 ret = sys_close_range(open_fds[50], UINT_MAX,
1308 CLOSE_RANGE_UNSHARE |
1309 CLOSE_RANGE_CLOEXEC_ONLY);
1310 if (ret)
1311 exit(EXIT_FAILURE);
1312
1313 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
1314 bool closed = i % 2 && i >= 50;
1315
1316 if (closed == (fcntl(open_fds[i], F_GETFD) != -1))
1317 exit(EXIT_FAILURE);
1318 }
1319
1320 /* The first slot left behind is the next one handed out. */
1321 if (dup(0) != open_fds[51])
1322 exit(EXIT_FAILURE);
1323
1324 exit(EXIT_SUCCESS);
1325 }
1326
1327 EXPECT_EQ(waitpid(pid, &status, 0), pid);
1328 EXPECT_EQ(true, WIFEXITED(status));
1329 EXPECT_EQ(0, WEXITSTATUS(status));
1330
1331 /* The shared table the child unshared from is untouched. */
1332 for (i = 0; i < ARRAY_SIZE(open_fds); i++)
1333 EXPECT_NE(-1, fcntl(open_fds[i], F_GETFD));
1334}
1335
1336TEST(close_range_cloexec_only_except_unshare)
1337{
1338 int i, ret, status;
1339 pid_t pid;
1340 int open_fds[101];
1341 struct __clone_args args = {
1342 .flags = CLONE_FILES,
1343 .exit_signal = SIGCHLD,
1344 };
1345
1346 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
1347 int fd;
1348
1349 fd = open("/dev/null", O_RDONLY | (i % 2 ? O_CLOEXEC : 0));
1350 ASSERT_GE(fd, 0) {
1351 if (errno == ENOENT)
1352 SKIP(return, "Skipping test since /dev/null does not exist");
1353 }
1354
1355 open_fds[i] = fd;
1356 }
1357
1358 /* A range covering everything keeps everything. */
1359 ret = sys_close_range(0, UINT_MAX,
1360 CLOSE_RANGE_CLOEXEC_ONLY | CLOSE_RANGE_EXCEPT);
1361 if (ret < 0) {
1362 if (errno == ENOSYS)
1363 SKIP(return, "close_range() syscall not supported");
1364 if (errno == EINVAL)
1365 SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC_ONLY");
1366 }
1367 ASSERT_EQ(0, ret);
1368
1369 for (i = 0; i < ARRAY_SIZE(open_fds); i++)
1370 ASSERT_NE(-1, fcntl(open_fds[i], F_GETFD));
1371
1372 pid = sys_clone3(&args, sizeof(args));
1373 ASSERT_GE(pid, 0);
1374
1375 if (pid == 0) {
1376 ret = sys_close_range(open_fds[10], open_fds[20],
1377 CLOSE_RANGE_UNSHARE |
1378 CLOSE_RANGE_CLOEXEC_ONLY |
1379 CLOSE_RANGE_EXCEPT);
1380 if (ret)
1381 exit(EXIT_FAILURE);
1382
1383 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
1384 bool kept = !(i % 2) || (i >= 10 && i <= 20);
1385 int flags = i % 2 ? FD_CLOEXEC : 0;
1386
1387 if (fcntl(open_fds[i], F_GETFD) != (kept ? flags : -1))
1388 exit(EXIT_FAILURE);
1389 }
1390
1391 exit(EXIT_SUCCESS);
1392 }
1393
1394 EXPECT_EQ(waitpid(pid, &status, 0), pid);
1395 EXPECT_EQ(true, WIFEXITED(status));
1396 EXPECT_EQ(0, WEXITSTATUS(status));
1397
1398 /* A window that cannot hold a descriptor keeps none of the marked. */
1399 pid = sys_clone3(&args, sizeof(args));
1400 ASSERT_GE(pid, 0);
1401
1402 if (pid == 0) {
1403 ret = sys_close_range(UINT_MAX, UINT_MAX,
1404 CLOSE_RANGE_UNSHARE |
1405 CLOSE_RANGE_CLOEXEC_ONLY |
1406 CLOSE_RANGE_EXCEPT);
1407 if (ret)
1408 exit(EXIT_FAILURE);
1409
1410 for (i = 0; i < ARRAY_SIZE(open_fds); i++)
1411 if ((i % 2) == (fcntl(open_fds[i], F_GETFD) != -1))
1412 exit(EXIT_FAILURE);
1413
1414 if (fcntl(STDERR_FILENO, F_GETFD) == -1)
1415 exit(EXIT_FAILURE);
1416
1417 exit(EXIT_SUCCESS);
1418 }
1419
1420 EXPECT_EQ(waitpid(pid, &status, 0), pid);
1421 EXPECT_EQ(true, WIFEXITED(status));
1422 EXPECT_EQ(0, WEXITSTATUS(status));
1423
1424 /* One that covers everything keeps everything, in a clone too. */
1425 pid = sys_clone3(&args, sizeof(args));
1426 ASSERT_GE(pid, 0);
1427
1428 if (pid == 0) {
1429 ret = sys_close_range(0, UINT_MAX,
1430 CLOSE_RANGE_UNSHARE |
1431 CLOSE_RANGE_CLOEXEC_ONLY |
1432 CLOSE_RANGE_EXCEPT);
1433 if (ret)
1434 exit(EXIT_FAILURE);
1435
1436 for (i = 0; i < ARRAY_SIZE(open_fds); i++)
1437 if (fcntl(open_fds[i], F_GETFD) != (i % 2 ? FD_CLOEXEC : 0))
1438 exit(EXIT_FAILURE);
1439
1440 exit(EXIT_SUCCESS);
1441 }
1442
1443 EXPECT_EQ(waitpid(pid, &status, 0), pid);
1444 EXPECT_EQ(true, WIFEXITED(status));
1445 EXPECT_EQ(0, WEXITSTATUS(status));
1446
1447 /* The shared table the child unshared from is untouched. */
1448 for (i = 0; i < ARRAY_SIZE(open_fds); i++)
1449 EXPECT_NE(-1, fcntl(open_fds[i], F_GETFD));
1450}
1451
1452TEST(close_range_cloexec_only_except_unshare_sizing)
1453{
1454 int i, ret, status;
1455 pid_t pid;
1456 int open_fds[200];
1457 struct __clone_args args = {
1458 .flags = CLONE_FILES,
1459 .exit_signal = SIGCHLD,
1460 };
1461
1462 /* All close-on-exec, so the kept range alone sizes the clone. */
1463 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
1464 int fd;
1465
1466 fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
1467 ASSERT_GE(fd, 0) {
1468 if (errno == ENOENT)
1469 SKIP(return, "Skipping test since /dev/null does not exist");
1470 }
1471
1472 open_fds[i] = fd;
1473 }
1474
1475 ret = sys_close_range(0, UINT_MAX,
1476 CLOSE_RANGE_CLOEXEC_ONLY | CLOSE_RANGE_EXCEPT);
1477 if (ret < 0) {
1478 if (errno == ENOSYS)
1479 SKIP(return, "close_range() syscall not supported");
1480 if (errno == EINVAL)
1481 SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC_ONLY");
1482 }
1483 ASSERT_EQ(0, ret);
1484
1485 pid = sys_clone3(&args, sizeof(args));
1486 ASSERT_GE(pid, 0);
1487
1488 if (pid == 0) {
1489 ret = sys_close_range(open_fds[150], open_fds[160],
1490 CLOSE_RANGE_UNSHARE |
1491 CLOSE_RANGE_CLOEXEC_ONLY |
1492 CLOSE_RANGE_EXCEPT);
1493 if (ret)
1494 exit(EXIT_FAILURE);
1495
1496 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
1497 bool kept = i >= 150 && i <= 160;
1498
1499 if (kept != (fcntl(open_fds[i], F_GETFD) != -1))
1500 exit(EXIT_FAILURE);
1501 }
1502
1503 /* Nothing set close-on-exec on stdio. */
1504 if (fcntl(STDERR_FILENO, F_GETFD) == -1)
1505 exit(EXIT_FAILURE);
1506
1507 exit(EXIT_SUCCESS);
1508 }
1509
1510 EXPECT_EQ(waitpid(pid, &status, 0), pid);
1511 EXPECT_EQ(true, WIFEXITED(status));
1512 EXPECT_EQ(0, WEXITSTATUS(status));
1513}
1514
1515TEST(close_range_cloexec_only_einval)
1516{
1517 int ret;
1518
1519 /* A range covering everything keeps everything, so this only probes. */
1520 ret = sys_close_range(0, UINT_MAX,
1521 CLOSE_RANGE_CLOEXEC_ONLY | CLOSE_RANGE_EXCEPT);
1522 if (ret < 0) {
1523 if (errno == ENOSYS)
1524 SKIP(return, "close_range() syscall not supported");
1525 if (errno == EINVAL)
1526 SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC_ONLY");
1527 }
1528 ASSERT_EQ(0, ret);
1529
1530 EXPECT_EQ(-1, sys_close_range(3, UINT_MAX, CLOSE_RANGE_CLOEXEC |
1531 CLOSE_RANGE_CLOEXEC_ONLY));
1532 EXPECT_EQ(EINVAL, errno);
1533
1534 /* The other flags do not make the pair acceptable. */
1535 EXPECT_EQ(-1, sys_close_range(3, UINT_MAX, CLOSE_RANGE_UNSHARE |
1536 CLOSE_RANGE_CLOEXEC |
1537 CLOSE_RANGE_CLOEXEC_ONLY |
1538 CLOSE_RANGE_EXCEPT));
1539 EXPECT_EQ(EINVAL, errno);
1540
1541 /* The bounds are checked with the new flag too. */
1542 EXPECT_EQ(-1, sys_close_range(4, 3, CLOSE_RANGE_CLOEXEC_ONLY |
1543 CLOSE_RANGE_EXCEPT));
1544 EXPECT_EQ(EINVAL, errno);
1545}
1546
1547TEST(close_range_bitmap_corruption)
1548{
1549 pid_t pid;
1550 int status;
1551 struct __clone_args args = {
1552 .flags = CLONE_FILES,
1553 .exit_signal = SIGCHLD,
1554 };
1555
1556 /* get the first 128 descriptors open */
1557 for (int i = 2; i < 128; i++)
1558 EXPECT_GE(dup2(0, i), 0);
1559
1560 /* get descriptor table shared */
1561 pid = sys_clone3(&args, sizeof(args));
1562 ASSERT_GE(pid, 0);
1563
1564 if (pid == 0) {
1565 /* unshare and truncate descriptor table down to 64 */
1566 if (sys_close_range(64, ~0U, CLOSE_RANGE_UNSHARE))
1567 exit(EXIT_FAILURE);
1568
1569 ASSERT_EQ(fcntl(64, F_GETFD), -1);
1570 /* ... and verify that the range 64..127 is not
1571 stuck "fully used" according to secondary bitmap */
1572 EXPECT_EQ(dup(0), 64)
1573 exit(EXIT_FAILURE);
1574 exit(EXIT_SUCCESS);
1575 }
1576
1577 EXPECT_EQ(waitpid(pid, &status, 0), pid);
1578 EXPECT_EQ(true, WIFEXITED(status));
1579 EXPECT_EQ(0, WEXITSTATUS(status));
1580}
1581
1582TEST(fcntl_created)
1583{
1584 for (int i = 0; i < 101; i++) {
1585 int fd;
1586 char path[PATH_MAX];
1587
1588 fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
1589 ASSERT_GE(fd, 0) {
1590 if (errno == ENOENT)
1591 SKIP(return,
1592 "Skipping test since /dev/null does not exist");
1593 }
1594
1595 /* We didn't create "/dev/null". */
1596 EXPECT_EQ(fcntl(fd, F_CREATED_QUERY, 0), 0);
1597 close(fd);
1598
1599 sprintf(path, "aaaa_%d", i);
1600 fd = open(path, O_CREAT | O_RDONLY | O_CLOEXEC, 0600);
1601 ASSERT_GE(fd, 0);
1602
1603 /* We created "aaaa_%d". */
1604 EXPECT_EQ(fcntl(fd, F_CREATED_QUERY, 0), 1);
1605 close(fd);
1606
1607 fd = open(path, O_RDONLY | O_CLOEXEC);
1608 ASSERT_GE(fd, 0);
1609
1610 /* We're opening it again, so no positive creation check. */
1611 EXPECT_EQ(fcntl(fd, F_CREATED_QUERY, 0), 0);
1612 close(fd);
1613 unlink(path);
1614 }
1615}
1616
1617TEST_HARNESS_MAIN