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 
19 #ifndef __NR_close_range
20 #define __NR_close_range -1
21 #endif
22 
23 #ifndef CLOSE_RANGE_UNSHARE
24 #define CLOSE_RANGE_UNSHARE	(1U << 1)
25 #endif
26 
27 #ifndef CLOSE_RANGE_CLOEXEC
28 #define CLOSE_RANGE_CLOEXEC	(1U << 2)
29 #endif
30 
31 static inline int sys_close_range(unsigned int fd, unsigned int max_fd,
32 				  unsigned int flags)
33 {
34 	return syscall(__NR_close_range, fd, max_fd, flags);
35 }
36 
37 #ifndef ARRAY_SIZE
38 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
39 #endif
40 
41 TEST(close_range)
42 {
43 	int i, ret;
44 	int open_fds[101];
45 
46 	for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
47 		int fd;
48 
49 		fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
50 		ASSERT_GE(fd, 0) {
51 			if (errno == ENOENT)
52 				SKIP(return, "Skipping test since /dev/null does not exist");
53 		}
54 
55 		open_fds[i] = fd;
56 	}
57 
58 	EXPECT_EQ(-1, sys_close_range(open_fds[0], open_fds[100], -1)) {
59 		if (errno == ENOSYS)
60 			SKIP(return, "close_range() syscall not supported");
61 	}
62 
63 	EXPECT_EQ(0, sys_close_range(open_fds[0], open_fds[50], 0));
64 
65 	for (i = 0; i <= 50; i++)
66 		EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
67 
68 	for (i = 51; i <= 100; i++)
69 		EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
70 
71 	/* create a couple of gaps */
72 	close(57);
73 	close(78);
74 	close(81);
75 	close(82);
76 	close(84);
77 	close(90);
78 
79 	EXPECT_EQ(0, sys_close_range(open_fds[51], open_fds[92], 0));
80 
81 	for (i = 51; i <= 92; i++)
82 		EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
83 
84 	for (i = 93; i <= 100; i++)
85 		EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
86 
87 	/* test that the kernel caps and still closes all fds */
88 	EXPECT_EQ(0, sys_close_range(open_fds[93], open_fds[99], 0));
89 
90 	for (i = 93; i <= 99; i++)
91 		EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
92 
93 	EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
94 
95 	EXPECT_EQ(0, sys_close_range(open_fds[100], open_fds[100], 0));
96 
97 	EXPECT_EQ(-1, fcntl(open_fds[100], F_GETFL));
98 }
99 
100 TEST(close_range_unshare)
101 {
102 	int i, ret, status;
103 	pid_t pid;
104 	int open_fds[101];
105 	struct clone_args args = {
106 		.flags = CLONE_FILES,
107 		.exit_signal = SIGCHLD,
108 	};
109 
110 	for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
111 		int fd;
112 
113 		fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
114 		ASSERT_GE(fd, 0) {
115 			if (errno == ENOENT)
116 				SKIP(return, "Skipping test since /dev/null does not exist");
117 		}
118 
119 		open_fds[i] = fd;
120 	}
121 
122 	pid = sys_clone3(&args, sizeof(args));
123 	ASSERT_GE(pid, 0);
124 
125 	if (pid == 0) {
126 		ret = sys_close_range(open_fds[0], open_fds[50],
127 				      CLOSE_RANGE_UNSHARE);
128 		if (ret)
129 			exit(EXIT_FAILURE);
130 
131 		for (i = 0; i <= 50; i++)
132 			if (fcntl(open_fds[i], F_GETFL) != -1)
133 				exit(EXIT_FAILURE);
134 
135 		for (i = 51; i <= 100; i++)
136 			if (fcntl(open_fds[i], F_GETFL) == -1)
137 				exit(EXIT_FAILURE);
138 
139 		/* create a couple of gaps */
140 		close(57);
141 		close(78);
142 		close(81);
143 		close(82);
144 		close(84);
145 		close(90);
146 
147 		ret = sys_close_range(open_fds[51], open_fds[92],
148 				      CLOSE_RANGE_UNSHARE);
149 		if (ret)
150 			exit(EXIT_FAILURE);
151 
152 		for (i = 51; i <= 92; i++)
153 			if (fcntl(open_fds[i], F_GETFL) != -1)
154 				exit(EXIT_FAILURE);
155 
156 		for (i = 93; i <= 100; i++)
157 			if (fcntl(open_fds[i], F_GETFL) == -1)
158 				exit(EXIT_FAILURE);
159 
160 		/* test that the kernel caps and still closes all fds */
161 		ret = sys_close_range(open_fds[93], open_fds[99],
162 				      CLOSE_RANGE_UNSHARE);
163 		if (ret)
164 			exit(EXIT_FAILURE);
165 
166 		for (i = 93; i <= 99; i++)
167 			if (fcntl(open_fds[i], F_GETFL) != -1)
168 				exit(EXIT_FAILURE);
169 
170 		if (fcntl(open_fds[100], F_GETFL) == -1)
171 			exit(EXIT_FAILURE);
172 
173 		ret = sys_close_range(open_fds[100], open_fds[100],
174 				      CLOSE_RANGE_UNSHARE);
175 		if (ret)
176 			exit(EXIT_FAILURE);
177 
178 		if (fcntl(open_fds[100], F_GETFL) != -1)
179 			exit(EXIT_FAILURE);
180 
181 		exit(EXIT_SUCCESS);
182 	}
183 
184 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
185 	EXPECT_EQ(true, WIFEXITED(status));
186 	EXPECT_EQ(0, WEXITSTATUS(status));
187 }
188 
189 TEST(close_range_unshare_capped)
190 {
191 	int i, ret, status;
192 	pid_t pid;
193 	int open_fds[101];
194 	struct clone_args args = {
195 		.flags = CLONE_FILES,
196 		.exit_signal = SIGCHLD,
197 	};
198 
199 	for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
200 		int fd;
201 
202 		fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
203 		ASSERT_GE(fd, 0) {
204 			if (errno == ENOENT)
205 				SKIP(return, "Skipping test since /dev/null does not exist");
206 		}
207 
208 		open_fds[i] = fd;
209 	}
210 
211 	pid = sys_clone3(&args, sizeof(args));
212 	ASSERT_GE(pid, 0);
213 
214 	if (pid == 0) {
215 		ret = sys_close_range(open_fds[0], UINT_MAX,
216 				      CLOSE_RANGE_UNSHARE);
217 		if (ret)
218 			exit(EXIT_FAILURE);
219 
220 		for (i = 0; i <= 100; i++)
221 			if (fcntl(open_fds[i], F_GETFL) != -1)
222 				exit(EXIT_FAILURE);
223 
224 		exit(EXIT_SUCCESS);
225 	}
226 
227 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
228 	EXPECT_EQ(true, WIFEXITED(status));
229 	EXPECT_EQ(0, WEXITSTATUS(status));
230 }
231 
232 TEST(close_range_cloexec)
233 {
234 	int i, ret;
235 	int open_fds[101];
236 	struct rlimit rlimit;
237 
238 	for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
239 		int fd;
240 
241 		fd = open("/dev/null", O_RDONLY);
242 		ASSERT_GE(fd, 0) {
243 			if (errno == ENOENT)
244 				XFAIL(return, "Skipping test since /dev/null does not exist");
245 		}
246 
247 		open_fds[i] = fd;
248 	}
249 
250 	ret = sys_close_range(1000, 1000, CLOSE_RANGE_CLOEXEC);
251 	if (ret < 0) {
252 		if (errno == ENOSYS)
253 			XFAIL(return, "close_range() syscall not supported");
254 		if (errno == EINVAL)
255 			XFAIL(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC");
256 	}
257 
258 	/* Ensure the FD_CLOEXEC bit is set also with a resource limit in place.  */
259 	ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit));
260 	rlimit.rlim_cur = 25;
261 	ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlimit));
262 
263 	/* Set close-on-exec for two ranges: [0-50] and [75-100].  */
264 	ret = sys_close_range(open_fds[0], open_fds[50], CLOSE_RANGE_CLOEXEC);
265 	ASSERT_EQ(0, ret);
266 	ret = sys_close_range(open_fds[75], open_fds[100], CLOSE_RANGE_CLOEXEC);
267 	ASSERT_EQ(0, ret);
268 
269 	for (i = 0; i <= 50; i++) {
270 		int flags = fcntl(open_fds[i], F_GETFD);
271 
272 		EXPECT_GT(flags, -1);
273 		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
274 	}
275 
276 	for (i = 51; i <= 74; i++) {
277 		int flags = fcntl(open_fds[i], F_GETFD);
278 
279 		EXPECT_GT(flags, -1);
280 		EXPECT_EQ(flags & FD_CLOEXEC, 0);
281 	}
282 
283 	for (i = 75; i <= 100; i++) {
284 		int flags = fcntl(open_fds[i], F_GETFD);
285 
286 		EXPECT_GT(flags, -1);
287 		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
288 	}
289 
290 	/* Test a common pattern.  */
291 	ret = sys_close_range(3, UINT_MAX, CLOSE_RANGE_CLOEXEC);
292 	for (i = 0; i <= 100; i++) {
293 		int flags = fcntl(open_fds[i], F_GETFD);
294 
295 		EXPECT_GT(flags, -1);
296 		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
297 	}
298 }
299 
300 
301 TEST_HARNESS_MAIN
302