1
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
26static 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
36TEST(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
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
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
95TEST(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
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
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
184TEST(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
227TEST_HARNESS_MAIN
228