Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
16#include "../kselftest_harness.h"
17#include "../clone3/clone3_selftests.h"
18
19static inline int sys_close_range(unsigned int fd, unsigned int max_fd,
20 unsigned int flags)
21{
22 return syscall(__NR_close_range, fd, max_fd, flags);
23}
24
25TEST(core_close_range)
26{
27 int i, ret;
28 int open_fds[101];
29
30 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
31 int fd;
32
33 fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
34 ASSERT_GE(fd, 0) {
35 if (errno == ENOENT)
36 SKIP(return, "Skipping test since /dev/null does not exist");
37 }
38
39 open_fds[i] = fd;
40 }
41
42 EXPECT_EQ(-1, sys_close_range(open_fds[0], open_fds[100], -1)) {
43 if (errno == ENOSYS)
44 SKIP(return, "close_range() syscall not supported");
45 }
46
47 EXPECT_EQ(0, sys_close_range(open_fds[0], open_fds[50], 0));
48
49 for (i = 0; i <= 50; i++)
50 EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
51
52 for (i = 51; i <= 100; i++)
53 EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
54
55 /* create a couple of gaps */
56 close(57);
57 close(78);
58 close(81);
59 close(82);
60 close(84);
61 close(90);
62
63 EXPECT_EQ(0, sys_close_range(open_fds[51], open_fds[92], 0));
64
65 for (i = 51; i <= 92; i++)
66 EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
67
68 for (i = 93; i <= 100; i++)
69 EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
70
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));
73
74 for (i = 93; i <= 99; i++)
75 EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
76
77 EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
78
79 EXPECT_EQ(0, sys_close_range(open_fds[100], open_fds[100], 0));
80
81 EXPECT_EQ(-1, fcntl(open_fds[100], F_GETFL));
82}
83
84TEST(close_range_unshare)
85{
86 int i, ret, status;
87 pid_t pid;
88 int open_fds[101];
89 struct __clone_args args = {
90 .flags = CLONE_FILES,
91 .exit_signal = SIGCHLD,
92 };
93
94 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
95 int fd;
96
97 fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
98 ASSERT_GE(fd, 0) {
99 if (errno == ENOENT)
100 SKIP(return, "Skipping test since /dev/null does not exist");
101 }
102
103 open_fds[i] = fd;
104 }
105
106 pid = sys_clone3(&args, sizeof(args));
107 ASSERT_GE(pid, 0);
108
109 if (pid == 0) {
110 ret = sys_close_range(open_fds[0], open_fds[50],
111 CLOSE_RANGE_UNSHARE);
112 if (ret)
113 exit(EXIT_FAILURE);
114
115 for (i = 0; i <= 50; i++)
116 if (fcntl(open_fds[i], F_GETFL) != -1)
117 exit(EXIT_FAILURE);
118
119 for (i = 51; i <= 100; i++)
120 if (fcntl(open_fds[i], F_GETFL) == -1)
121 exit(EXIT_FAILURE);
122
123 /* create a couple of gaps */
124 close(57);
125 close(78);
126 close(81);
127 close(82);
128 close(84);
129 close(90);
130
131 ret = sys_close_range(open_fds[51], open_fds[92],
132 CLOSE_RANGE_UNSHARE);
133 if (ret)
134 exit(EXIT_FAILURE);
135
136 for (i = 51; i <= 92; i++)
137 if (fcntl(open_fds[i], F_GETFL) != -1)
138 exit(EXIT_FAILURE);
139
140 for (i = 93; i <= 100; i++)
141 if (fcntl(open_fds[i], F_GETFL) == -1)
142 exit(EXIT_FAILURE);
143
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);
147 if (ret)
148 exit(EXIT_FAILURE);
149
150 for (i = 93; i <= 99; i++)
151 if (fcntl(open_fds[i], F_GETFL) != -1)
152 exit(EXIT_FAILURE);
153
154 if (fcntl(open_fds[100], F_GETFL) == -1)
155 exit(EXIT_FAILURE);
156
157 ret = sys_close_range(open_fds[100], open_fds[100],
158 CLOSE_RANGE_UNSHARE);
159 if (ret)
160 exit(EXIT_FAILURE);
161
162 if (fcntl(open_fds[100], F_GETFL) != -1)
163 exit(EXIT_FAILURE);
164
165 exit(EXIT_SUCCESS);
166 }
167
168 EXPECT_EQ(waitpid(pid, &status, 0), pid);
169 EXPECT_EQ(true, WIFEXITED(status));
170 EXPECT_EQ(0, WEXITSTATUS(status));
171}
172
173TEST(close_range_unshare_capped)
174{
175 int i, ret, status;
176 pid_t pid;
177 int open_fds[101];
178 struct __clone_args args = {
179 .flags = CLONE_FILES,
180 .exit_signal = SIGCHLD,
181 };
182
183 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
184 int fd;
185
186 fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
187 ASSERT_GE(fd, 0) {
188 if (errno == ENOENT)
189 SKIP(return, "Skipping test since /dev/null does not exist");
190 }
191
192 open_fds[i] = fd;
193 }
194
195 pid = sys_clone3(&args, sizeof(args));
196 ASSERT_GE(pid, 0);
197
198 if (pid == 0) {
199 ret = sys_close_range(open_fds[0], UINT_MAX,
200 CLOSE_RANGE_UNSHARE);
201 if (ret)
202 exit(EXIT_FAILURE);
203
204 for (i = 0; i <= 100; i++)
205 if (fcntl(open_fds[i], F_GETFL) != -1)
206 exit(EXIT_FAILURE);
207
208 exit(EXIT_SUCCESS);
209 }
210
211 EXPECT_EQ(waitpid(pid, &status, 0), pid);
212 EXPECT_EQ(true, WIFEXITED(status));
213 EXPECT_EQ(0, WEXITSTATUS(status));
214}
215
216TEST(close_range_cloexec)
217{
218 int i, ret;
219 int open_fds[101];
220 struct rlimit rlimit;
221
222 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
223 int fd;
224
225 fd = open("/dev/null", O_RDONLY);
226 ASSERT_GE(fd, 0) {
227 if (errno == ENOENT)
228 SKIP(return, "Skipping test since /dev/null does not exist");
229 }
230
231 open_fds[i] = fd;
232 }
233
234 ret = sys_close_range(1000, 1000, CLOSE_RANGE_CLOEXEC);
235 if (ret < 0) {
236 if (errno == ENOSYS)
237 SKIP(return, "close_range() syscall not supported");
238 if (errno == EINVAL)
239 SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC");
240 }
241
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));
246
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);
249 ASSERT_EQ(0, ret);
250 ret = sys_close_range(open_fds[75], open_fds[100], CLOSE_RANGE_CLOEXEC);
251 ASSERT_EQ(0, ret);
252
253 for (i = 0; i <= 50; i++) {
254 int flags = fcntl(open_fds[i], F_GETFD);
255
256 EXPECT_GT(flags, -1);
257 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
258 }
259
260 for (i = 51; i <= 74; i++) {
261 int flags = fcntl(open_fds[i], F_GETFD);
262
263 EXPECT_GT(flags, -1);
264 EXPECT_EQ(flags & FD_CLOEXEC, 0);
265 }
266
267 for (i = 75; i <= 100; i++) {
268 int flags = fcntl(open_fds[i], F_GETFD);
269
270 EXPECT_GT(flags, -1);
271 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
272 }
273
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);
278
279 EXPECT_GT(flags, -1);
280 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
281 }
282}
283
284TEST(close_range_cloexec_unshare)
285{
286 int i, ret;
287 int open_fds[101];
288 struct rlimit rlimit;
289
290 for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
291 int fd;
292
293 fd = open("/dev/null", O_RDONLY);
294 ASSERT_GE(fd, 0) {
295 if (errno == ENOENT)
296 SKIP(return, "Skipping test since /dev/null does not exist");
297 }
298
299 open_fds[i] = fd;
300 }
301
302 ret = sys_close_range(1000, 1000, CLOSE_RANGE_CLOEXEC);
303 if (ret < 0) {
304 if (errno == ENOSYS)
305 SKIP(return, "close_range() syscall not supported");
306 if (errno == EINVAL)
307 SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC");
308 }
309
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));
314
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);
318 ASSERT_EQ(0, ret);
319 ret = sys_close_range(open_fds[75], open_fds[100],
320 CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
321 ASSERT_EQ(0, ret);
322
323 for (i = 0; i <= 50; i++) {
324 int flags = fcntl(open_fds[i], F_GETFD);
325
326 EXPECT_GT(flags, -1);
327 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
328 }
329
330 for (i = 51; i <= 74; i++) {
331 int flags = fcntl(open_fds[i], F_GETFD);
332
333 EXPECT_GT(flags, -1);
334 EXPECT_EQ(flags & FD_CLOEXEC, 0);
335 }
336
337 for (i = 75; i <= 100; i++) {
338 int flags = fcntl(open_fds[i], F_GETFD);
339
340 EXPECT_GT(flags, -1);
341 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
342 }
343
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);
349
350 EXPECT_GT(flags, -1);
351 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
352 }
353}
354
355/*
356 * Regression test for syzbot+96cfd2b22b3213646a93@syzkaller.appspotmail.com
357 */
358TEST(close_range_cloexec_syzbot)
359{
360 int fd1, fd2, fd3, flags, ret, status;
361 pid_t pid;
362 struct __clone_args args = {
363 .flags = CLONE_FILES,
364 .exit_signal = SIGCHLD,
365 };
366
367 /* Create a huge gap in the fd table. */
368 fd1 = open("/dev/null", O_RDWR);
369 EXPECT_GT(fd1, 0);
370
371 fd2 = dup2(fd1, 1000);
372 EXPECT_GT(fd2, 0);
373
374 pid = sys_clone3(&args, sizeof(args));
375 ASSERT_GE(pid, 0);
376
377 if (pid == 0) {
378 ret = sys_close_range(3, ~0U, CLOSE_RANGE_CLOEXEC);
379 if (ret)
380 exit(EXIT_FAILURE);
381
382 /*
383 * We now have a private file descriptor table and all
384 * our open fds should still be open but made
385 * close-on-exec.
386 */
387 flags = fcntl(fd1, F_GETFD);
388 EXPECT_GT(flags, -1);
389 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
390
391 flags = fcntl(fd2, F_GETFD);
392 EXPECT_GT(flags, -1);
393 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
394
395 fd3 = dup2(fd1, 42);
396 EXPECT_GT(fd3, 0);
397
398 /*
399 * Duplicating the file descriptor must remove the
400 * FD_CLOEXEC flag.
401 */
402 flags = fcntl(fd3, F_GETFD);
403 EXPECT_GT(flags, -1);
404 EXPECT_EQ(flags & FD_CLOEXEC, 0);
405
406 exit(EXIT_SUCCESS);
407 }
408
409 EXPECT_EQ(waitpid(pid, &status, 0), pid);
410 EXPECT_EQ(true, WIFEXITED(status));
411 EXPECT_EQ(0, WEXITSTATUS(status));
412
413 /*
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.
416 */
417 flags = fcntl(fd1, F_GETFD);
418 EXPECT_GT(flags, -1);
419 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
420
421 flags = fcntl(fd2, F_GETFD);
422 EXPECT_GT(flags, -1);
423 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
424
425 fd3 = dup2(fd1, 42);
426 EXPECT_GT(fd3, 0);
427
428 flags = fcntl(fd3, F_GETFD);
429 EXPECT_GT(flags, -1);
430 EXPECT_EQ(flags & FD_CLOEXEC, 0);
431
432 EXPECT_EQ(close(fd1), 0);
433 EXPECT_EQ(close(fd2), 0);
434 EXPECT_EQ(close(fd3), 0);
435}
436
437/*
438 * Regression test for syzbot+96cfd2b22b3213646a93@syzkaller.appspotmail.com
439 */
440TEST(close_range_cloexec_unshare_syzbot)
441{
442 int i, fd1, fd2, fd3, flags, ret, status;
443 pid_t pid;
444 struct __clone_args args = {
445 .flags = CLONE_FILES,
446 .exit_signal = SIGCHLD,
447 };
448
449 /*
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!
456 *
457 * On a buggy kernel this should immediately oops. But let's loop just
458 * to be sure.
459 */
460 fd1 = open("/dev/null", O_RDWR);
461 EXPECT_GT(fd1, 0);
462
463 fd2 = dup2(fd1, 1000);
464 EXPECT_GT(fd2, 0);
465
466 for (i = 0; i < 100; i++) {
467
468 pid = sys_clone3(&args, sizeof(args));
469 ASSERT_GE(pid, 0);
470
471 if (pid == 0) {
472 ret = sys_close_range(3, ~0U, CLOSE_RANGE_UNSHARE |
473 CLOSE_RANGE_CLOEXEC);
474 if (ret)
475 exit(EXIT_FAILURE);
476
477 /*
478 * We now have a private file descriptor table and all
479 * our open fds should still be open but made
480 * close-on-exec.
481 */
482 flags = fcntl(fd1, F_GETFD);
483 EXPECT_GT(flags, -1);
484 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
485
486 flags = fcntl(fd2, F_GETFD);
487 EXPECT_GT(flags, -1);
488 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
489
490 fd3 = dup2(fd1, 42);
491 EXPECT_GT(fd3, 0);
492
493 /*
494 * Duplicating the file descriptor must remove the
495 * FD_CLOEXEC flag.
496 */
497 flags = fcntl(fd3, F_GETFD);
498 EXPECT_GT(flags, -1);
499 EXPECT_EQ(flags & FD_CLOEXEC, 0);
500
501 EXPECT_EQ(close(fd1), 0);
502 EXPECT_EQ(close(fd2), 0);
503 EXPECT_EQ(close(fd3), 0);
504
505 exit(EXIT_SUCCESS);
506 }
507
508 EXPECT_EQ(waitpid(pid, &status, 0), pid);
509 EXPECT_EQ(true, WIFEXITED(status));
510 EXPECT_EQ(0, WEXITSTATUS(status));
511 }
512
513 /*
514 * We created a private file descriptor table before along with
515 * requesting close-on-exec so the original fds must not be
516 * close-on-exec.
517 */
518 flags = fcntl(fd1, F_GETFD);
519 EXPECT_GT(flags, -1);
520 EXPECT_EQ(flags & FD_CLOEXEC, 0);
521
522 flags = fcntl(fd2, F_GETFD);
523 EXPECT_GT(flags, -1);
524 EXPECT_EQ(flags & FD_CLOEXEC, 0);
525
526 fd3 = dup2(fd1, 42);
527 EXPECT_GT(fd3, 0);
528
529 flags = fcntl(fd3, F_GETFD);
530 EXPECT_GT(flags, -1);
531 EXPECT_EQ(flags & FD_CLOEXEC, 0);
532
533 EXPECT_EQ(close(fd1), 0);
534 EXPECT_EQ(close(fd2), 0);
535 EXPECT_EQ(close(fd3), 0);
536}
537
538TEST_HARNESS_MAIN