12c5db60eSChristian Brauner // SPDX-License-Identifier: GPL-2.0
22c5db60eSChristian Brauner 
32c5db60eSChristian Brauner #define _GNU_SOURCE
42c5db60eSChristian Brauner #include <errno.h>
52c5db60eSChristian Brauner #include <fcntl.h>
62c5db60eSChristian Brauner #include <linux/kernel.h>
72c5db60eSChristian Brauner #include <limits.h>
82c5db60eSChristian Brauner #include <stdbool.h>
92c5db60eSChristian Brauner #include <stdio.h>
102c5db60eSChristian Brauner #include <stdlib.h>
112c5db60eSChristian Brauner #include <string.h>
122c5db60eSChristian Brauner #include <syscall.h>
132c5db60eSChristian Brauner #include <unistd.h>
1423afeaefSGiuseppe Scrivano #include <sys/resource.h>
1501c1484aSMuhammad Usama Anjum #include <linux/close_range.h>
162c5db60eSChristian Brauner 
172c5db60eSChristian Brauner #include "../kselftest_harness.h"
18a5161eeeSChristian Brauner #include "../clone3/clone3_selftests.h"
192c5db60eSChristian Brauner 
204810ce7cSChristian Brauner 
214810ce7cSChristian Brauner #ifndef F_LINUX_SPECIFIC_BASE
224810ce7cSChristian Brauner #define F_LINUX_SPECIFIC_BASE 1024
234810ce7cSChristian Brauner #endif
244810ce7cSChristian Brauner 
254810ce7cSChristian Brauner #ifndef F_DUPFD_QUERY
264810ce7cSChristian Brauner #define F_DUPFD_QUERY (F_LINUX_SPECIFIC_BASE + 3)
274810ce7cSChristian Brauner #endif
284810ce7cSChristian Brauner 
29*d0fe8920SChristian Brauner #ifndef F_CREATED_QUERY
30*d0fe8920SChristian Brauner #define F_CREATED_QUERY (F_LINUX_SPECIFIC_BASE + 4)
31*d0fe8920SChristian Brauner #endif
32*d0fe8920SChristian Brauner 
sys_close_range(unsigned int fd,unsigned int max_fd,unsigned int flags)332c5db60eSChristian Brauner static inline int sys_close_range(unsigned int fd, unsigned int max_fd,
342c5db60eSChristian Brauner 				  unsigned int flags)
352c5db60eSChristian Brauner {
362c5db60eSChristian Brauner 	return syscall(__NR_close_range, fd, max_fd, flags);
372c5db60eSChristian Brauner }
382c5db60eSChristian Brauner 
TEST(core_close_range)39f35dcaa0SShuah Khan TEST(core_close_range)
402c5db60eSChristian Brauner {
412c5db60eSChristian Brauner 	int i, ret;
422c5db60eSChristian Brauner 	int open_fds[101];
432c5db60eSChristian Brauner 
442c5db60eSChristian Brauner 	for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
452c5db60eSChristian Brauner 		int fd;
462c5db60eSChristian Brauner 
472c5db60eSChristian Brauner 		fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
482c5db60eSChristian Brauner 		ASSERT_GE(fd, 0) {
492c5db60eSChristian Brauner 			if (errno == ENOENT)
501d44d0ddSTommi Rantala 				SKIP(return, "Skipping test since /dev/null does not exist");
512c5db60eSChristian Brauner 		}
522c5db60eSChristian Brauner 
532c5db60eSChristian Brauner 		open_fds[i] = fd;
542c5db60eSChristian Brauner 	}
552c5db60eSChristian Brauner 
562c5db60eSChristian Brauner 	EXPECT_EQ(-1, sys_close_range(open_fds[0], open_fds[100], -1)) {
572c5db60eSChristian Brauner 		if (errno == ENOSYS)
581d44d0ddSTommi Rantala 			SKIP(return, "close_range() syscall not supported");
592c5db60eSChristian Brauner 	}
602c5db60eSChristian Brauner 
614810ce7cSChristian Brauner 	for (i = 0; i < 100; i++) {
624810ce7cSChristian Brauner 		ret = fcntl(open_fds[i], F_DUPFD_QUERY, open_fds[i + 1]);
634810ce7cSChristian Brauner 		if (ret < 0) {
644810ce7cSChristian Brauner 			EXPECT_EQ(errno, EINVAL);
654810ce7cSChristian Brauner 		} else {
664810ce7cSChristian Brauner 			EXPECT_EQ(ret, 0);
674810ce7cSChristian Brauner 		}
684810ce7cSChristian Brauner 	}
694810ce7cSChristian Brauner 
702c5db60eSChristian Brauner 	EXPECT_EQ(0, sys_close_range(open_fds[0], open_fds[50], 0));
712c5db60eSChristian Brauner 
722c5db60eSChristian Brauner 	for (i = 0; i <= 50; i++)
732c5db60eSChristian Brauner 		EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
742c5db60eSChristian Brauner 
752c5db60eSChristian Brauner 	for (i = 51; i <= 100; i++)
762c5db60eSChristian Brauner 		EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
772c5db60eSChristian Brauner 
782c5db60eSChristian Brauner 	/* create a couple of gaps */
792c5db60eSChristian Brauner 	close(57);
802c5db60eSChristian Brauner 	close(78);
812c5db60eSChristian Brauner 	close(81);
822c5db60eSChristian Brauner 	close(82);
832c5db60eSChristian Brauner 	close(84);
842c5db60eSChristian Brauner 	close(90);
852c5db60eSChristian Brauner 
862c5db60eSChristian Brauner 	EXPECT_EQ(0, sys_close_range(open_fds[51], open_fds[92], 0));
872c5db60eSChristian Brauner 
882c5db60eSChristian Brauner 	for (i = 51; i <= 92; i++)
892c5db60eSChristian Brauner 		EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
902c5db60eSChristian Brauner 
912c5db60eSChristian Brauner 	for (i = 93; i <= 100; i++)
922c5db60eSChristian Brauner 		EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
932c5db60eSChristian Brauner 
942c5db60eSChristian Brauner 	/* test that the kernel caps and still closes all fds */
952c5db60eSChristian Brauner 	EXPECT_EQ(0, sys_close_range(open_fds[93], open_fds[99], 0));
962c5db60eSChristian Brauner 
972c5db60eSChristian Brauner 	for (i = 93; i <= 99; i++)
982c5db60eSChristian Brauner 		EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
992c5db60eSChristian Brauner 
1002c5db60eSChristian Brauner 	EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
1012c5db60eSChristian Brauner 
1022c5db60eSChristian Brauner 	EXPECT_EQ(0, sys_close_range(open_fds[100], open_fds[100], 0));
1032c5db60eSChristian Brauner 
1042c5db60eSChristian Brauner 	EXPECT_EQ(-1, fcntl(open_fds[100], F_GETFL));
1052c5db60eSChristian Brauner }
1062c5db60eSChristian Brauner 
TEST(close_range_unshare)107a5161eeeSChristian Brauner TEST(close_range_unshare)
108a5161eeeSChristian Brauner {
109a5161eeeSChristian Brauner 	int i, ret, status;
110a5161eeeSChristian Brauner 	pid_t pid;
111a5161eeeSChristian Brauner 	int open_fds[101];
112ca202504STobias Klauser 	struct __clone_args args = {
113a5161eeeSChristian Brauner 		.flags = CLONE_FILES,
114a5161eeeSChristian Brauner 		.exit_signal = SIGCHLD,
115a5161eeeSChristian Brauner 	};
116a5161eeeSChristian Brauner 
117a5161eeeSChristian Brauner 	for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
118a5161eeeSChristian Brauner 		int fd;
119a5161eeeSChristian Brauner 
120a5161eeeSChristian Brauner 		fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
121a5161eeeSChristian Brauner 		ASSERT_GE(fd, 0) {
122a5161eeeSChristian Brauner 			if (errno == ENOENT)
1231d44d0ddSTommi Rantala 				SKIP(return, "Skipping test since /dev/null does not exist");
124a5161eeeSChristian Brauner 		}
125a5161eeeSChristian Brauner 
126a5161eeeSChristian Brauner 		open_fds[i] = fd;
127a5161eeeSChristian Brauner 	}
128a5161eeeSChristian Brauner 
129a5161eeeSChristian Brauner 	pid = sys_clone3(&args, sizeof(args));
130a5161eeeSChristian Brauner 	ASSERT_GE(pid, 0);
131a5161eeeSChristian Brauner 
132a5161eeeSChristian Brauner 	if (pid == 0) {
133a5161eeeSChristian Brauner 		ret = sys_close_range(open_fds[0], open_fds[50],
134a5161eeeSChristian Brauner 				      CLOSE_RANGE_UNSHARE);
135a5161eeeSChristian Brauner 		if (ret)
136a5161eeeSChristian Brauner 			exit(EXIT_FAILURE);
137a5161eeeSChristian Brauner 
138a5161eeeSChristian Brauner 		for (i = 0; i <= 50; i++)
139a5161eeeSChristian Brauner 			if (fcntl(open_fds[i], F_GETFL) != -1)
140a5161eeeSChristian Brauner 				exit(EXIT_FAILURE);
141a5161eeeSChristian Brauner 
142a5161eeeSChristian Brauner 		for (i = 51; i <= 100; i++)
143a5161eeeSChristian Brauner 			if (fcntl(open_fds[i], F_GETFL) == -1)
144a5161eeeSChristian Brauner 				exit(EXIT_FAILURE);
145a5161eeeSChristian Brauner 
146a5161eeeSChristian Brauner 		/* create a couple of gaps */
147a5161eeeSChristian Brauner 		close(57);
148a5161eeeSChristian Brauner 		close(78);
149a5161eeeSChristian Brauner 		close(81);
150a5161eeeSChristian Brauner 		close(82);
151a5161eeeSChristian Brauner 		close(84);
152a5161eeeSChristian Brauner 		close(90);
153a5161eeeSChristian Brauner 
154a5161eeeSChristian Brauner 		ret = sys_close_range(open_fds[51], open_fds[92],
155a5161eeeSChristian Brauner 				      CLOSE_RANGE_UNSHARE);
156a5161eeeSChristian Brauner 		if (ret)
157a5161eeeSChristian Brauner 			exit(EXIT_FAILURE);
158a5161eeeSChristian Brauner 
159a5161eeeSChristian Brauner 		for (i = 51; i <= 92; i++)
160a5161eeeSChristian Brauner 			if (fcntl(open_fds[i], F_GETFL) != -1)
161a5161eeeSChristian Brauner 				exit(EXIT_FAILURE);
162a5161eeeSChristian Brauner 
163a5161eeeSChristian Brauner 		for (i = 93; i <= 100; i++)
164a5161eeeSChristian Brauner 			if (fcntl(open_fds[i], F_GETFL) == -1)
165a5161eeeSChristian Brauner 				exit(EXIT_FAILURE);
166a5161eeeSChristian Brauner 
167a5161eeeSChristian Brauner 		/* test that the kernel caps and still closes all fds */
168a5161eeeSChristian Brauner 		ret = sys_close_range(open_fds[93], open_fds[99],
169a5161eeeSChristian Brauner 				      CLOSE_RANGE_UNSHARE);
170a5161eeeSChristian Brauner 		if (ret)
171a5161eeeSChristian Brauner 			exit(EXIT_FAILURE);
172a5161eeeSChristian Brauner 
173a5161eeeSChristian Brauner 		for (i = 93; i <= 99; i++)
174a5161eeeSChristian Brauner 			if (fcntl(open_fds[i], F_GETFL) != -1)
175a5161eeeSChristian Brauner 				exit(EXIT_FAILURE);
176a5161eeeSChristian Brauner 
177a5161eeeSChristian Brauner 		if (fcntl(open_fds[100], F_GETFL) == -1)
178a5161eeeSChristian Brauner 			exit(EXIT_FAILURE);
179a5161eeeSChristian Brauner 
180a5161eeeSChristian Brauner 		ret = sys_close_range(open_fds[100], open_fds[100],
181a5161eeeSChristian Brauner 				      CLOSE_RANGE_UNSHARE);
182a5161eeeSChristian Brauner 		if (ret)
183a5161eeeSChristian Brauner 			exit(EXIT_FAILURE);
184a5161eeeSChristian Brauner 
185a5161eeeSChristian Brauner 		if (fcntl(open_fds[100], F_GETFL) != -1)
186a5161eeeSChristian Brauner 			exit(EXIT_FAILURE);
187a5161eeeSChristian Brauner 
188a5161eeeSChristian Brauner 		exit(EXIT_SUCCESS);
189a5161eeeSChristian Brauner 	}
190a5161eeeSChristian Brauner 
191a5161eeeSChristian Brauner 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
192a5161eeeSChristian Brauner 	EXPECT_EQ(true, WIFEXITED(status));
193a5161eeeSChristian Brauner 	EXPECT_EQ(0, WEXITSTATUS(status));
194a5161eeeSChristian Brauner }
195a5161eeeSChristian Brauner 
TEST(close_range_unshare_capped)196a5161eeeSChristian Brauner TEST(close_range_unshare_capped)
197a5161eeeSChristian Brauner {
198a5161eeeSChristian Brauner 	int i, ret, status;
199a5161eeeSChristian Brauner 	pid_t pid;
200a5161eeeSChristian Brauner 	int open_fds[101];
201ca202504STobias Klauser 	struct __clone_args args = {
202a5161eeeSChristian Brauner 		.flags = CLONE_FILES,
203a5161eeeSChristian Brauner 		.exit_signal = SIGCHLD,
204a5161eeeSChristian Brauner 	};
205a5161eeeSChristian Brauner 
206a5161eeeSChristian Brauner 	for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
207a5161eeeSChristian Brauner 		int fd;
208a5161eeeSChristian Brauner 
209a5161eeeSChristian Brauner 		fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
210a5161eeeSChristian Brauner 		ASSERT_GE(fd, 0) {
211a5161eeeSChristian Brauner 			if (errno == ENOENT)
2121d44d0ddSTommi Rantala 				SKIP(return, "Skipping test since /dev/null does not exist");
213a5161eeeSChristian Brauner 		}
214a5161eeeSChristian Brauner 
215a5161eeeSChristian Brauner 		open_fds[i] = fd;
216a5161eeeSChristian Brauner 	}
217a5161eeeSChristian Brauner 
218a5161eeeSChristian Brauner 	pid = sys_clone3(&args, sizeof(args));
219a5161eeeSChristian Brauner 	ASSERT_GE(pid, 0);
220a5161eeeSChristian Brauner 
221a5161eeeSChristian Brauner 	if (pid == 0) {
222a5161eeeSChristian Brauner 		ret = sys_close_range(open_fds[0], UINT_MAX,
223a5161eeeSChristian Brauner 				      CLOSE_RANGE_UNSHARE);
224a5161eeeSChristian Brauner 		if (ret)
225a5161eeeSChristian Brauner 			exit(EXIT_FAILURE);
226a5161eeeSChristian Brauner 
227a5161eeeSChristian Brauner 		for (i = 0; i <= 100; i++)
228a5161eeeSChristian Brauner 			if (fcntl(open_fds[i], F_GETFL) != -1)
229a5161eeeSChristian Brauner 				exit(EXIT_FAILURE);
230a5161eeeSChristian Brauner 
231a5161eeeSChristian Brauner 		exit(EXIT_SUCCESS);
232a5161eeeSChristian Brauner 	}
233a5161eeeSChristian Brauner 
234a5161eeeSChristian Brauner 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
235a5161eeeSChristian Brauner 	EXPECT_EQ(true, WIFEXITED(status));
236a5161eeeSChristian Brauner 	EXPECT_EQ(0, WEXITSTATUS(status));
237a5161eeeSChristian Brauner }
238a5161eeeSChristian Brauner 
TEST(close_range_cloexec)23923afeaefSGiuseppe Scrivano TEST(close_range_cloexec)
24023afeaefSGiuseppe Scrivano {
24123afeaefSGiuseppe Scrivano 	int i, ret;
24223afeaefSGiuseppe Scrivano 	int open_fds[101];
24323afeaefSGiuseppe Scrivano 	struct rlimit rlimit;
24423afeaefSGiuseppe Scrivano 
24523afeaefSGiuseppe Scrivano 	for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
24623afeaefSGiuseppe Scrivano 		int fd;
24723afeaefSGiuseppe Scrivano 
24823afeaefSGiuseppe Scrivano 		fd = open("/dev/null", O_RDONLY);
24923afeaefSGiuseppe Scrivano 		ASSERT_GE(fd, 0) {
25023afeaefSGiuseppe Scrivano 			if (errno == ENOENT)
251ca202504STobias Klauser 				SKIP(return, "Skipping test since /dev/null does not exist");
25223afeaefSGiuseppe Scrivano 		}
25323afeaefSGiuseppe Scrivano 
25423afeaefSGiuseppe Scrivano 		open_fds[i] = fd;
25523afeaefSGiuseppe Scrivano 	}
25623afeaefSGiuseppe Scrivano 
25723afeaefSGiuseppe Scrivano 	ret = sys_close_range(1000, 1000, CLOSE_RANGE_CLOEXEC);
25823afeaefSGiuseppe Scrivano 	if (ret < 0) {
25923afeaefSGiuseppe Scrivano 		if (errno == ENOSYS)
260ca202504STobias Klauser 			SKIP(return, "close_range() syscall not supported");
26123afeaefSGiuseppe Scrivano 		if (errno == EINVAL)
262ca202504STobias Klauser 			SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC");
26323afeaefSGiuseppe Scrivano 	}
26423afeaefSGiuseppe Scrivano 
26523afeaefSGiuseppe Scrivano 	/* Ensure the FD_CLOEXEC bit is set also with a resource limit in place.  */
26623afeaefSGiuseppe Scrivano 	ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit));
26723afeaefSGiuseppe Scrivano 	rlimit.rlim_cur = 25;
26823afeaefSGiuseppe Scrivano 	ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlimit));
26923afeaefSGiuseppe Scrivano 
27023afeaefSGiuseppe Scrivano 	/* Set close-on-exec for two ranges: [0-50] and [75-100].  */
27123afeaefSGiuseppe Scrivano 	ret = sys_close_range(open_fds[0], open_fds[50], CLOSE_RANGE_CLOEXEC);
27223afeaefSGiuseppe Scrivano 	ASSERT_EQ(0, ret);
27323afeaefSGiuseppe Scrivano 	ret = sys_close_range(open_fds[75], open_fds[100], CLOSE_RANGE_CLOEXEC);
27423afeaefSGiuseppe Scrivano 	ASSERT_EQ(0, ret);
27523afeaefSGiuseppe Scrivano 
27623afeaefSGiuseppe Scrivano 	for (i = 0; i <= 50; i++) {
27723afeaefSGiuseppe Scrivano 		int flags = fcntl(open_fds[i], F_GETFD);
27823afeaefSGiuseppe Scrivano 
27923afeaefSGiuseppe Scrivano 		EXPECT_GT(flags, -1);
28023afeaefSGiuseppe Scrivano 		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
28123afeaefSGiuseppe Scrivano 	}
28223afeaefSGiuseppe Scrivano 
28323afeaefSGiuseppe Scrivano 	for (i = 51; i <= 74; i++) {
28423afeaefSGiuseppe Scrivano 		int flags = fcntl(open_fds[i], F_GETFD);
28523afeaefSGiuseppe Scrivano 
28623afeaefSGiuseppe Scrivano 		EXPECT_GT(flags, -1);
28723afeaefSGiuseppe Scrivano 		EXPECT_EQ(flags & FD_CLOEXEC, 0);
28823afeaefSGiuseppe Scrivano 	}
28923afeaefSGiuseppe Scrivano 
29023afeaefSGiuseppe Scrivano 	for (i = 75; i <= 100; i++) {
29123afeaefSGiuseppe Scrivano 		int flags = fcntl(open_fds[i], F_GETFD);
29223afeaefSGiuseppe Scrivano 
29323afeaefSGiuseppe Scrivano 		EXPECT_GT(flags, -1);
29423afeaefSGiuseppe Scrivano 		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
29523afeaefSGiuseppe Scrivano 	}
29623afeaefSGiuseppe Scrivano 
29723afeaefSGiuseppe Scrivano 	/* Test a common pattern.  */
29823afeaefSGiuseppe Scrivano 	ret = sys_close_range(3, UINT_MAX, CLOSE_RANGE_CLOEXEC);
29923afeaefSGiuseppe Scrivano 	for (i = 0; i <= 100; i++) {
30023afeaefSGiuseppe Scrivano 		int flags = fcntl(open_fds[i], F_GETFD);
30123afeaefSGiuseppe Scrivano 
30223afeaefSGiuseppe Scrivano 		EXPECT_GT(flags, -1);
30323afeaefSGiuseppe Scrivano 		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
30423afeaefSGiuseppe Scrivano 	}
30523afeaefSGiuseppe Scrivano }
30623afeaefSGiuseppe Scrivano 
TEST(close_range_cloexec_unshare)307fe325c3fSChristian Brauner TEST(close_range_cloexec_unshare)
308fe325c3fSChristian Brauner {
309fe325c3fSChristian Brauner 	int i, ret;
310fe325c3fSChristian Brauner 	int open_fds[101];
311fe325c3fSChristian Brauner 	struct rlimit rlimit;
312fe325c3fSChristian Brauner 
313fe325c3fSChristian Brauner 	for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
314fe325c3fSChristian Brauner 		int fd;
315fe325c3fSChristian Brauner 
316fe325c3fSChristian Brauner 		fd = open("/dev/null", O_RDONLY);
317fe325c3fSChristian Brauner 		ASSERT_GE(fd, 0) {
318fe325c3fSChristian Brauner 			if (errno == ENOENT)
319fe325c3fSChristian Brauner 				SKIP(return, "Skipping test since /dev/null does not exist");
320fe325c3fSChristian Brauner 		}
321fe325c3fSChristian Brauner 
322fe325c3fSChristian Brauner 		open_fds[i] = fd;
323fe325c3fSChristian Brauner 	}
324fe325c3fSChristian Brauner 
325fe325c3fSChristian Brauner 	ret = sys_close_range(1000, 1000, CLOSE_RANGE_CLOEXEC);
326fe325c3fSChristian Brauner 	if (ret < 0) {
327fe325c3fSChristian Brauner 		if (errno == ENOSYS)
328fe325c3fSChristian Brauner 			SKIP(return, "close_range() syscall not supported");
329fe325c3fSChristian Brauner 		if (errno == EINVAL)
330fe325c3fSChristian Brauner 			SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC");
331fe325c3fSChristian Brauner 	}
332fe325c3fSChristian Brauner 
333fe325c3fSChristian Brauner 	/* Ensure the FD_CLOEXEC bit is set also with a resource limit in place.  */
334fe325c3fSChristian Brauner 	ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit));
335fe325c3fSChristian Brauner 	rlimit.rlim_cur = 25;
336fe325c3fSChristian Brauner 	ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlimit));
337fe325c3fSChristian Brauner 
338fe325c3fSChristian Brauner 	/* Set close-on-exec for two ranges: [0-50] and [75-100].  */
339fe325c3fSChristian Brauner 	ret = sys_close_range(open_fds[0], open_fds[50],
340fe325c3fSChristian Brauner 			      CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
341fe325c3fSChristian Brauner 	ASSERT_EQ(0, ret);
342fe325c3fSChristian Brauner 	ret = sys_close_range(open_fds[75], open_fds[100],
343fe325c3fSChristian Brauner 			      CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
344fe325c3fSChristian Brauner 	ASSERT_EQ(0, ret);
345fe325c3fSChristian Brauner 
346fe325c3fSChristian Brauner 	for (i = 0; i <= 50; i++) {
347fe325c3fSChristian Brauner 		int flags = fcntl(open_fds[i], F_GETFD);
348fe325c3fSChristian Brauner 
349fe325c3fSChristian Brauner 		EXPECT_GT(flags, -1);
350fe325c3fSChristian Brauner 		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
351fe325c3fSChristian Brauner 	}
352fe325c3fSChristian Brauner 
353fe325c3fSChristian Brauner 	for (i = 51; i <= 74; i++) {
354fe325c3fSChristian Brauner 		int flags = fcntl(open_fds[i], F_GETFD);
355fe325c3fSChristian Brauner 
356fe325c3fSChristian Brauner 		EXPECT_GT(flags, -1);
357fe325c3fSChristian Brauner 		EXPECT_EQ(flags & FD_CLOEXEC, 0);
358fe325c3fSChristian Brauner 	}
359fe325c3fSChristian Brauner 
360fe325c3fSChristian Brauner 	for (i = 75; i <= 100; i++) {
361fe325c3fSChristian Brauner 		int flags = fcntl(open_fds[i], F_GETFD);
362fe325c3fSChristian Brauner 
363fe325c3fSChristian Brauner 		EXPECT_GT(flags, -1);
364fe325c3fSChristian Brauner 		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
365fe325c3fSChristian Brauner 	}
366fe325c3fSChristian Brauner 
367fe325c3fSChristian Brauner 	/* Test a common pattern.  */
368fe325c3fSChristian Brauner 	ret = sys_close_range(3, UINT_MAX,
369fe325c3fSChristian Brauner 			      CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
370fe325c3fSChristian Brauner 	for (i = 0; i <= 100; i++) {
371fe325c3fSChristian Brauner 		int flags = fcntl(open_fds[i], F_GETFD);
372fe325c3fSChristian Brauner 
373fe325c3fSChristian Brauner 		EXPECT_GT(flags, -1);
374fe325c3fSChristian Brauner 		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
375fe325c3fSChristian Brauner 	}
376fe325c3fSChristian Brauner }
37723afeaefSGiuseppe Scrivano 
3786abc20f8SChristian Brauner /*
3796abc20f8SChristian Brauner  * Regression test for [email protected]
3806abc20f8SChristian Brauner  */
TEST(close_range_cloexec_syzbot)3816abc20f8SChristian Brauner TEST(close_range_cloexec_syzbot)
3826abc20f8SChristian Brauner {
3834810ce7cSChristian Brauner 	int fd1, fd2, fd3, fd4, flags, ret, status;
3846abc20f8SChristian Brauner 	pid_t pid;
3856abc20f8SChristian Brauner 	struct __clone_args args = {
3866abc20f8SChristian Brauner 		.flags = CLONE_FILES,
3876abc20f8SChristian Brauner 		.exit_signal = SIGCHLD,
3886abc20f8SChristian Brauner 	};
3896abc20f8SChristian Brauner 
3906abc20f8SChristian Brauner 	/* Create a huge gap in the fd table. */
3916abc20f8SChristian Brauner 	fd1 = open("/dev/null", O_RDWR);
3926abc20f8SChristian Brauner 	EXPECT_GT(fd1, 0);
3936abc20f8SChristian Brauner 
3946abc20f8SChristian Brauner 	fd2 = dup2(fd1, 1000);
3956abc20f8SChristian Brauner 	EXPECT_GT(fd2, 0);
3966abc20f8SChristian Brauner 
3974810ce7cSChristian Brauner 	flags = fcntl(fd1, F_DUPFD_QUERY, fd2);
3984810ce7cSChristian Brauner 	if (flags < 0) {
3994810ce7cSChristian Brauner 		EXPECT_EQ(errno, EINVAL);
4004810ce7cSChristian Brauner 	} else {
4014810ce7cSChristian Brauner 		EXPECT_EQ(flags, 1);
4024810ce7cSChristian Brauner 	}
4034810ce7cSChristian Brauner 
4046abc20f8SChristian Brauner 	pid = sys_clone3(&args, sizeof(args));
4056abc20f8SChristian Brauner 	ASSERT_GE(pid, 0);
4066abc20f8SChristian Brauner 
4076abc20f8SChristian Brauner 	if (pid == 0) {
4086abc20f8SChristian Brauner 		ret = sys_close_range(3, ~0U, CLOSE_RANGE_CLOEXEC);
4096abc20f8SChristian Brauner 		if (ret)
4106abc20f8SChristian Brauner 			exit(EXIT_FAILURE);
4116abc20f8SChristian Brauner 
4126abc20f8SChristian Brauner 		/*
4136abc20f8SChristian Brauner 			 * We now have a private file descriptor table and all
4146abc20f8SChristian Brauner 			 * our open fds should still be open but made
4156abc20f8SChristian Brauner 			 * close-on-exec.
4166abc20f8SChristian Brauner 			 */
4176abc20f8SChristian Brauner 		flags = fcntl(fd1, F_GETFD);
4186abc20f8SChristian Brauner 		EXPECT_GT(flags, -1);
4196abc20f8SChristian Brauner 		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
4206abc20f8SChristian Brauner 
4216abc20f8SChristian Brauner 		flags = fcntl(fd2, F_GETFD);
4226abc20f8SChristian Brauner 		EXPECT_GT(flags, -1);
4236abc20f8SChristian Brauner 		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
4246abc20f8SChristian Brauner 
4256abc20f8SChristian Brauner 		fd3 = dup2(fd1, 42);
4266abc20f8SChristian Brauner 		EXPECT_GT(fd3, 0);
4276abc20f8SChristian Brauner 
4284810ce7cSChristian Brauner 		flags = fcntl(fd1, F_DUPFD_QUERY, fd3);
4294810ce7cSChristian Brauner 		if (flags < 0) {
4304810ce7cSChristian Brauner 			EXPECT_EQ(errno, EINVAL);
4314810ce7cSChristian Brauner 		} else {
4324810ce7cSChristian Brauner 			EXPECT_EQ(flags, 1);
4334810ce7cSChristian Brauner 		}
4344810ce7cSChristian Brauner 
4354810ce7cSChristian Brauner 
4364810ce7cSChristian Brauner 
4376abc20f8SChristian Brauner 		/*
4386abc20f8SChristian Brauner 			 * Duplicating the file descriptor must remove the
4396abc20f8SChristian Brauner 			 * FD_CLOEXEC flag.
4406abc20f8SChristian Brauner 			 */
4416abc20f8SChristian Brauner 		flags = fcntl(fd3, F_GETFD);
4426abc20f8SChristian Brauner 		EXPECT_GT(flags, -1);
4436abc20f8SChristian Brauner 		EXPECT_EQ(flags & FD_CLOEXEC, 0);
4446abc20f8SChristian Brauner 
4456abc20f8SChristian Brauner 		exit(EXIT_SUCCESS);
4466abc20f8SChristian Brauner 	}
4476abc20f8SChristian Brauner 
4486abc20f8SChristian Brauner 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
4496abc20f8SChristian Brauner 	EXPECT_EQ(true, WIFEXITED(status));
4506abc20f8SChristian Brauner 	EXPECT_EQ(0, WEXITSTATUS(status));
4516abc20f8SChristian Brauner 
4526abc20f8SChristian Brauner 	/*
4536abc20f8SChristian Brauner 	 * We had a shared file descriptor table before along with requesting
4546abc20f8SChristian Brauner 	 * close-on-exec so the original fds must not be close-on-exec.
4556abc20f8SChristian Brauner 	 */
4566abc20f8SChristian Brauner 	flags = fcntl(fd1, F_GETFD);
4576abc20f8SChristian Brauner 	EXPECT_GT(flags, -1);
4586abc20f8SChristian Brauner 	EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
4596abc20f8SChristian Brauner 
4606abc20f8SChristian Brauner 	flags = fcntl(fd2, F_GETFD);
4616abc20f8SChristian Brauner 	EXPECT_GT(flags, -1);
4626abc20f8SChristian Brauner 	EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
4636abc20f8SChristian Brauner 
4646abc20f8SChristian Brauner 	fd3 = dup2(fd1, 42);
4656abc20f8SChristian Brauner 	EXPECT_GT(fd3, 0);
4666abc20f8SChristian Brauner 
4674810ce7cSChristian Brauner 	flags = fcntl(fd1, F_DUPFD_QUERY, fd3);
4684810ce7cSChristian Brauner 	if (flags < 0) {
4694810ce7cSChristian Brauner 		EXPECT_EQ(errno, EINVAL);
4704810ce7cSChristian Brauner 	} else {
4714810ce7cSChristian Brauner 		EXPECT_EQ(flags, 1);
4724810ce7cSChristian Brauner 	}
4734810ce7cSChristian Brauner 
4744810ce7cSChristian Brauner 	fd4 = open("/dev/null", O_RDWR);
4754810ce7cSChristian Brauner 	EXPECT_GT(fd4, 0);
4764810ce7cSChristian Brauner 
4774810ce7cSChristian Brauner 	/* Same inode, different file pointers. */
4784810ce7cSChristian Brauner 	flags = fcntl(fd1, F_DUPFD_QUERY, fd4);
4794810ce7cSChristian Brauner 	if (flags < 0) {
4804810ce7cSChristian Brauner 		EXPECT_EQ(errno, EINVAL);
4814810ce7cSChristian Brauner 	} else {
4824810ce7cSChristian Brauner 		EXPECT_EQ(flags, 0);
4834810ce7cSChristian Brauner 	}
4844810ce7cSChristian Brauner 
4856abc20f8SChristian Brauner 	flags = fcntl(fd3, F_GETFD);
4866abc20f8SChristian Brauner 	EXPECT_GT(flags, -1);
4876abc20f8SChristian Brauner 	EXPECT_EQ(flags & FD_CLOEXEC, 0);
4886abc20f8SChristian Brauner 
4896abc20f8SChristian Brauner 	EXPECT_EQ(close(fd1), 0);
4906abc20f8SChristian Brauner 	EXPECT_EQ(close(fd2), 0);
4916abc20f8SChristian Brauner 	EXPECT_EQ(close(fd3), 0);
4924810ce7cSChristian Brauner 	EXPECT_EQ(close(fd4), 0);
4936abc20f8SChristian Brauner }
4946abc20f8SChristian Brauner 
4956abc20f8SChristian Brauner /*
4966abc20f8SChristian Brauner  * Regression test for [email protected]
4976abc20f8SChristian Brauner  */
TEST(close_range_cloexec_unshare_syzbot)4986abc20f8SChristian Brauner TEST(close_range_cloexec_unshare_syzbot)
4996abc20f8SChristian Brauner {
5006abc20f8SChristian Brauner 	int i, fd1, fd2, fd3, flags, ret, status;
5016abc20f8SChristian Brauner 	pid_t pid;
5026abc20f8SChristian Brauner 	struct __clone_args args = {
5036abc20f8SChristian Brauner 		.flags = CLONE_FILES,
5046abc20f8SChristian Brauner 		.exit_signal = SIGCHLD,
5056abc20f8SChristian Brauner 	};
5066abc20f8SChristian Brauner 
5076abc20f8SChristian Brauner 	/*
5086abc20f8SChristian Brauner 	 * Create a huge gap in the fd table. When we now call
5096abc20f8SChristian Brauner 	 * CLOSE_RANGE_UNSHARE with a shared fd table and and with ~0U as upper
5106abc20f8SChristian Brauner 	 * bound the kernel will only copy up to fd1 file descriptors into the
5116abc20f8SChristian Brauner 	 * new fd table. If the kernel is buggy and doesn't handle
5126abc20f8SChristian Brauner 	 * CLOSE_RANGE_CLOEXEC correctly it will not have copied all file
5136abc20f8SChristian Brauner 	 * descriptors and we will oops!
5146abc20f8SChristian Brauner 	 *
5156abc20f8SChristian Brauner 	 * On a buggy kernel this should immediately oops. But let's loop just
5166abc20f8SChristian Brauner 	 * to be sure.
5176abc20f8SChristian Brauner 	 */
5186abc20f8SChristian Brauner 	fd1 = open("/dev/null", O_RDWR);
5196abc20f8SChristian Brauner 	EXPECT_GT(fd1, 0);
5206abc20f8SChristian Brauner 
5216abc20f8SChristian Brauner 	fd2 = dup2(fd1, 1000);
5226abc20f8SChristian Brauner 	EXPECT_GT(fd2, 0);
5236abc20f8SChristian Brauner 
5246abc20f8SChristian Brauner 	for (i = 0; i < 100; i++) {
5256abc20f8SChristian Brauner 
5266abc20f8SChristian Brauner 		pid = sys_clone3(&args, sizeof(args));
5276abc20f8SChristian Brauner 		ASSERT_GE(pid, 0);
5286abc20f8SChristian Brauner 
5296abc20f8SChristian Brauner 		if (pid == 0) {
5306abc20f8SChristian Brauner 			ret = sys_close_range(3, ~0U, CLOSE_RANGE_UNSHARE |
5316abc20f8SChristian Brauner 						      CLOSE_RANGE_CLOEXEC);
5326abc20f8SChristian Brauner 			if (ret)
5336abc20f8SChristian Brauner 				exit(EXIT_FAILURE);
5346abc20f8SChristian Brauner 
5356abc20f8SChristian Brauner 			/*
5366abc20f8SChristian Brauner 			 * We now have a private file descriptor table and all
5376abc20f8SChristian Brauner 			 * our open fds should still be open but made
5386abc20f8SChristian Brauner 			 * close-on-exec.
5396abc20f8SChristian Brauner 			 */
5406abc20f8SChristian Brauner 			flags = fcntl(fd1, F_GETFD);
5416abc20f8SChristian Brauner 			EXPECT_GT(flags, -1);
5426abc20f8SChristian Brauner 			EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
5436abc20f8SChristian Brauner 
5446abc20f8SChristian Brauner 			flags = fcntl(fd2, F_GETFD);
5456abc20f8SChristian Brauner 			EXPECT_GT(flags, -1);
5466abc20f8SChristian Brauner 			EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
5476abc20f8SChristian Brauner 
5486abc20f8SChristian Brauner 			fd3 = dup2(fd1, 42);
5496abc20f8SChristian Brauner 			EXPECT_GT(fd3, 0);
5506abc20f8SChristian Brauner 
5516abc20f8SChristian Brauner 			/*
5526abc20f8SChristian Brauner 			 * Duplicating the file descriptor must remove the
5536abc20f8SChristian Brauner 			 * FD_CLOEXEC flag.
5546abc20f8SChristian Brauner 			 */
5556abc20f8SChristian Brauner 			flags = fcntl(fd3, F_GETFD);
5566abc20f8SChristian Brauner 			EXPECT_GT(flags, -1);
5576abc20f8SChristian Brauner 			EXPECT_EQ(flags & FD_CLOEXEC, 0);
5586abc20f8SChristian Brauner 
5596abc20f8SChristian Brauner 			EXPECT_EQ(close(fd1), 0);
5606abc20f8SChristian Brauner 			EXPECT_EQ(close(fd2), 0);
5616abc20f8SChristian Brauner 			EXPECT_EQ(close(fd3), 0);
5626abc20f8SChristian Brauner 
5636abc20f8SChristian Brauner 			exit(EXIT_SUCCESS);
5646abc20f8SChristian Brauner 		}
5656abc20f8SChristian Brauner 
5666abc20f8SChristian Brauner 		EXPECT_EQ(waitpid(pid, &status, 0), pid);
5676abc20f8SChristian Brauner 		EXPECT_EQ(true, WIFEXITED(status));
5686abc20f8SChristian Brauner 		EXPECT_EQ(0, WEXITSTATUS(status));
5696abc20f8SChristian Brauner 	}
5706abc20f8SChristian Brauner 
5716abc20f8SChristian Brauner 	/*
5726abc20f8SChristian Brauner 	 * We created a private file descriptor table before along with
5736abc20f8SChristian Brauner 	 * requesting close-on-exec so the original fds must not be
5746abc20f8SChristian Brauner 	 * close-on-exec.
5756abc20f8SChristian Brauner 	 */
5766abc20f8SChristian Brauner 	flags = fcntl(fd1, F_GETFD);
5776abc20f8SChristian Brauner 	EXPECT_GT(flags, -1);
5786abc20f8SChristian Brauner 	EXPECT_EQ(flags & FD_CLOEXEC, 0);
5796abc20f8SChristian Brauner 
5806abc20f8SChristian Brauner 	flags = fcntl(fd2, F_GETFD);
5816abc20f8SChristian Brauner 	EXPECT_GT(flags, -1);
5826abc20f8SChristian Brauner 	EXPECT_EQ(flags & FD_CLOEXEC, 0);
5836abc20f8SChristian Brauner 
5846abc20f8SChristian Brauner 	fd3 = dup2(fd1, 42);
5856abc20f8SChristian Brauner 	EXPECT_GT(fd3, 0);
5866abc20f8SChristian Brauner 
5876abc20f8SChristian Brauner 	flags = fcntl(fd3, F_GETFD);
5886abc20f8SChristian Brauner 	EXPECT_GT(flags, -1);
5896abc20f8SChristian Brauner 	EXPECT_EQ(flags & FD_CLOEXEC, 0);
5906abc20f8SChristian Brauner 
5916abc20f8SChristian Brauner 	EXPECT_EQ(close(fd1), 0);
5926abc20f8SChristian Brauner 	EXPECT_EQ(close(fd2), 0);
5936abc20f8SChristian Brauner 	EXPECT_EQ(close(fd3), 0);
5946abc20f8SChristian Brauner }
5956abc20f8SChristian Brauner 
TEST(close_range_bitmap_corruption)5969a2fa147SAl Viro TEST(close_range_bitmap_corruption)
5979a2fa147SAl Viro {
5989a2fa147SAl Viro 	pid_t pid;
5999a2fa147SAl Viro 	int status;
6009a2fa147SAl Viro 	struct __clone_args args = {
6019a2fa147SAl Viro 		.flags = CLONE_FILES,
6029a2fa147SAl Viro 		.exit_signal = SIGCHLD,
6039a2fa147SAl Viro 	};
6049a2fa147SAl Viro 
6059a2fa147SAl Viro 	/* get the first 128 descriptors open */
6069a2fa147SAl Viro 	for (int i = 2; i < 128; i++)
6079a2fa147SAl Viro 		EXPECT_GE(dup2(0, i), 0);
6089a2fa147SAl Viro 
6099a2fa147SAl Viro 	/* get descriptor table shared */
6109a2fa147SAl Viro 	pid = sys_clone3(&args, sizeof(args));
6119a2fa147SAl Viro 	ASSERT_GE(pid, 0);
6129a2fa147SAl Viro 
6139a2fa147SAl Viro 	if (pid == 0) {
6149a2fa147SAl Viro 		/* unshare and truncate descriptor table down to 64 */
6159a2fa147SAl Viro 		if (sys_close_range(64, ~0U, CLOSE_RANGE_UNSHARE))
6169a2fa147SAl Viro 			exit(EXIT_FAILURE);
6179a2fa147SAl Viro 
6189a2fa147SAl Viro 		ASSERT_EQ(fcntl(64, F_GETFD), -1);
6199a2fa147SAl Viro 		/* ... and verify that the range 64..127 is not
6209a2fa147SAl Viro 		   stuck "fully used" according to secondary bitmap */
6219a2fa147SAl Viro 		EXPECT_EQ(dup(0), 64)
6229a2fa147SAl Viro 			exit(EXIT_FAILURE);
6239a2fa147SAl Viro 		exit(EXIT_SUCCESS);
6249a2fa147SAl Viro 	}
6259a2fa147SAl Viro 
6269a2fa147SAl Viro 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
6279a2fa147SAl Viro 	EXPECT_EQ(true, WIFEXITED(status));
6289a2fa147SAl Viro 	EXPECT_EQ(0, WEXITSTATUS(status));
6299a2fa147SAl Viro }
6309a2fa147SAl Viro 
TEST(fcntl_created)631*d0fe8920SChristian Brauner TEST(fcntl_created)
632*d0fe8920SChristian Brauner {
633*d0fe8920SChristian Brauner 	for (int i = 0; i < 101; i++) {
634*d0fe8920SChristian Brauner 		int fd;
635*d0fe8920SChristian Brauner 		char path[PATH_MAX];
636*d0fe8920SChristian Brauner 
637*d0fe8920SChristian Brauner 		fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
638*d0fe8920SChristian Brauner 		ASSERT_GE(fd, 0) {
639*d0fe8920SChristian Brauner 			if (errno == ENOENT)
640*d0fe8920SChristian Brauner 				SKIP(return,
641*d0fe8920SChristian Brauner 					   "Skipping test since /dev/null does not exist");
642*d0fe8920SChristian Brauner 		}
643*d0fe8920SChristian Brauner 
644*d0fe8920SChristian Brauner 		/* We didn't create "/dev/null". */
645*d0fe8920SChristian Brauner 		EXPECT_EQ(fcntl(fd, F_CREATED_QUERY, 0), 0);
646*d0fe8920SChristian Brauner 		close(fd);
647*d0fe8920SChristian Brauner 
648*d0fe8920SChristian Brauner 		sprintf(path, "aaaa_%d", i);
649*d0fe8920SChristian Brauner 		fd = open(path, O_CREAT | O_RDONLY | O_CLOEXEC, 0600);
650*d0fe8920SChristian Brauner 		ASSERT_GE(fd, 0);
651*d0fe8920SChristian Brauner 
652*d0fe8920SChristian Brauner 		/* We created "aaaa_%d". */
653*d0fe8920SChristian Brauner 		EXPECT_EQ(fcntl(fd, F_CREATED_QUERY, 0), 1);
654*d0fe8920SChristian Brauner 		close(fd);
655*d0fe8920SChristian Brauner 
656*d0fe8920SChristian Brauner 		fd = open(path, O_RDONLY | O_CLOEXEC);
657*d0fe8920SChristian Brauner 		ASSERT_GE(fd, 0);
658*d0fe8920SChristian Brauner 
659*d0fe8920SChristian Brauner 		/* We're opening it again, so no positive creation check. */
660*d0fe8920SChristian Brauner 		EXPECT_EQ(fcntl(fd, F_CREATED_QUERY, 0), 0);
661*d0fe8920SChristian Brauner 		close(fd);
662*d0fe8920SChristian Brauner 		unlink(path);
663*d0fe8920SChristian Brauner 	}
664*d0fe8920SChristian Brauner }
665*d0fe8920SChristian Brauner 
6662c5db60eSChristian Brauner TEST_HARNESS_MAIN
667