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>
152c5db60eSChristian Brauner 
162c5db60eSChristian Brauner #include "../kselftest_harness.h"
17a5161eeeSChristian Brauner #include "../clone3/clone3_selftests.h"
182c5db60eSChristian Brauner 
192c5db60eSChristian Brauner #ifndef __NR_close_range
20ae78ba8dSChristian Brauner 	#if defined __alpha__
21ae78ba8dSChristian Brauner 		#define __NR_close_range 546
22ae78ba8dSChristian Brauner 	#elif defined _MIPS_SIM
23ae78ba8dSChristian Brauner 		#if _MIPS_SIM == _MIPS_SIM_ABI32	/* o32 */
24ae78ba8dSChristian Brauner 			#define __NR_close_range (436 + 4000)
25ae78ba8dSChristian Brauner 		#endif
26ae78ba8dSChristian Brauner 		#if _MIPS_SIM == _MIPS_SIM_NABI32	/* n32 */
27ae78ba8dSChristian Brauner 			#define __NR_close_range (436 + 6000)
28ae78ba8dSChristian Brauner 		#endif
29ae78ba8dSChristian Brauner 		#if _MIPS_SIM == _MIPS_SIM_ABI64	/* n64 */
30ae78ba8dSChristian Brauner 			#define __NR_close_range (436 + 5000)
31ae78ba8dSChristian Brauner 		#endif
32ae78ba8dSChristian Brauner 	#elif defined __ia64__
33ae78ba8dSChristian Brauner 		#define __NR_close_range (436 + 1024)
34ae78ba8dSChristian Brauner 	#else
35ae78ba8dSChristian Brauner 		#define __NR_close_range 436
36ae78ba8dSChristian Brauner 	#endif
372c5db60eSChristian Brauner #endif
382c5db60eSChristian Brauner 
39a5161eeeSChristian Brauner #ifndef CLOSE_RANGE_UNSHARE
40a5161eeeSChristian Brauner #define CLOSE_RANGE_UNSHARE	(1U << 1)
41a5161eeeSChristian Brauner #endif
42a5161eeeSChristian Brauner 
4323afeaefSGiuseppe Scrivano #ifndef CLOSE_RANGE_CLOEXEC
4423afeaefSGiuseppe Scrivano #define CLOSE_RANGE_CLOEXEC	(1U << 2)
4523afeaefSGiuseppe Scrivano #endif
4623afeaefSGiuseppe Scrivano 
sys_close_range(unsigned int fd,unsigned int max_fd,unsigned int flags)472c5db60eSChristian Brauner static inline int sys_close_range(unsigned int fd, unsigned int max_fd,
482c5db60eSChristian Brauner 				  unsigned int flags)
492c5db60eSChristian Brauner {
502c5db60eSChristian Brauner 	return syscall(__NR_close_range, fd, max_fd, flags);
512c5db60eSChristian Brauner }
522c5db60eSChristian Brauner 
TEST(core_close_range)53*f35dcaa0SShuah Khan TEST(core_close_range)
542c5db60eSChristian Brauner {
552c5db60eSChristian Brauner 	int i, ret;
562c5db60eSChristian Brauner 	int open_fds[101];
572c5db60eSChristian Brauner 
582c5db60eSChristian Brauner 	for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
592c5db60eSChristian Brauner 		int fd;
602c5db60eSChristian Brauner 
612c5db60eSChristian Brauner 		fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
622c5db60eSChristian Brauner 		ASSERT_GE(fd, 0) {
632c5db60eSChristian Brauner 			if (errno == ENOENT)
641d44d0ddSTommi Rantala 				SKIP(return, "Skipping test since /dev/null does not exist");
652c5db60eSChristian Brauner 		}
662c5db60eSChristian Brauner 
672c5db60eSChristian Brauner 		open_fds[i] = fd;
682c5db60eSChristian Brauner 	}
692c5db60eSChristian Brauner 
702c5db60eSChristian Brauner 	EXPECT_EQ(-1, sys_close_range(open_fds[0], open_fds[100], -1)) {
712c5db60eSChristian Brauner 		if (errno == ENOSYS)
721d44d0ddSTommi Rantala 			SKIP(return, "close_range() syscall not supported");
732c5db60eSChristian Brauner 	}
742c5db60eSChristian Brauner 
752c5db60eSChristian Brauner 	EXPECT_EQ(0, sys_close_range(open_fds[0], open_fds[50], 0));
762c5db60eSChristian Brauner 
772c5db60eSChristian Brauner 	for (i = 0; i <= 50; i++)
782c5db60eSChristian Brauner 		EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
792c5db60eSChristian Brauner 
802c5db60eSChristian Brauner 	for (i = 51; i <= 100; i++)
812c5db60eSChristian Brauner 		EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
822c5db60eSChristian Brauner 
832c5db60eSChristian Brauner 	/* create a couple of gaps */
842c5db60eSChristian Brauner 	close(57);
852c5db60eSChristian Brauner 	close(78);
862c5db60eSChristian Brauner 	close(81);
872c5db60eSChristian Brauner 	close(82);
882c5db60eSChristian Brauner 	close(84);
892c5db60eSChristian Brauner 	close(90);
902c5db60eSChristian Brauner 
912c5db60eSChristian Brauner 	EXPECT_EQ(0, sys_close_range(open_fds[51], open_fds[92], 0));
922c5db60eSChristian Brauner 
932c5db60eSChristian Brauner 	for (i = 51; i <= 92; i++)
942c5db60eSChristian Brauner 		EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
952c5db60eSChristian Brauner 
962c5db60eSChristian Brauner 	for (i = 93; i <= 100; i++)
972c5db60eSChristian Brauner 		EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
982c5db60eSChristian Brauner 
992c5db60eSChristian Brauner 	/* test that the kernel caps and still closes all fds */
1002c5db60eSChristian Brauner 	EXPECT_EQ(0, sys_close_range(open_fds[93], open_fds[99], 0));
1012c5db60eSChristian Brauner 
1022c5db60eSChristian Brauner 	for (i = 93; i <= 99; i++)
1032c5db60eSChristian Brauner 		EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
1042c5db60eSChristian Brauner 
1052c5db60eSChristian Brauner 	EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
1062c5db60eSChristian Brauner 
1072c5db60eSChristian Brauner 	EXPECT_EQ(0, sys_close_range(open_fds[100], open_fds[100], 0));
1082c5db60eSChristian Brauner 
1092c5db60eSChristian Brauner 	EXPECT_EQ(-1, fcntl(open_fds[100], F_GETFL));
1102c5db60eSChristian Brauner }
1112c5db60eSChristian Brauner 
TEST(close_range_unshare)112a5161eeeSChristian Brauner TEST(close_range_unshare)
113a5161eeeSChristian Brauner {
114a5161eeeSChristian Brauner 	int i, ret, status;
115a5161eeeSChristian Brauner 	pid_t pid;
116a5161eeeSChristian Brauner 	int open_fds[101];
117ca202504STobias Klauser 	struct __clone_args args = {
118a5161eeeSChristian Brauner 		.flags = CLONE_FILES,
119a5161eeeSChristian Brauner 		.exit_signal = SIGCHLD,
120a5161eeeSChristian Brauner 	};
121a5161eeeSChristian Brauner 
122a5161eeeSChristian Brauner 	for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
123a5161eeeSChristian Brauner 		int fd;
124a5161eeeSChristian Brauner 
125a5161eeeSChristian Brauner 		fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
126a5161eeeSChristian Brauner 		ASSERT_GE(fd, 0) {
127a5161eeeSChristian Brauner 			if (errno == ENOENT)
1281d44d0ddSTommi Rantala 				SKIP(return, "Skipping test since /dev/null does not exist");
129a5161eeeSChristian Brauner 		}
130a5161eeeSChristian Brauner 
131a5161eeeSChristian Brauner 		open_fds[i] = fd;
132a5161eeeSChristian Brauner 	}
133a5161eeeSChristian Brauner 
134a5161eeeSChristian Brauner 	pid = sys_clone3(&args, sizeof(args));
135a5161eeeSChristian Brauner 	ASSERT_GE(pid, 0);
136a5161eeeSChristian Brauner 
137a5161eeeSChristian Brauner 	if (pid == 0) {
138a5161eeeSChristian Brauner 		ret = sys_close_range(open_fds[0], open_fds[50],
139a5161eeeSChristian Brauner 				      CLOSE_RANGE_UNSHARE);
140a5161eeeSChristian Brauner 		if (ret)
141a5161eeeSChristian Brauner 			exit(EXIT_FAILURE);
142a5161eeeSChristian Brauner 
143a5161eeeSChristian Brauner 		for (i = 0; i <= 50; i++)
144a5161eeeSChristian Brauner 			if (fcntl(open_fds[i], F_GETFL) != -1)
145a5161eeeSChristian Brauner 				exit(EXIT_FAILURE);
146a5161eeeSChristian Brauner 
147a5161eeeSChristian Brauner 		for (i = 51; i <= 100; i++)
148a5161eeeSChristian Brauner 			if (fcntl(open_fds[i], F_GETFL) == -1)
149a5161eeeSChristian Brauner 				exit(EXIT_FAILURE);
150a5161eeeSChristian Brauner 
151a5161eeeSChristian Brauner 		/* create a couple of gaps */
152a5161eeeSChristian Brauner 		close(57);
153a5161eeeSChristian Brauner 		close(78);
154a5161eeeSChristian Brauner 		close(81);
155a5161eeeSChristian Brauner 		close(82);
156a5161eeeSChristian Brauner 		close(84);
157a5161eeeSChristian Brauner 		close(90);
158a5161eeeSChristian Brauner 
159a5161eeeSChristian Brauner 		ret = sys_close_range(open_fds[51], open_fds[92],
160a5161eeeSChristian Brauner 				      CLOSE_RANGE_UNSHARE);
161a5161eeeSChristian Brauner 		if (ret)
162a5161eeeSChristian Brauner 			exit(EXIT_FAILURE);
163a5161eeeSChristian Brauner 
164a5161eeeSChristian Brauner 		for (i = 51; i <= 92; i++)
165a5161eeeSChristian Brauner 			if (fcntl(open_fds[i], F_GETFL) != -1)
166a5161eeeSChristian Brauner 				exit(EXIT_FAILURE);
167a5161eeeSChristian Brauner 
168a5161eeeSChristian Brauner 		for (i = 93; i <= 100; i++)
169a5161eeeSChristian Brauner 			if (fcntl(open_fds[i], F_GETFL) == -1)
170a5161eeeSChristian Brauner 				exit(EXIT_FAILURE);
171a5161eeeSChristian Brauner 
172a5161eeeSChristian Brauner 		/* test that the kernel caps and still closes all fds */
173a5161eeeSChristian Brauner 		ret = sys_close_range(open_fds[93], open_fds[99],
174a5161eeeSChristian Brauner 				      CLOSE_RANGE_UNSHARE);
175a5161eeeSChristian Brauner 		if (ret)
176a5161eeeSChristian Brauner 			exit(EXIT_FAILURE);
177a5161eeeSChristian Brauner 
178a5161eeeSChristian Brauner 		for (i = 93; i <= 99; i++)
179a5161eeeSChristian Brauner 			if (fcntl(open_fds[i], F_GETFL) != -1)
180a5161eeeSChristian Brauner 				exit(EXIT_FAILURE);
181a5161eeeSChristian Brauner 
182a5161eeeSChristian Brauner 		if (fcntl(open_fds[100], F_GETFL) == -1)
183a5161eeeSChristian Brauner 			exit(EXIT_FAILURE);
184a5161eeeSChristian Brauner 
185a5161eeeSChristian Brauner 		ret = sys_close_range(open_fds[100], open_fds[100],
186a5161eeeSChristian Brauner 				      CLOSE_RANGE_UNSHARE);
187a5161eeeSChristian Brauner 		if (ret)
188a5161eeeSChristian Brauner 			exit(EXIT_FAILURE);
189a5161eeeSChristian Brauner 
190a5161eeeSChristian Brauner 		if (fcntl(open_fds[100], F_GETFL) != -1)
191a5161eeeSChristian Brauner 			exit(EXIT_FAILURE);
192a5161eeeSChristian Brauner 
193a5161eeeSChristian Brauner 		exit(EXIT_SUCCESS);
194a5161eeeSChristian Brauner 	}
195a5161eeeSChristian Brauner 
196a5161eeeSChristian Brauner 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
197a5161eeeSChristian Brauner 	EXPECT_EQ(true, WIFEXITED(status));
198a5161eeeSChristian Brauner 	EXPECT_EQ(0, WEXITSTATUS(status));
199a5161eeeSChristian Brauner }
200a5161eeeSChristian Brauner 
TEST(close_range_unshare_capped)201a5161eeeSChristian Brauner TEST(close_range_unshare_capped)
202a5161eeeSChristian Brauner {
203a5161eeeSChristian Brauner 	int i, ret, status;
204a5161eeeSChristian Brauner 	pid_t pid;
205a5161eeeSChristian Brauner 	int open_fds[101];
206ca202504STobias Klauser 	struct __clone_args args = {
207a5161eeeSChristian Brauner 		.flags = CLONE_FILES,
208a5161eeeSChristian Brauner 		.exit_signal = SIGCHLD,
209a5161eeeSChristian Brauner 	};
210a5161eeeSChristian Brauner 
211a5161eeeSChristian Brauner 	for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
212a5161eeeSChristian Brauner 		int fd;
213a5161eeeSChristian Brauner 
214a5161eeeSChristian Brauner 		fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
215a5161eeeSChristian Brauner 		ASSERT_GE(fd, 0) {
216a5161eeeSChristian Brauner 			if (errno == ENOENT)
2171d44d0ddSTommi Rantala 				SKIP(return, "Skipping test since /dev/null does not exist");
218a5161eeeSChristian Brauner 		}
219a5161eeeSChristian Brauner 
220a5161eeeSChristian Brauner 		open_fds[i] = fd;
221a5161eeeSChristian Brauner 	}
222a5161eeeSChristian Brauner 
223a5161eeeSChristian Brauner 	pid = sys_clone3(&args, sizeof(args));
224a5161eeeSChristian Brauner 	ASSERT_GE(pid, 0);
225a5161eeeSChristian Brauner 
226a5161eeeSChristian Brauner 	if (pid == 0) {
227a5161eeeSChristian Brauner 		ret = sys_close_range(open_fds[0], UINT_MAX,
228a5161eeeSChristian Brauner 				      CLOSE_RANGE_UNSHARE);
229a5161eeeSChristian Brauner 		if (ret)
230a5161eeeSChristian Brauner 			exit(EXIT_FAILURE);
231a5161eeeSChristian Brauner 
232a5161eeeSChristian Brauner 		for (i = 0; i <= 100; i++)
233a5161eeeSChristian Brauner 			if (fcntl(open_fds[i], F_GETFL) != -1)
234a5161eeeSChristian Brauner 				exit(EXIT_FAILURE);
235a5161eeeSChristian Brauner 
236a5161eeeSChristian Brauner 		exit(EXIT_SUCCESS);
237a5161eeeSChristian Brauner 	}
238a5161eeeSChristian Brauner 
239a5161eeeSChristian Brauner 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
240a5161eeeSChristian Brauner 	EXPECT_EQ(true, WIFEXITED(status));
241a5161eeeSChristian Brauner 	EXPECT_EQ(0, WEXITSTATUS(status));
242a5161eeeSChristian Brauner }
243a5161eeeSChristian Brauner 
TEST(close_range_cloexec)24423afeaefSGiuseppe Scrivano TEST(close_range_cloexec)
24523afeaefSGiuseppe Scrivano {
24623afeaefSGiuseppe Scrivano 	int i, ret;
24723afeaefSGiuseppe Scrivano 	int open_fds[101];
24823afeaefSGiuseppe Scrivano 	struct rlimit rlimit;
24923afeaefSGiuseppe Scrivano 
25023afeaefSGiuseppe Scrivano 	for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
25123afeaefSGiuseppe Scrivano 		int fd;
25223afeaefSGiuseppe Scrivano 
25323afeaefSGiuseppe Scrivano 		fd = open("/dev/null", O_RDONLY);
25423afeaefSGiuseppe Scrivano 		ASSERT_GE(fd, 0) {
25523afeaefSGiuseppe Scrivano 			if (errno == ENOENT)
256ca202504STobias Klauser 				SKIP(return, "Skipping test since /dev/null does not exist");
25723afeaefSGiuseppe Scrivano 		}
25823afeaefSGiuseppe Scrivano 
25923afeaefSGiuseppe Scrivano 		open_fds[i] = fd;
26023afeaefSGiuseppe Scrivano 	}
26123afeaefSGiuseppe Scrivano 
26223afeaefSGiuseppe Scrivano 	ret = sys_close_range(1000, 1000, CLOSE_RANGE_CLOEXEC);
26323afeaefSGiuseppe Scrivano 	if (ret < 0) {
26423afeaefSGiuseppe Scrivano 		if (errno == ENOSYS)
265ca202504STobias Klauser 			SKIP(return, "close_range() syscall not supported");
26623afeaefSGiuseppe Scrivano 		if (errno == EINVAL)
267ca202504STobias Klauser 			SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC");
26823afeaefSGiuseppe Scrivano 	}
26923afeaefSGiuseppe Scrivano 
27023afeaefSGiuseppe Scrivano 	/* Ensure the FD_CLOEXEC bit is set also with a resource limit in place.  */
27123afeaefSGiuseppe Scrivano 	ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit));
27223afeaefSGiuseppe Scrivano 	rlimit.rlim_cur = 25;
27323afeaefSGiuseppe Scrivano 	ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlimit));
27423afeaefSGiuseppe Scrivano 
27523afeaefSGiuseppe Scrivano 	/* Set close-on-exec for two ranges: [0-50] and [75-100].  */
27623afeaefSGiuseppe Scrivano 	ret = sys_close_range(open_fds[0], open_fds[50], CLOSE_RANGE_CLOEXEC);
27723afeaefSGiuseppe Scrivano 	ASSERT_EQ(0, ret);
27823afeaefSGiuseppe Scrivano 	ret = sys_close_range(open_fds[75], open_fds[100], CLOSE_RANGE_CLOEXEC);
27923afeaefSGiuseppe Scrivano 	ASSERT_EQ(0, ret);
28023afeaefSGiuseppe Scrivano 
28123afeaefSGiuseppe Scrivano 	for (i = 0; i <= 50; i++) {
28223afeaefSGiuseppe Scrivano 		int flags = fcntl(open_fds[i], F_GETFD);
28323afeaefSGiuseppe Scrivano 
28423afeaefSGiuseppe Scrivano 		EXPECT_GT(flags, -1);
28523afeaefSGiuseppe Scrivano 		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
28623afeaefSGiuseppe Scrivano 	}
28723afeaefSGiuseppe Scrivano 
28823afeaefSGiuseppe Scrivano 	for (i = 51; i <= 74; i++) {
28923afeaefSGiuseppe Scrivano 		int flags = fcntl(open_fds[i], F_GETFD);
29023afeaefSGiuseppe Scrivano 
29123afeaefSGiuseppe Scrivano 		EXPECT_GT(flags, -1);
29223afeaefSGiuseppe Scrivano 		EXPECT_EQ(flags & FD_CLOEXEC, 0);
29323afeaefSGiuseppe Scrivano 	}
29423afeaefSGiuseppe Scrivano 
29523afeaefSGiuseppe Scrivano 	for (i = 75; i <= 100; i++) {
29623afeaefSGiuseppe Scrivano 		int flags = fcntl(open_fds[i], F_GETFD);
29723afeaefSGiuseppe Scrivano 
29823afeaefSGiuseppe Scrivano 		EXPECT_GT(flags, -1);
29923afeaefSGiuseppe Scrivano 		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
30023afeaefSGiuseppe Scrivano 	}
30123afeaefSGiuseppe Scrivano 
30223afeaefSGiuseppe Scrivano 	/* Test a common pattern.  */
30323afeaefSGiuseppe Scrivano 	ret = sys_close_range(3, UINT_MAX, CLOSE_RANGE_CLOEXEC);
30423afeaefSGiuseppe Scrivano 	for (i = 0; i <= 100; i++) {
30523afeaefSGiuseppe Scrivano 		int flags = fcntl(open_fds[i], F_GETFD);
30623afeaefSGiuseppe Scrivano 
30723afeaefSGiuseppe Scrivano 		EXPECT_GT(flags, -1);
30823afeaefSGiuseppe Scrivano 		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
30923afeaefSGiuseppe Scrivano 	}
31023afeaefSGiuseppe Scrivano }
31123afeaefSGiuseppe Scrivano 
TEST(close_range_cloexec_unshare)312fe325c3fSChristian Brauner TEST(close_range_cloexec_unshare)
313fe325c3fSChristian Brauner {
314fe325c3fSChristian Brauner 	int i, ret;
315fe325c3fSChristian Brauner 	int open_fds[101];
316fe325c3fSChristian Brauner 	struct rlimit rlimit;
317fe325c3fSChristian Brauner 
318fe325c3fSChristian Brauner 	for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
319fe325c3fSChristian Brauner 		int fd;
320fe325c3fSChristian Brauner 
321fe325c3fSChristian Brauner 		fd = open("/dev/null", O_RDONLY);
322fe325c3fSChristian Brauner 		ASSERT_GE(fd, 0) {
323fe325c3fSChristian Brauner 			if (errno == ENOENT)
324fe325c3fSChristian Brauner 				SKIP(return, "Skipping test since /dev/null does not exist");
325fe325c3fSChristian Brauner 		}
326fe325c3fSChristian Brauner 
327fe325c3fSChristian Brauner 		open_fds[i] = fd;
328fe325c3fSChristian Brauner 	}
329fe325c3fSChristian Brauner 
330fe325c3fSChristian Brauner 	ret = sys_close_range(1000, 1000, CLOSE_RANGE_CLOEXEC);
331fe325c3fSChristian Brauner 	if (ret < 0) {
332fe325c3fSChristian Brauner 		if (errno == ENOSYS)
333fe325c3fSChristian Brauner 			SKIP(return, "close_range() syscall not supported");
334fe325c3fSChristian Brauner 		if (errno == EINVAL)
335fe325c3fSChristian Brauner 			SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC");
336fe325c3fSChristian Brauner 	}
337fe325c3fSChristian Brauner 
338fe325c3fSChristian Brauner 	/* Ensure the FD_CLOEXEC bit is set also with a resource limit in place.  */
339fe325c3fSChristian Brauner 	ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit));
340fe325c3fSChristian Brauner 	rlimit.rlim_cur = 25;
341fe325c3fSChristian Brauner 	ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlimit));
342fe325c3fSChristian Brauner 
343fe325c3fSChristian Brauner 	/* Set close-on-exec for two ranges: [0-50] and [75-100].  */
344fe325c3fSChristian Brauner 	ret = sys_close_range(open_fds[0], open_fds[50],
345fe325c3fSChristian Brauner 			      CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
346fe325c3fSChristian Brauner 	ASSERT_EQ(0, ret);
347fe325c3fSChristian Brauner 	ret = sys_close_range(open_fds[75], open_fds[100],
348fe325c3fSChristian Brauner 			      CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
349fe325c3fSChristian Brauner 	ASSERT_EQ(0, ret);
350fe325c3fSChristian Brauner 
351fe325c3fSChristian Brauner 	for (i = 0; i <= 50; i++) {
352fe325c3fSChristian Brauner 		int flags = fcntl(open_fds[i], F_GETFD);
353fe325c3fSChristian Brauner 
354fe325c3fSChristian Brauner 		EXPECT_GT(flags, -1);
355fe325c3fSChristian Brauner 		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
356fe325c3fSChristian Brauner 	}
357fe325c3fSChristian Brauner 
358fe325c3fSChristian Brauner 	for (i = 51; i <= 74; i++) {
359fe325c3fSChristian Brauner 		int flags = fcntl(open_fds[i], F_GETFD);
360fe325c3fSChristian Brauner 
361fe325c3fSChristian Brauner 		EXPECT_GT(flags, -1);
362fe325c3fSChristian Brauner 		EXPECT_EQ(flags & FD_CLOEXEC, 0);
363fe325c3fSChristian Brauner 	}
364fe325c3fSChristian Brauner 
365fe325c3fSChristian Brauner 	for (i = 75; i <= 100; i++) {
366fe325c3fSChristian Brauner 		int flags = fcntl(open_fds[i], F_GETFD);
367fe325c3fSChristian Brauner 
368fe325c3fSChristian Brauner 		EXPECT_GT(flags, -1);
369fe325c3fSChristian Brauner 		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
370fe325c3fSChristian Brauner 	}
371fe325c3fSChristian Brauner 
372fe325c3fSChristian Brauner 	/* Test a common pattern.  */
373fe325c3fSChristian Brauner 	ret = sys_close_range(3, UINT_MAX,
374fe325c3fSChristian Brauner 			      CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
375fe325c3fSChristian Brauner 	for (i = 0; i <= 100; i++) {
376fe325c3fSChristian Brauner 		int flags = fcntl(open_fds[i], F_GETFD);
377fe325c3fSChristian Brauner 
378fe325c3fSChristian Brauner 		EXPECT_GT(flags, -1);
379fe325c3fSChristian Brauner 		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
380fe325c3fSChristian Brauner 	}
381fe325c3fSChristian Brauner }
38223afeaefSGiuseppe Scrivano 
3836abc20f8SChristian Brauner /*
3846abc20f8SChristian Brauner  * Regression test for syzbot+96cfd2b22b3213646a93@syzkaller.appspotmail.com
3856abc20f8SChristian Brauner  */
TEST(close_range_cloexec_syzbot)3866abc20f8SChristian Brauner TEST(close_range_cloexec_syzbot)
3876abc20f8SChristian Brauner {
3886abc20f8SChristian Brauner 	int fd1, fd2, fd3, flags, ret, status;
3896abc20f8SChristian Brauner 	pid_t pid;
3906abc20f8SChristian Brauner 	struct __clone_args args = {
3916abc20f8SChristian Brauner 		.flags = CLONE_FILES,
3926abc20f8SChristian Brauner 		.exit_signal = SIGCHLD,
3936abc20f8SChristian Brauner 	};
3946abc20f8SChristian Brauner 
3956abc20f8SChristian Brauner 	/* Create a huge gap in the fd table. */
3966abc20f8SChristian Brauner 	fd1 = open("/dev/null", O_RDWR);
3976abc20f8SChristian Brauner 	EXPECT_GT(fd1, 0);
3986abc20f8SChristian Brauner 
3996abc20f8SChristian Brauner 	fd2 = dup2(fd1, 1000);
4006abc20f8SChristian Brauner 	EXPECT_GT(fd2, 0);
4016abc20f8SChristian Brauner 
4026abc20f8SChristian Brauner 	pid = sys_clone3(&args, sizeof(args));
4036abc20f8SChristian Brauner 	ASSERT_GE(pid, 0);
4046abc20f8SChristian Brauner 
4056abc20f8SChristian Brauner 	if (pid == 0) {
4066abc20f8SChristian Brauner 		ret = sys_close_range(3, ~0U, CLOSE_RANGE_CLOEXEC);
4076abc20f8SChristian Brauner 		if (ret)
4086abc20f8SChristian Brauner 			exit(EXIT_FAILURE);
4096abc20f8SChristian Brauner 
4106abc20f8SChristian Brauner 		/*
4116abc20f8SChristian Brauner 			 * We now have a private file descriptor table and all
4126abc20f8SChristian Brauner 			 * our open fds should still be open but made
4136abc20f8SChristian Brauner 			 * close-on-exec.
4146abc20f8SChristian Brauner 			 */
4156abc20f8SChristian Brauner 		flags = fcntl(fd1, F_GETFD);
4166abc20f8SChristian Brauner 		EXPECT_GT(flags, -1);
4176abc20f8SChristian Brauner 		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
4186abc20f8SChristian Brauner 
4196abc20f8SChristian Brauner 		flags = fcntl(fd2, F_GETFD);
4206abc20f8SChristian Brauner 		EXPECT_GT(flags, -1);
4216abc20f8SChristian Brauner 		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
4226abc20f8SChristian Brauner 
4236abc20f8SChristian Brauner 		fd3 = dup2(fd1, 42);
4246abc20f8SChristian Brauner 		EXPECT_GT(fd3, 0);
4256abc20f8SChristian Brauner 
4266abc20f8SChristian Brauner 		/*
4276abc20f8SChristian Brauner 			 * Duplicating the file descriptor must remove the
4286abc20f8SChristian Brauner 			 * FD_CLOEXEC flag.
4296abc20f8SChristian Brauner 			 */
4306abc20f8SChristian Brauner 		flags = fcntl(fd3, F_GETFD);
4316abc20f8SChristian Brauner 		EXPECT_GT(flags, -1);
4326abc20f8SChristian Brauner 		EXPECT_EQ(flags & FD_CLOEXEC, 0);
4336abc20f8SChristian Brauner 
4346abc20f8SChristian Brauner 		exit(EXIT_SUCCESS);
4356abc20f8SChristian Brauner 	}
4366abc20f8SChristian Brauner 
4376abc20f8SChristian Brauner 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
4386abc20f8SChristian Brauner 	EXPECT_EQ(true, WIFEXITED(status));
4396abc20f8SChristian Brauner 	EXPECT_EQ(0, WEXITSTATUS(status));
4406abc20f8SChristian Brauner 
4416abc20f8SChristian Brauner 	/*
4426abc20f8SChristian Brauner 	 * We had a shared file descriptor table before along with requesting
4436abc20f8SChristian Brauner 	 * close-on-exec so the original fds must not be close-on-exec.
4446abc20f8SChristian Brauner 	 */
4456abc20f8SChristian Brauner 	flags = fcntl(fd1, F_GETFD);
4466abc20f8SChristian Brauner 	EXPECT_GT(flags, -1);
4476abc20f8SChristian Brauner 	EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
4486abc20f8SChristian Brauner 
4496abc20f8SChristian Brauner 	flags = fcntl(fd2, F_GETFD);
4506abc20f8SChristian Brauner 	EXPECT_GT(flags, -1);
4516abc20f8SChristian Brauner 	EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
4526abc20f8SChristian Brauner 
4536abc20f8SChristian Brauner 	fd3 = dup2(fd1, 42);
4546abc20f8SChristian Brauner 	EXPECT_GT(fd3, 0);
4556abc20f8SChristian Brauner 
4566abc20f8SChristian Brauner 	flags = fcntl(fd3, F_GETFD);
4576abc20f8SChristian Brauner 	EXPECT_GT(flags, -1);
4586abc20f8SChristian Brauner 	EXPECT_EQ(flags & FD_CLOEXEC, 0);
4596abc20f8SChristian Brauner 
4606abc20f8SChristian Brauner 	EXPECT_EQ(close(fd1), 0);
4616abc20f8SChristian Brauner 	EXPECT_EQ(close(fd2), 0);
4626abc20f8SChristian Brauner 	EXPECT_EQ(close(fd3), 0);
4636abc20f8SChristian Brauner }
4646abc20f8SChristian Brauner 
4656abc20f8SChristian Brauner /*
4666abc20f8SChristian Brauner  * Regression test for syzbot+96cfd2b22b3213646a93@syzkaller.appspotmail.com
4676abc20f8SChristian Brauner  */
TEST(close_range_cloexec_unshare_syzbot)4686abc20f8SChristian Brauner TEST(close_range_cloexec_unshare_syzbot)
4696abc20f8SChristian Brauner {
4706abc20f8SChristian Brauner 	int i, fd1, fd2, fd3, flags, ret, status;
4716abc20f8SChristian Brauner 	pid_t pid;
4726abc20f8SChristian Brauner 	struct __clone_args args = {
4736abc20f8SChristian Brauner 		.flags = CLONE_FILES,
4746abc20f8SChristian Brauner 		.exit_signal = SIGCHLD,
4756abc20f8SChristian Brauner 	};
4766abc20f8SChristian Brauner 
4776abc20f8SChristian Brauner 	/*
4786abc20f8SChristian Brauner 	 * Create a huge gap in the fd table. When we now call
4796abc20f8SChristian Brauner 	 * CLOSE_RANGE_UNSHARE with a shared fd table and and with ~0U as upper
4806abc20f8SChristian Brauner 	 * bound the kernel will only copy up to fd1 file descriptors into the
4816abc20f8SChristian Brauner 	 * new fd table. If the kernel is buggy and doesn't handle
4826abc20f8SChristian Brauner 	 * CLOSE_RANGE_CLOEXEC correctly it will not have copied all file
4836abc20f8SChristian Brauner 	 * descriptors and we will oops!
4846abc20f8SChristian Brauner 	 *
4856abc20f8SChristian Brauner 	 * On a buggy kernel this should immediately oops. But let's loop just
4866abc20f8SChristian Brauner 	 * to be sure.
4876abc20f8SChristian Brauner 	 */
4886abc20f8SChristian Brauner 	fd1 = open("/dev/null", O_RDWR);
4896abc20f8SChristian Brauner 	EXPECT_GT(fd1, 0);
4906abc20f8SChristian Brauner 
4916abc20f8SChristian Brauner 	fd2 = dup2(fd1, 1000);
4926abc20f8SChristian Brauner 	EXPECT_GT(fd2, 0);
4936abc20f8SChristian Brauner 
4946abc20f8SChristian Brauner 	for (i = 0; i < 100; i++) {
4956abc20f8SChristian Brauner 
4966abc20f8SChristian Brauner 		pid = sys_clone3(&args, sizeof(args));
4976abc20f8SChristian Brauner 		ASSERT_GE(pid, 0);
4986abc20f8SChristian Brauner 
4996abc20f8SChristian Brauner 		if (pid == 0) {
5006abc20f8SChristian Brauner 			ret = sys_close_range(3, ~0U, CLOSE_RANGE_UNSHARE |
5016abc20f8SChristian Brauner 						      CLOSE_RANGE_CLOEXEC);
5026abc20f8SChristian Brauner 			if (ret)
5036abc20f8SChristian Brauner 				exit(EXIT_FAILURE);
5046abc20f8SChristian Brauner 
5056abc20f8SChristian Brauner 			/*
5066abc20f8SChristian Brauner 			 * We now have a private file descriptor table and all
5076abc20f8SChristian Brauner 			 * our open fds should still be open but made
5086abc20f8SChristian Brauner 			 * close-on-exec.
5096abc20f8SChristian Brauner 			 */
5106abc20f8SChristian Brauner 			flags = fcntl(fd1, F_GETFD);
5116abc20f8SChristian Brauner 			EXPECT_GT(flags, -1);
5126abc20f8SChristian Brauner 			EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
5136abc20f8SChristian Brauner 
5146abc20f8SChristian Brauner 			flags = fcntl(fd2, F_GETFD);
5156abc20f8SChristian Brauner 			EXPECT_GT(flags, -1);
5166abc20f8SChristian Brauner 			EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
5176abc20f8SChristian Brauner 
5186abc20f8SChristian Brauner 			fd3 = dup2(fd1, 42);
5196abc20f8SChristian Brauner 			EXPECT_GT(fd3, 0);
5206abc20f8SChristian Brauner 
5216abc20f8SChristian Brauner 			/*
5226abc20f8SChristian Brauner 			 * Duplicating the file descriptor must remove the
5236abc20f8SChristian Brauner 			 * FD_CLOEXEC flag.
5246abc20f8SChristian Brauner 			 */
5256abc20f8SChristian Brauner 			flags = fcntl(fd3, F_GETFD);
5266abc20f8SChristian Brauner 			EXPECT_GT(flags, -1);
5276abc20f8SChristian Brauner 			EXPECT_EQ(flags & FD_CLOEXEC, 0);
5286abc20f8SChristian Brauner 
5296abc20f8SChristian Brauner 			EXPECT_EQ(close(fd1), 0);
5306abc20f8SChristian Brauner 			EXPECT_EQ(close(fd2), 0);
5316abc20f8SChristian Brauner 			EXPECT_EQ(close(fd3), 0);
5326abc20f8SChristian Brauner 
5336abc20f8SChristian Brauner 			exit(EXIT_SUCCESS);
5346abc20f8SChristian Brauner 		}
5356abc20f8SChristian Brauner 
5366abc20f8SChristian Brauner 		EXPECT_EQ(waitpid(pid, &status, 0), pid);
5376abc20f8SChristian Brauner 		EXPECT_EQ(true, WIFEXITED(status));
5386abc20f8SChristian Brauner 		EXPECT_EQ(0, WEXITSTATUS(status));
5396abc20f8SChristian Brauner 	}
5406abc20f8SChristian Brauner 
5416abc20f8SChristian Brauner 	/*
5426abc20f8SChristian Brauner 	 * We created a private file descriptor table before along with
5436abc20f8SChristian Brauner 	 * requesting close-on-exec so the original fds must not be
5446abc20f8SChristian Brauner 	 * close-on-exec.
5456abc20f8SChristian Brauner 	 */
5466abc20f8SChristian Brauner 	flags = fcntl(fd1, F_GETFD);
5476abc20f8SChristian Brauner 	EXPECT_GT(flags, -1);
5486abc20f8SChristian Brauner 	EXPECT_EQ(flags & FD_CLOEXEC, 0);
5496abc20f8SChristian Brauner 
5506abc20f8SChristian Brauner 	flags = fcntl(fd2, F_GETFD);
5516abc20f8SChristian Brauner 	EXPECT_GT(flags, -1);
5526abc20f8SChristian Brauner 	EXPECT_EQ(flags & FD_CLOEXEC, 0);
5536abc20f8SChristian Brauner 
5546abc20f8SChristian Brauner 	fd3 = dup2(fd1, 42);
5556abc20f8SChristian Brauner 	EXPECT_GT(fd3, 0);
5566abc20f8SChristian Brauner 
5576abc20f8SChristian Brauner 	flags = fcntl(fd3, F_GETFD);
5586abc20f8SChristian Brauner 	EXPECT_GT(flags, -1);
5596abc20f8SChristian Brauner 	EXPECT_EQ(flags & FD_CLOEXEC, 0);
5606abc20f8SChristian Brauner 
5616abc20f8SChristian Brauner 	EXPECT_EQ(close(fd1), 0);
5626abc20f8SChristian Brauner 	EXPECT_EQ(close(fd2), 0);
5636abc20f8SChristian Brauner 	EXPECT_EQ(close(fd3), 0);
5646abc20f8SChristian Brauner }
5656abc20f8SChristian Brauner 
5662c5db60eSChristian Brauner TEST_HARNESS_MAIN
567