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