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 static inline int sys_close_range(unsigned int fd, unsigned int max_fd,
22 return syscall(__NR_close_range, fd, max_fd, flags);
25 TEST(core_close_range)
30 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
33 fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
36 SKIP(return, "Skipping test since /dev/null does not exist");
42 EXPECT_EQ(-1, sys_close_range(open_fds[0], open_fds[100], -1)) {
44 SKIP(return, "close_range() syscall not supported");
47 EXPECT_EQ(0, sys_close_range(open_fds[0], open_fds[50], 0));
49 for (i = 0; i <= 50; i++)
50 EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
52 for (i = 51; i <= 100; i++)
53 EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
55 /* create a couple of gaps */
63 EXPECT_EQ(0, sys_close_range(open_fds[51], open_fds[92], 0));
65 for (i = 51; i <= 92; i++)
66 EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
68 for (i = 93; i <= 100; i++)
69 EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
71 /* test that the kernel caps and still closes all fds */
72 EXPECT_EQ(0, sys_close_range(open_fds[93], open_fds[99], 0));
74 for (i = 93; i <= 99; i++)
75 EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
77 EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
79 EXPECT_EQ(0, sys_close_range(open_fds[100], open_fds[100], 0));
81 EXPECT_EQ(-1, fcntl(open_fds[100], F_GETFL));
84 TEST(close_range_unshare)
89 struct __clone_args args = {
91 .exit_signal = SIGCHLD,
94 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
97 fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
100 SKIP(return, "Skipping test since /dev/null does not exist");
106 pid = sys_clone3(&args, sizeof(args));
110 ret = sys_close_range(open_fds[0], open_fds[50],
111 CLOSE_RANGE_UNSHARE);
115 for (i = 0; i <= 50; i++)
116 if (fcntl(open_fds[i], F_GETFL) != -1)
119 for (i = 51; i <= 100; i++)
120 if (fcntl(open_fds[i], F_GETFL) == -1)
123 /* create a couple of gaps */
131 ret = sys_close_range(open_fds[51], open_fds[92],
132 CLOSE_RANGE_UNSHARE);
136 for (i = 51; i <= 92; i++)
137 if (fcntl(open_fds[i], F_GETFL) != -1)
140 for (i = 93; i <= 100; i++)
141 if (fcntl(open_fds[i], F_GETFL) == -1)
144 /* test that the kernel caps and still closes all fds */
145 ret = sys_close_range(open_fds[93], open_fds[99],
146 CLOSE_RANGE_UNSHARE);
150 for (i = 93; i <= 99; i++)
151 if (fcntl(open_fds[i], F_GETFL) != -1)
154 if (fcntl(open_fds[100], F_GETFL) == -1)
157 ret = sys_close_range(open_fds[100], open_fds[100],
158 CLOSE_RANGE_UNSHARE);
162 if (fcntl(open_fds[100], F_GETFL) != -1)
168 EXPECT_EQ(waitpid(pid, &status, 0), pid);
169 EXPECT_EQ(true, WIFEXITED(status));
170 EXPECT_EQ(0, WEXITSTATUS(status));
173 TEST(close_range_unshare_capped)
178 struct __clone_args args = {
179 .flags = CLONE_FILES,
180 .exit_signal = SIGCHLD,
183 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
186 fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
189 SKIP(return, "Skipping test since /dev/null does not exist");
195 pid = sys_clone3(&args, sizeof(args));
199 ret = sys_close_range(open_fds[0], UINT_MAX,
200 CLOSE_RANGE_UNSHARE);
204 for (i = 0; i <= 100; i++)
205 if (fcntl(open_fds[i], F_GETFL) != -1)
211 EXPECT_EQ(waitpid(pid, &status, 0), pid);
212 EXPECT_EQ(true, WIFEXITED(status));
213 EXPECT_EQ(0, WEXITSTATUS(status));
216 TEST(close_range_cloexec)
220 struct rlimit rlimit;
222 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
225 fd = open("/dev/null", O_RDONLY);
228 SKIP(return, "Skipping test since /dev/null does not exist");
234 ret = sys_close_range(1000, 1000, CLOSE_RANGE_CLOEXEC);
237 SKIP(return, "close_range() syscall not supported");
239 SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC");
242 /* Ensure the FD_CLOEXEC bit is set also with a resource limit in place. */
243 ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit));
244 rlimit.rlim_cur = 25;
245 ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlimit));
247 /* Set close-on-exec for two ranges: [0-50] and [75-100]. */
248 ret = sys_close_range(open_fds[0], open_fds[50], CLOSE_RANGE_CLOEXEC);
250 ret = sys_close_range(open_fds[75], open_fds[100], CLOSE_RANGE_CLOEXEC);
253 for (i = 0; i <= 50; i++) {
254 int flags = fcntl(open_fds[i], F_GETFD);
256 EXPECT_GT(flags, -1);
257 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
260 for (i = 51; i <= 74; i++) {
261 int flags = fcntl(open_fds[i], F_GETFD);
263 EXPECT_GT(flags, -1);
264 EXPECT_EQ(flags & FD_CLOEXEC, 0);
267 for (i = 75; i <= 100; i++) {
268 int flags = fcntl(open_fds[i], F_GETFD);
270 EXPECT_GT(flags, -1);
271 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
274 /* Test a common pattern. */
275 ret = sys_close_range(3, UINT_MAX, CLOSE_RANGE_CLOEXEC);
276 for (i = 0; i <= 100; i++) {
277 int flags = fcntl(open_fds[i], F_GETFD);
279 EXPECT_GT(flags, -1);
280 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
284 TEST(close_range_cloexec_unshare)
288 struct rlimit rlimit;
290 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
293 fd = open("/dev/null", O_RDONLY);
296 SKIP(return, "Skipping test since /dev/null does not exist");
302 ret = sys_close_range(1000, 1000, CLOSE_RANGE_CLOEXEC);
305 SKIP(return, "close_range() syscall not supported");
307 SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC");
310 /* Ensure the FD_CLOEXEC bit is set also with a resource limit in place. */
311 ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit));
312 rlimit.rlim_cur = 25;
313 ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlimit));
315 /* Set close-on-exec for two ranges: [0-50] and [75-100]. */
316 ret = sys_close_range(open_fds[0], open_fds[50],
317 CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
319 ret = sys_close_range(open_fds[75], open_fds[100],
320 CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
323 for (i = 0; i <= 50; i++) {
324 int flags = fcntl(open_fds[i], F_GETFD);
326 EXPECT_GT(flags, -1);
327 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
330 for (i = 51; i <= 74; i++) {
331 int flags = fcntl(open_fds[i], F_GETFD);
333 EXPECT_GT(flags, -1);
334 EXPECT_EQ(flags & FD_CLOEXEC, 0);
337 for (i = 75; i <= 100; i++) {
338 int flags = fcntl(open_fds[i], F_GETFD);
340 EXPECT_GT(flags, -1);
341 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
344 /* Test a common pattern. */
345 ret = sys_close_range(3, UINT_MAX,
346 CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
347 for (i = 0; i <= 100; i++) {
348 int flags = fcntl(open_fds[i], F_GETFD);
350 EXPECT_GT(flags, -1);
351 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
356 * Regression test for syzbot+96cfd2b22b3213646a93@syzkaller.appspotmail.com
358 TEST(close_range_cloexec_syzbot)
360 int fd1, fd2, fd3, flags, ret, status;
362 struct __clone_args args = {
363 .flags = CLONE_FILES,
364 .exit_signal = SIGCHLD,
367 /* Create a huge gap in the fd table. */
368 fd1 = open("/dev/null", O_RDWR);
371 fd2 = dup2(fd1, 1000);
374 pid = sys_clone3(&args, sizeof(args));
378 ret = sys_close_range(3, ~0U, CLOSE_RANGE_CLOEXEC);
383 * We now have a private file descriptor table and all
384 * our open fds should still be open but made
387 flags = fcntl(fd1, F_GETFD);
388 EXPECT_GT(flags, -1);
389 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
391 flags = fcntl(fd2, F_GETFD);
392 EXPECT_GT(flags, -1);
393 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
399 * Duplicating the file descriptor must remove the
402 flags = fcntl(fd3, F_GETFD);
403 EXPECT_GT(flags, -1);
404 EXPECT_EQ(flags & FD_CLOEXEC, 0);
409 EXPECT_EQ(waitpid(pid, &status, 0), pid);
410 EXPECT_EQ(true, WIFEXITED(status));
411 EXPECT_EQ(0, WEXITSTATUS(status));
414 * We had a shared file descriptor table before along with requesting
415 * close-on-exec so the original fds must not be close-on-exec.
417 flags = fcntl(fd1, F_GETFD);
418 EXPECT_GT(flags, -1);
419 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
421 flags = fcntl(fd2, F_GETFD);
422 EXPECT_GT(flags, -1);
423 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
428 flags = fcntl(fd3, F_GETFD);
429 EXPECT_GT(flags, -1);
430 EXPECT_EQ(flags & FD_CLOEXEC, 0);
432 EXPECT_EQ(close(fd1), 0);
433 EXPECT_EQ(close(fd2), 0);
434 EXPECT_EQ(close(fd3), 0);
438 * Regression test for syzbot+96cfd2b22b3213646a93@syzkaller.appspotmail.com
440 TEST(close_range_cloexec_unshare_syzbot)
442 int i, fd1, fd2, fd3, flags, ret, status;
444 struct __clone_args args = {
445 .flags = CLONE_FILES,
446 .exit_signal = SIGCHLD,
450 * Create a huge gap in the fd table. When we now call
451 * CLOSE_RANGE_UNSHARE with a shared fd table and and with ~0U as upper
452 * bound the kernel will only copy up to fd1 file descriptors into the
453 * new fd table. If the kernel is buggy and doesn't handle
454 * CLOSE_RANGE_CLOEXEC correctly it will not have copied all file
455 * descriptors and we will oops!
457 * On a buggy kernel this should immediately oops. But let's loop just
460 fd1 = open("/dev/null", O_RDWR);
463 fd2 = dup2(fd1, 1000);
466 for (i = 0; i < 100; i++) {
468 pid = sys_clone3(&args, sizeof(args));
472 ret = sys_close_range(3, ~0U, CLOSE_RANGE_UNSHARE |
473 CLOSE_RANGE_CLOEXEC);
478 * We now have a private file descriptor table and all
479 * our open fds should still be open but made
482 flags = fcntl(fd1, F_GETFD);
483 EXPECT_GT(flags, -1);
484 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
486 flags = fcntl(fd2, F_GETFD);
487 EXPECT_GT(flags, -1);
488 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
494 * Duplicating the file descriptor must remove the
497 flags = fcntl(fd3, F_GETFD);
498 EXPECT_GT(flags, -1);
499 EXPECT_EQ(flags & FD_CLOEXEC, 0);
501 EXPECT_EQ(close(fd1), 0);
502 EXPECT_EQ(close(fd2), 0);
503 EXPECT_EQ(close(fd3), 0);
508 EXPECT_EQ(waitpid(pid, &status, 0), pid);
509 EXPECT_EQ(true, WIFEXITED(status));
510 EXPECT_EQ(0, WEXITSTATUS(status));
514 * We created a private file descriptor table before along with
515 * requesting close-on-exec so the original fds must not be
518 flags = fcntl(fd1, F_GETFD);
519 EXPECT_GT(flags, -1);
520 EXPECT_EQ(flags & FD_CLOEXEC, 0);
522 flags = fcntl(fd2, F_GETFD);
523 EXPECT_GT(flags, -1);
524 EXPECT_EQ(flags & FD_CLOEXEC, 0);
529 flags = fcntl(fd3, F_GETFD);
530 EXPECT_GT(flags, -1);
531 EXPECT_EQ(flags & FD_CLOEXEC, 0);
533 EXPECT_EQ(close(fd1), 0);
534 EXPECT_EQ(close(fd2), 0);
535 EXPECT_EQ(close(fd3), 0);