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 
15 #include "../kselftest_harness.h"
16 #include "../clone3/clone3_selftests.h"
17 
18 #ifndef __NR_close_range
19 #define __NR_close_range -1
20 #endif
21 
22 #ifndef CLOSE_RANGE_UNSHARE
23 #define CLOSE_RANGE_UNSHARE	(1U << 1)
24 #endif
25 
26 static inline int sys_close_range(unsigned int fd, unsigned int max_fd,
27 				  unsigned int flags)
28 {
29 	return syscall(__NR_close_range, fd, max_fd, flags);
30 }
31 
32 #ifndef ARRAY_SIZE
33 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
34 #endif
35 
36 TEST(close_range)
37 {
38 	int i, ret;
39 	int open_fds[101];
40 
41 	for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
42 		int fd;
43 
44 		fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
45 		ASSERT_GE(fd, 0) {
46 			if (errno == ENOENT)
47 				XFAIL(return, "Skipping test since /dev/null does not exist");
48 		}
49 
50 		open_fds[i] = fd;
51 	}
52 
53 	EXPECT_EQ(-1, sys_close_range(open_fds[0], open_fds[100], -1)) {
54 		if (errno == ENOSYS)
55 			XFAIL(return, "close_range() syscall not supported");
56 	}
57 
58 	EXPECT_EQ(0, sys_close_range(open_fds[0], open_fds[50], 0));
59 
60 	for (i = 0; i <= 50; i++)
61 		EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
62 
63 	for (i = 51; i <= 100; i++)
64 		EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
65 
66 	/* create a couple of gaps */
67 	close(57);
68 	close(78);
69 	close(81);
70 	close(82);
71 	close(84);
72 	close(90);
73 
74 	EXPECT_EQ(0, sys_close_range(open_fds[51], open_fds[92], 0));
75 
76 	for (i = 51; i <= 92; i++)
77 		EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
78 
79 	for (i = 93; i <= 100; i++)
80 		EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
81 
82 	/* test that the kernel caps and still closes all fds */
83 	EXPECT_EQ(0, sys_close_range(open_fds[93], open_fds[99], 0));
84 
85 	for (i = 93; i <= 99; i++)
86 		EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
87 
88 	EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
89 
90 	EXPECT_EQ(0, sys_close_range(open_fds[100], open_fds[100], 0));
91 
92 	EXPECT_EQ(-1, fcntl(open_fds[100], F_GETFL));
93 }
94 
95 TEST(close_range_unshare)
96 {
97 	int i, ret, status;
98 	pid_t pid;
99 	int open_fds[101];
100 	struct clone_args args = {
101 		.flags = CLONE_FILES,
102 		.exit_signal = SIGCHLD,
103 	};
104 
105 	for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
106 		int fd;
107 
108 		fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
109 		ASSERT_GE(fd, 0) {
110 			if (errno == ENOENT)
111 				XFAIL(return, "Skipping test since /dev/null does not exist");
112 		}
113 
114 		open_fds[i] = fd;
115 	}
116 
117 	pid = sys_clone3(&args, sizeof(args));
118 	ASSERT_GE(pid, 0);
119 
120 	if (pid == 0) {
121 		ret = sys_close_range(open_fds[0], open_fds[50],
122 				      CLOSE_RANGE_UNSHARE);
123 		if (ret)
124 			exit(EXIT_FAILURE);
125 
126 		for (i = 0; i <= 50; i++)
127 			if (fcntl(open_fds[i], F_GETFL) != -1)
128 				exit(EXIT_FAILURE);
129 
130 		for (i = 51; i <= 100; i++)
131 			if (fcntl(open_fds[i], F_GETFL) == -1)
132 				exit(EXIT_FAILURE);
133 
134 		/* create a couple of gaps */
135 		close(57);
136 		close(78);
137 		close(81);
138 		close(82);
139 		close(84);
140 		close(90);
141 
142 		ret = sys_close_range(open_fds[51], open_fds[92],
143 				      CLOSE_RANGE_UNSHARE);
144 		if (ret)
145 			exit(EXIT_FAILURE);
146 
147 		for (i = 51; i <= 92; i++)
148 			if (fcntl(open_fds[i], F_GETFL) != -1)
149 				exit(EXIT_FAILURE);
150 
151 		for (i = 93; i <= 100; i++)
152 			if (fcntl(open_fds[i], F_GETFL) == -1)
153 				exit(EXIT_FAILURE);
154 
155 		/* test that the kernel caps and still closes all fds */
156 		ret = sys_close_range(open_fds[93], open_fds[99],
157 				      CLOSE_RANGE_UNSHARE);
158 		if (ret)
159 			exit(EXIT_FAILURE);
160 
161 		for (i = 93; i <= 99; i++)
162 			if (fcntl(open_fds[i], F_GETFL) != -1)
163 				exit(EXIT_FAILURE);
164 
165 		if (fcntl(open_fds[100], F_GETFL) == -1)
166 			exit(EXIT_FAILURE);
167 
168 		ret = sys_close_range(open_fds[100], open_fds[100],
169 				      CLOSE_RANGE_UNSHARE);
170 		if (ret)
171 			exit(EXIT_FAILURE);
172 
173 		if (fcntl(open_fds[100], F_GETFL) != -1)
174 			exit(EXIT_FAILURE);
175 
176 		exit(EXIT_SUCCESS);
177 	}
178 
179 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
180 	EXPECT_EQ(true, WIFEXITED(status));
181 	EXPECT_EQ(0, WEXITSTATUS(status));
182 }
183 
184 TEST(close_range_unshare_capped)
185 {
186 	int i, ret, status;
187 	pid_t pid;
188 	int open_fds[101];
189 	struct clone_args args = {
190 		.flags = CLONE_FILES,
191 		.exit_signal = SIGCHLD,
192 	};
193 
194 	for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
195 		int fd;
196 
197 		fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
198 		ASSERT_GE(fd, 0) {
199 			if (errno == ENOENT)
200 				XFAIL(return, "Skipping test since /dev/null does not exist");
201 		}
202 
203 		open_fds[i] = fd;
204 	}
205 
206 	pid = sys_clone3(&args, sizeof(args));
207 	ASSERT_GE(pid, 0);
208 
209 	if (pid == 0) {
210 		ret = sys_close_range(open_fds[0], UINT_MAX,
211 				      CLOSE_RANGE_UNSHARE);
212 		if (ret)
213 			exit(EXIT_FAILURE);
214 
215 		for (i = 0; i <= 100; i++)
216 			if (fcntl(open_fds[i], F_GETFL) != -1)
217 				exit(EXIT_FAILURE);
218 
219 		exit(EXIT_SUCCESS);
220 	}
221 
222 	EXPECT_EQ(waitpid(pid, &status, 0), pid);
223 	EXPECT_EQ(true, WIFEXITED(status));
224 	EXPECT_EQ(0, WEXITSTATUS(status));
225 }
226 
227 TEST_HARNESS_MAIN
228