1 // SPDX-License-Identifier: GPL-2.0
6 #include <linux/kernel.h>
14 #include <sys/resource.h>
16 #include "../kselftest_harness.h"
17 #include "../clone3/clone3_selftests.h"
19 #ifndef __NR_close_range
21 #define __NR_close_range 546
22 #elif defined _MIPS_SIM
23 #if _MIPS_SIM == _MIPS_SIM_ABI32 /* o32 */
24 #define __NR_close_range (436 + 4000)
26 #if _MIPS_SIM == _MIPS_SIM_NABI32 /* n32 */
27 #define __NR_close_range (436 + 6000)
29 #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */
30 #define __NR_close_range (436 + 5000)
32 #elif defined __ia64__
33 #define __NR_close_range (436 + 1024)
35 #define __NR_close_range 436
39 #ifndef CLOSE_RANGE_UNSHARE
40 #define CLOSE_RANGE_UNSHARE (1U << 1)
43 #ifndef CLOSE_RANGE_CLOEXEC
44 #define CLOSE_RANGE_CLOEXEC (1U << 2)
47 static inline int sys_close_range(unsigned int fd, unsigned int max_fd,
50 return syscall(__NR_close_range, fd, max_fd, flags);
53 TEST(core_close_range)
58 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
61 fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
64 SKIP(return, "Skipping test since /dev/null does not exist");
70 EXPECT_EQ(-1, sys_close_range(open_fds[0], open_fds[100], -1)) {
72 SKIP(return, "close_range() syscall not supported");
75 EXPECT_EQ(0, sys_close_range(open_fds[0], open_fds[50], 0));
77 for (i = 0; i <= 50; i++)
78 EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
80 for (i = 51; i <= 100; i++)
81 EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
83 /* create a couple of gaps */
91 EXPECT_EQ(0, sys_close_range(open_fds[51], open_fds[92], 0));
93 for (i = 51; i <= 92; i++)
94 EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
96 for (i = 93; i <= 100; i++)
97 EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
99 /* test that the kernel caps and still closes all fds */
100 EXPECT_EQ(0, sys_close_range(open_fds[93], open_fds[99], 0));
102 for (i = 93; i <= 99; i++)
103 EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
105 EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
107 EXPECT_EQ(0, sys_close_range(open_fds[100], open_fds[100], 0));
109 EXPECT_EQ(-1, fcntl(open_fds[100], F_GETFL));
112 TEST(close_range_unshare)
117 struct __clone_args args = {
118 .flags = CLONE_FILES,
119 .exit_signal = SIGCHLD,
122 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
125 fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
128 SKIP(return, "Skipping test since /dev/null does not exist");
134 pid = sys_clone3(&args, sizeof(args));
138 ret = sys_close_range(open_fds[0], open_fds[50],
139 CLOSE_RANGE_UNSHARE);
143 for (i = 0; i <= 50; i++)
144 if (fcntl(open_fds[i], F_GETFL) != -1)
147 for (i = 51; i <= 100; i++)
148 if (fcntl(open_fds[i], F_GETFL) == -1)
151 /* create a couple of gaps */
159 ret = sys_close_range(open_fds[51], open_fds[92],
160 CLOSE_RANGE_UNSHARE);
164 for (i = 51; i <= 92; i++)
165 if (fcntl(open_fds[i], F_GETFL) != -1)
168 for (i = 93; i <= 100; i++)
169 if (fcntl(open_fds[i], F_GETFL) == -1)
172 /* test that the kernel caps and still closes all fds */
173 ret = sys_close_range(open_fds[93], open_fds[99],
174 CLOSE_RANGE_UNSHARE);
178 for (i = 93; i <= 99; i++)
179 if (fcntl(open_fds[i], F_GETFL) != -1)
182 if (fcntl(open_fds[100], F_GETFL) == -1)
185 ret = sys_close_range(open_fds[100], open_fds[100],
186 CLOSE_RANGE_UNSHARE);
190 if (fcntl(open_fds[100], F_GETFL) != -1)
196 EXPECT_EQ(waitpid(pid, &status, 0), pid);
197 EXPECT_EQ(true, WIFEXITED(status));
198 EXPECT_EQ(0, WEXITSTATUS(status));
201 TEST(close_range_unshare_capped)
206 struct __clone_args args = {
207 .flags = CLONE_FILES,
208 .exit_signal = SIGCHLD,
211 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
214 fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
217 SKIP(return, "Skipping test since /dev/null does not exist");
223 pid = sys_clone3(&args, sizeof(args));
227 ret = sys_close_range(open_fds[0], UINT_MAX,
228 CLOSE_RANGE_UNSHARE);
232 for (i = 0; i <= 100; i++)
233 if (fcntl(open_fds[i], F_GETFL) != -1)
239 EXPECT_EQ(waitpid(pid, &status, 0), pid);
240 EXPECT_EQ(true, WIFEXITED(status));
241 EXPECT_EQ(0, WEXITSTATUS(status));
244 TEST(close_range_cloexec)
248 struct rlimit rlimit;
250 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
253 fd = open("/dev/null", O_RDONLY);
256 SKIP(return, "Skipping test since /dev/null does not exist");
262 ret = sys_close_range(1000, 1000, CLOSE_RANGE_CLOEXEC);
265 SKIP(return, "close_range() syscall not supported");
267 SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC");
270 /* Ensure the FD_CLOEXEC bit is set also with a resource limit in place. */
271 ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit));
272 rlimit.rlim_cur = 25;
273 ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlimit));
275 /* Set close-on-exec for two ranges: [0-50] and [75-100]. */
276 ret = sys_close_range(open_fds[0], open_fds[50], CLOSE_RANGE_CLOEXEC);
278 ret = sys_close_range(open_fds[75], open_fds[100], CLOSE_RANGE_CLOEXEC);
281 for (i = 0; i <= 50; i++) {
282 int flags = fcntl(open_fds[i], F_GETFD);
284 EXPECT_GT(flags, -1);
285 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
288 for (i = 51; i <= 74; i++) {
289 int flags = fcntl(open_fds[i], F_GETFD);
291 EXPECT_GT(flags, -1);
292 EXPECT_EQ(flags & FD_CLOEXEC, 0);
295 for (i = 75; i <= 100; i++) {
296 int flags = fcntl(open_fds[i], F_GETFD);
298 EXPECT_GT(flags, -1);
299 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
302 /* Test a common pattern. */
303 ret = sys_close_range(3, UINT_MAX, CLOSE_RANGE_CLOEXEC);
304 for (i = 0; i <= 100; i++) {
305 int flags = fcntl(open_fds[i], F_GETFD);
307 EXPECT_GT(flags, -1);
308 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
312 TEST(close_range_cloexec_unshare)
316 struct rlimit rlimit;
318 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
321 fd = open("/dev/null", O_RDONLY);
324 SKIP(return, "Skipping test since /dev/null does not exist");
330 ret = sys_close_range(1000, 1000, CLOSE_RANGE_CLOEXEC);
333 SKIP(return, "close_range() syscall not supported");
335 SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC");
338 /* Ensure the FD_CLOEXEC bit is set also with a resource limit in place. */
339 ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit));
340 rlimit.rlim_cur = 25;
341 ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlimit));
343 /* Set close-on-exec for two ranges: [0-50] and [75-100]. */
344 ret = sys_close_range(open_fds[0], open_fds[50],
345 CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
347 ret = sys_close_range(open_fds[75], open_fds[100],
348 CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
351 for (i = 0; i <= 50; i++) {
352 int flags = fcntl(open_fds[i], F_GETFD);
354 EXPECT_GT(flags, -1);
355 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
358 for (i = 51; i <= 74; i++) {
359 int flags = fcntl(open_fds[i], F_GETFD);
361 EXPECT_GT(flags, -1);
362 EXPECT_EQ(flags & FD_CLOEXEC, 0);
365 for (i = 75; i <= 100; i++) {
366 int flags = fcntl(open_fds[i], F_GETFD);
368 EXPECT_GT(flags, -1);
369 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
372 /* Test a common pattern. */
373 ret = sys_close_range(3, UINT_MAX,
374 CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
375 for (i = 0; i <= 100; i++) {
376 int flags = fcntl(open_fds[i], F_GETFD);
378 EXPECT_GT(flags, -1);
379 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
386 TEST(close_range_cloexec_syzbot)
388 int fd1, fd2, fd3, flags, ret, status;
390 struct __clone_args args = {
391 .flags = CLONE_FILES,
392 .exit_signal = SIGCHLD,
395 /* Create a huge gap in the fd table. */
396 fd1 = open("/dev/null", O_RDWR);
399 fd2 = dup2(fd1, 1000);
402 pid = sys_clone3(&args, sizeof(args));
406 ret = sys_close_range(3, ~0U, CLOSE_RANGE_CLOEXEC);
411 * We now have a private file descriptor table and all
412 * our open fds should still be open but made
415 flags = fcntl(fd1, F_GETFD);
416 EXPECT_GT(flags, -1);
417 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
419 flags = fcntl(fd2, F_GETFD);
420 EXPECT_GT(flags, -1);
421 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
427 * Duplicating the file descriptor must remove the
430 flags = fcntl(fd3, F_GETFD);
431 EXPECT_GT(flags, -1);
432 EXPECT_EQ(flags & FD_CLOEXEC, 0);
437 EXPECT_EQ(waitpid(pid, &status, 0), pid);
438 EXPECT_EQ(true, WIFEXITED(status));
439 EXPECT_EQ(0, WEXITSTATUS(status));
442 * We had a shared file descriptor table before along with requesting
443 * close-on-exec so the original fds must not be close-on-exec.
445 flags = fcntl(fd1, F_GETFD);
446 EXPECT_GT(flags, -1);
447 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
449 flags = fcntl(fd2, F_GETFD);
450 EXPECT_GT(flags, -1);
451 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
456 flags = fcntl(fd3, F_GETFD);
457 EXPECT_GT(flags, -1);
458 EXPECT_EQ(flags & FD_CLOEXEC, 0);
460 EXPECT_EQ(close(fd1), 0);
461 EXPECT_EQ(close(fd2), 0);
462 EXPECT_EQ(close(fd3), 0);
468 TEST(close_range_cloexec_unshare_syzbot)
470 int i, fd1, fd2, fd3, flags, ret, status;
472 struct __clone_args args = {
473 .flags = CLONE_FILES,
474 .exit_signal = SIGCHLD,
478 * Create a huge gap in the fd table. When we now call
479 * CLOSE_RANGE_UNSHARE with a shared fd table and and with ~0U as upper
480 * bound the kernel will only copy up to fd1 file descriptors into the
481 * new fd table. If the kernel is buggy and doesn't handle
482 * CLOSE_RANGE_CLOEXEC correctly it will not have copied all file
483 * descriptors and we will oops!
485 * On a buggy kernel this should immediately oops. But let's loop just
488 fd1 = open("/dev/null", O_RDWR);
491 fd2 = dup2(fd1, 1000);
494 for (i = 0; i < 100; i++) {
496 pid = sys_clone3(&args, sizeof(args));
500 ret = sys_close_range(3, ~0U, CLOSE_RANGE_UNSHARE |
501 CLOSE_RANGE_CLOEXEC);
506 * We now have a private file descriptor table and all
507 * our open fds should still be open but made
510 flags = fcntl(fd1, F_GETFD);
511 EXPECT_GT(flags, -1);
512 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
514 flags = fcntl(fd2, F_GETFD);
515 EXPECT_GT(flags, -1);
516 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
522 * Duplicating the file descriptor must remove the
525 flags = fcntl(fd3, F_GETFD);
526 EXPECT_GT(flags, -1);
527 EXPECT_EQ(flags & FD_CLOEXEC, 0);
529 EXPECT_EQ(close(fd1), 0);
530 EXPECT_EQ(close(fd2), 0);
531 EXPECT_EQ(close(fd3), 0);
536 EXPECT_EQ(waitpid(pid, &status, 0), pid);
537 EXPECT_EQ(true, WIFEXITED(status));
538 EXPECT_EQ(0, WEXITSTATUS(status));
542 * We created a private file descriptor table before along with
543 * requesting close-on-exec so the original fds must not be
546 flags = fcntl(fd1, F_GETFD);
547 EXPECT_GT(flags, -1);
548 EXPECT_EQ(flags & FD_CLOEXEC, 0);
550 flags = fcntl(fd2, F_GETFD);
551 EXPECT_GT(flags, -1);
552 EXPECT_EQ(flags & FD_CLOEXEC, 0);
557 flags = fcntl(fd3, F_GETFD);
558 EXPECT_GT(flags, -1);
559 EXPECT_EQ(flags & FD_CLOEXEC, 0);
561 EXPECT_EQ(close(fd1), 0);
562 EXPECT_EQ(close(fd2), 0);
563 EXPECT_EQ(close(fd3), 0);