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
sys_close_range(unsigned int fd,unsigned int max_fd,unsigned int flags)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
TEST(close_range)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 SKIP(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 SKIP(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
TEST(close_range_unshare)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 SKIP(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
TEST(close_range_unshare_capped)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 SKIP(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