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>
1501c1484aSMuhammad Usama Anjum #include <linux/close_range.h>
162c5db60eSChristian Brauner
172c5db60eSChristian Brauner #include "../kselftest_harness.h"
18a5161eeeSChristian Brauner #include "../clone3/clone3_selftests.h"
192c5db60eSChristian Brauner
204810ce7cSChristian Brauner
214810ce7cSChristian Brauner #ifndef F_LINUX_SPECIFIC_BASE
224810ce7cSChristian Brauner #define F_LINUX_SPECIFIC_BASE 1024
234810ce7cSChristian Brauner #endif
244810ce7cSChristian Brauner
254810ce7cSChristian Brauner #ifndef F_DUPFD_QUERY
264810ce7cSChristian Brauner #define F_DUPFD_QUERY (F_LINUX_SPECIFIC_BASE + 3)
274810ce7cSChristian Brauner #endif
284810ce7cSChristian Brauner
29*d0fe8920SChristian Brauner #ifndef F_CREATED_QUERY
30*d0fe8920SChristian Brauner #define F_CREATED_QUERY (F_LINUX_SPECIFIC_BASE + 4)
31*d0fe8920SChristian Brauner #endif
32*d0fe8920SChristian Brauner
sys_close_range(unsigned int fd,unsigned int max_fd,unsigned int flags)332c5db60eSChristian Brauner static inline int sys_close_range(unsigned int fd, unsigned int max_fd,
342c5db60eSChristian Brauner unsigned int flags)
352c5db60eSChristian Brauner {
362c5db60eSChristian Brauner return syscall(__NR_close_range, fd, max_fd, flags);
372c5db60eSChristian Brauner }
382c5db60eSChristian Brauner
TEST(core_close_range)39f35dcaa0SShuah Khan TEST(core_close_range)
402c5db60eSChristian Brauner {
412c5db60eSChristian Brauner int i, ret;
422c5db60eSChristian Brauner int open_fds[101];
432c5db60eSChristian Brauner
442c5db60eSChristian Brauner for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
452c5db60eSChristian Brauner int fd;
462c5db60eSChristian Brauner
472c5db60eSChristian Brauner fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
482c5db60eSChristian Brauner ASSERT_GE(fd, 0) {
492c5db60eSChristian Brauner if (errno == ENOENT)
501d44d0ddSTommi Rantala SKIP(return, "Skipping test since /dev/null does not exist");
512c5db60eSChristian Brauner }
522c5db60eSChristian Brauner
532c5db60eSChristian Brauner open_fds[i] = fd;
542c5db60eSChristian Brauner }
552c5db60eSChristian Brauner
562c5db60eSChristian Brauner EXPECT_EQ(-1, sys_close_range(open_fds[0], open_fds[100], -1)) {
572c5db60eSChristian Brauner if (errno == ENOSYS)
581d44d0ddSTommi Rantala SKIP(return, "close_range() syscall not supported");
592c5db60eSChristian Brauner }
602c5db60eSChristian Brauner
614810ce7cSChristian Brauner for (i = 0; i < 100; i++) {
624810ce7cSChristian Brauner ret = fcntl(open_fds[i], F_DUPFD_QUERY, open_fds[i + 1]);
634810ce7cSChristian Brauner if (ret < 0) {
644810ce7cSChristian Brauner EXPECT_EQ(errno, EINVAL);
654810ce7cSChristian Brauner } else {
664810ce7cSChristian Brauner EXPECT_EQ(ret, 0);
674810ce7cSChristian Brauner }
684810ce7cSChristian Brauner }
694810ce7cSChristian Brauner
702c5db60eSChristian Brauner EXPECT_EQ(0, sys_close_range(open_fds[0], open_fds[50], 0));
712c5db60eSChristian Brauner
722c5db60eSChristian Brauner for (i = 0; i <= 50; i++)
732c5db60eSChristian Brauner EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
742c5db60eSChristian Brauner
752c5db60eSChristian Brauner for (i = 51; i <= 100; i++)
762c5db60eSChristian Brauner EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
772c5db60eSChristian Brauner
782c5db60eSChristian Brauner /* create a couple of gaps */
792c5db60eSChristian Brauner close(57);
802c5db60eSChristian Brauner close(78);
812c5db60eSChristian Brauner close(81);
822c5db60eSChristian Brauner close(82);
832c5db60eSChristian Brauner close(84);
842c5db60eSChristian Brauner close(90);
852c5db60eSChristian Brauner
862c5db60eSChristian Brauner EXPECT_EQ(0, sys_close_range(open_fds[51], open_fds[92], 0));
872c5db60eSChristian Brauner
882c5db60eSChristian Brauner for (i = 51; i <= 92; i++)
892c5db60eSChristian Brauner EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
902c5db60eSChristian Brauner
912c5db60eSChristian Brauner for (i = 93; i <= 100; i++)
922c5db60eSChristian Brauner EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
932c5db60eSChristian Brauner
942c5db60eSChristian Brauner /* test that the kernel caps and still closes all fds */
952c5db60eSChristian Brauner EXPECT_EQ(0, sys_close_range(open_fds[93], open_fds[99], 0));
962c5db60eSChristian Brauner
972c5db60eSChristian Brauner for (i = 93; i <= 99; i++)
982c5db60eSChristian Brauner EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
992c5db60eSChristian Brauner
1002c5db60eSChristian Brauner EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
1012c5db60eSChristian Brauner
1022c5db60eSChristian Brauner EXPECT_EQ(0, sys_close_range(open_fds[100], open_fds[100], 0));
1032c5db60eSChristian Brauner
1042c5db60eSChristian Brauner EXPECT_EQ(-1, fcntl(open_fds[100], F_GETFL));
1052c5db60eSChristian Brauner }
1062c5db60eSChristian Brauner
TEST(close_range_unshare)107a5161eeeSChristian Brauner TEST(close_range_unshare)
108a5161eeeSChristian Brauner {
109a5161eeeSChristian Brauner int i, ret, status;
110a5161eeeSChristian Brauner pid_t pid;
111a5161eeeSChristian Brauner int open_fds[101];
112ca202504STobias Klauser struct __clone_args args = {
113a5161eeeSChristian Brauner .flags = CLONE_FILES,
114a5161eeeSChristian Brauner .exit_signal = SIGCHLD,
115a5161eeeSChristian Brauner };
116a5161eeeSChristian Brauner
117a5161eeeSChristian Brauner for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
118a5161eeeSChristian Brauner int fd;
119a5161eeeSChristian Brauner
120a5161eeeSChristian Brauner fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
121a5161eeeSChristian Brauner ASSERT_GE(fd, 0) {
122a5161eeeSChristian Brauner if (errno == ENOENT)
1231d44d0ddSTommi Rantala SKIP(return, "Skipping test since /dev/null does not exist");
124a5161eeeSChristian Brauner }
125a5161eeeSChristian Brauner
126a5161eeeSChristian Brauner open_fds[i] = fd;
127a5161eeeSChristian Brauner }
128a5161eeeSChristian Brauner
129a5161eeeSChristian Brauner pid = sys_clone3(&args, sizeof(args));
130a5161eeeSChristian Brauner ASSERT_GE(pid, 0);
131a5161eeeSChristian Brauner
132a5161eeeSChristian Brauner if (pid == 0) {
133a5161eeeSChristian Brauner ret = sys_close_range(open_fds[0], open_fds[50],
134a5161eeeSChristian Brauner CLOSE_RANGE_UNSHARE);
135a5161eeeSChristian Brauner if (ret)
136a5161eeeSChristian Brauner exit(EXIT_FAILURE);
137a5161eeeSChristian Brauner
138a5161eeeSChristian Brauner for (i = 0; i <= 50; i++)
139a5161eeeSChristian Brauner if (fcntl(open_fds[i], F_GETFL) != -1)
140a5161eeeSChristian Brauner exit(EXIT_FAILURE);
141a5161eeeSChristian Brauner
142a5161eeeSChristian Brauner for (i = 51; i <= 100; i++)
143a5161eeeSChristian Brauner if (fcntl(open_fds[i], F_GETFL) == -1)
144a5161eeeSChristian Brauner exit(EXIT_FAILURE);
145a5161eeeSChristian Brauner
146a5161eeeSChristian Brauner /* create a couple of gaps */
147a5161eeeSChristian Brauner close(57);
148a5161eeeSChristian Brauner close(78);
149a5161eeeSChristian Brauner close(81);
150a5161eeeSChristian Brauner close(82);
151a5161eeeSChristian Brauner close(84);
152a5161eeeSChristian Brauner close(90);
153a5161eeeSChristian Brauner
154a5161eeeSChristian Brauner ret = sys_close_range(open_fds[51], open_fds[92],
155a5161eeeSChristian Brauner CLOSE_RANGE_UNSHARE);
156a5161eeeSChristian Brauner if (ret)
157a5161eeeSChristian Brauner exit(EXIT_FAILURE);
158a5161eeeSChristian Brauner
159a5161eeeSChristian Brauner for (i = 51; i <= 92; i++)
160a5161eeeSChristian Brauner if (fcntl(open_fds[i], F_GETFL) != -1)
161a5161eeeSChristian Brauner exit(EXIT_FAILURE);
162a5161eeeSChristian Brauner
163a5161eeeSChristian Brauner for (i = 93; i <= 100; i++)
164a5161eeeSChristian Brauner if (fcntl(open_fds[i], F_GETFL) == -1)
165a5161eeeSChristian Brauner exit(EXIT_FAILURE);
166a5161eeeSChristian Brauner
167a5161eeeSChristian Brauner /* test that the kernel caps and still closes all fds */
168a5161eeeSChristian Brauner ret = sys_close_range(open_fds[93], open_fds[99],
169a5161eeeSChristian Brauner CLOSE_RANGE_UNSHARE);
170a5161eeeSChristian Brauner if (ret)
171a5161eeeSChristian Brauner exit(EXIT_FAILURE);
172a5161eeeSChristian Brauner
173a5161eeeSChristian Brauner for (i = 93; i <= 99; i++)
174a5161eeeSChristian Brauner if (fcntl(open_fds[i], F_GETFL) != -1)
175a5161eeeSChristian Brauner exit(EXIT_FAILURE);
176a5161eeeSChristian Brauner
177a5161eeeSChristian Brauner if (fcntl(open_fds[100], F_GETFL) == -1)
178a5161eeeSChristian Brauner exit(EXIT_FAILURE);
179a5161eeeSChristian Brauner
180a5161eeeSChristian Brauner ret = sys_close_range(open_fds[100], open_fds[100],
181a5161eeeSChristian Brauner CLOSE_RANGE_UNSHARE);
182a5161eeeSChristian Brauner if (ret)
183a5161eeeSChristian Brauner exit(EXIT_FAILURE);
184a5161eeeSChristian Brauner
185a5161eeeSChristian Brauner if (fcntl(open_fds[100], F_GETFL) != -1)
186a5161eeeSChristian Brauner exit(EXIT_FAILURE);
187a5161eeeSChristian Brauner
188a5161eeeSChristian Brauner exit(EXIT_SUCCESS);
189a5161eeeSChristian Brauner }
190a5161eeeSChristian Brauner
191a5161eeeSChristian Brauner EXPECT_EQ(waitpid(pid, &status, 0), pid);
192a5161eeeSChristian Brauner EXPECT_EQ(true, WIFEXITED(status));
193a5161eeeSChristian Brauner EXPECT_EQ(0, WEXITSTATUS(status));
194a5161eeeSChristian Brauner }
195a5161eeeSChristian Brauner
TEST(close_range_unshare_capped)196a5161eeeSChristian Brauner TEST(close_range_unshare_capped)
197a5161eeeSChristian Brauner {
198a5161eeeSChristian Brauner int i, ret, status;
199a5161eeeSChristian Brauner pid_t pid;
200a5161eeeSChristian Brauner int open_fds[101];
201ca202504STobias Klauser struct __clone_args args = {
202a5161eeeSChristian Brauner .flags = CLONE_FILES,
203a5161eeeSChristian Brauner .exit_signal = SIGCHLD,
204a5161eeeSChristian Brauner };
205a5161eeeSChristian Brauner
206a5161eeeSChristian Brauner for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
207a5161eeeSChristian Brauner int fd;
208a5161eeeSChristian Brauner
209a5161eeeSChristian Brauner fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
210a5161eeeSChristian Brauner ASSERT_GE(fd, 0) {
211a5161eeeSChristian Brauner if (errno == ENOENT)
2121d44d0ddSTommi Rantala SKIP(return, "Skipping test since /dev/null does not exist");
213a5161eeeSChristian Brauner }
214a5161eeeSChristian Brauner
215a5161eeeSChristian Brauner open_fds[i] = fd;
216a5161eeeSChristian Brauner }
217a5161eeeSChristian Brauner
218a5161eeeSChristian Brauner pid = sys_clone3(&args, sizeof(args));
219a5161eeeSChristian Brauner ASSERT_GE(pid, 0);
220a5161eeeSChristian Brauner
221a5161eeeSChristian Brauner if (pid == 0) {
222a5161eeeSChristian Brauner ret = sys_close_range(open_fds[0], UINT_MAX,
223a5161eeeSChristian Brauner CLOSE_RANGE_UNSHARE);
224a5161eeeSChristian Brauner if (ret)
225a5161eeeSChristian Brauner exit(EXIT_FAILURE);
226a5161eeeSChristian Brauner
227a5161eeeSChristian Brauner for (i = 0; i <= 100; i++)
228a5161eeeSChristian Brauner if (fcntl(open_fds[i], F_GETFL) != -1)
229a5161eeeSChristian Brauner exit(EXIT_FAILURE);
230a5161eeeSChristian Brauner
231a5161eeeSChristian Brauner exit(EXIT_SUCCESS);
232a5161eeeSChristian Brauner }
233a5161eeeSChristian Brauner
234a5161eeeSChristian Brauner EXPECT_EQ(waitpid(pid, &status, 0), pid);
235a5161eeeSChristian Brauner EXPECT_EQ(true, WIFEXITED(status));
236a5161eeeSChristian Brauner EXPECT_EQ(0, WEXITSTATUS(status));
237a5161eeeSChristian Brauner }
238a5161eeeSChristian Brauner
TEST(close_range_cloexec)23923afeaefSGiuseppe Scrivano TEST(close_range_cloexec)
24023afeaefSGiuseppe Scrivano {
24123afeaefSGiuseppe Scrivano int i, ret;
24223afeaefSGiuseppe Scrivano int open_fds[101];
24323afeaefSGiuseppe Scrivano struct rlimit rlimit;
24423afeaefSGiuseppe Scrivano
24523afeaefSGiuseppe Scrivano for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
24623afeaefSGiuseppe Scrivano int fd;
24723afeaefSGiuseppe Scrivano
24823afeaefSGiuseppe Scrivano fd = open("/dev/null", O_RDONLY);
24923afeaefSGiuseppe Scrivano ASSERT_GE(fd, 0) {
25023afeaefSGiuseppe Scrivano if (errno == ENOENT)
251ca202504STobias Klauser SKIP(return, "Skipping test since /dev/null does not exist");
25223afeaefSGiuseppe Scrivano }
25323afeaefSGiuseppe Scrivano
25423afeaefSGiuseppe Scrivano open_fds[i] = fd;
25523afeaefSGiuseppe Scrivano }
25623afeaefSGiuseppe Scrivano
25723afeaefSGiuseppe Scrivano ret = sys_close_range(1000, 1000, CLOSE_RANGE_CLOEXEC);
25823afeaefSGiuseppe Scrivano if (ret < 0) {
25923afeaefSGiuseppe Scrivano if (errno == ENOSYS)
260ca202504STobias Klauser SKIP(return, "close_range() syscall not supported");
26123afeaefSGiuseppe Scrivano if (errno == EINVAL)
262ca202504STobias Klauser SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC");
26323afeaefSGiuseppe Scrivano }
26423afeaefSGiuseppe Scrivano
26523afeaefSGiuseppe Scrivano /* Ensure the FD_CLOEXEC bit is set also with a resource limit in place. */
26623afeaefSGiuseppe Scrivano ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit));
26723afeaefSGiuseppe Scrivano rlimit.rlim_cur = 25;
26823afeaefSGiuseppe Scrivano ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlimit));
26923afeaefSGiuseppe Scrivano
27023afeaefSGiuseppe Scrivano /* Set close-on-exec for two ranges: [0-50] and [75-100]. */
27123afeaefSGiuseppe Scrivano ret = sys_close_range(open_fds[0], open_fds[50], CLOSE_RANGE_CLOEXEC);
27223afeaefSGiuseppe Scrivano ASSERT_EQ(0, ret);
27323afeaefSGiuseppe Scrivano ret = sys_close_range(open_fds[75], open_fds[100], CLOSE_RANGE_CLOEXEC);
27423afeaefSGiuseppe Scrivano ASSERT_EQ(0, ret);
27523afeaefSGiuseppe Scrivano
27623afeaefSGiuseppe Scrivano for (i = 0; i <= 50; i++) {
27723afeaefSGiuseppe Scrivano int flags = fcntl(open_fds[i], F_GETFD);
27823afeaefSGiuseppe Scrivano
27923afeaefSGiuseppe Scrivano EXPECT_GT(flags, -1);
28023afeaefSGiuseppe Scrivano EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
28123afeaefSGiuseppe Scrivano }
28223afeaefSGiuseppe Scrivano
28323afeaefSGiuseppe Scrivano for (i = 51; i <= 74; i++) {
28423afeaefSGiuseppe Scrivano int flags = fcntl(open_fds[i], F_GETFD);
28523afeaefSGiuseppe Scrivano
28623afeaefSGiuseppe Scrivano EXPECT_GT(flags, -1);
28723afeaefSGiuseppe Scrivano EXPECT_EQ(flags & FD_CLOEXEC, 0);
28823afeaefSGiuseppe Scrivano }
28923afeaefSGiuseppe Scrivano
29023afeaefSGiuseppe Scrivano for (i = 75; i <= 100; i++) {
29123afeaefSGiuseppe Scrivano int flags = fcntl(open_fds[i], F_GETFD);
29223afeaefSGiuseppe Scrivano
29323afeaefSGiuseppe Scrivano EXPECT_GT(flags, -1);
29423afeaefSGiuseppe Scrivano EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
29523afeaefSGiuseppe Scrivano }
29623afeaefSGiuseppe Scrivano
29723afeaefSGiuseppe Scrivano /* Test a common pattern. */
29823afeaefSGiuseppe Scrivano ret = sys_close_range(3, UINT_MAX, CLOSE_RANGE_CLOEXEC);
29923afeaefSGiuseppe Scrivano for (i = 0; i <= 100; i++) {
30023afeaefSGiuseppe Scrivano int flags = fcntl(open_fds[i], F_GETFD);
30123afeaefSGiuseppe Scrivano
30223afeaefSGiuseppe Scrivano EXPECT_GT(flags, -1);
30323afeaefSGiuseppe Scrivano EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
30423afeaefSGiuseppe Scrivano }
30523afeaefSGiuseppe Scrivano }
30623afeaefSGiuseppe Scrivano
TEST(close_range_cloexec_unshare)307fe325c3fSChristian Brauner TEST(close_range_cloexec_unshare)
308fe325c3fSChristian Brauner {
309fe325c3fSChristian Brauner int i, ret;
310fe325c3fSChristian Brauner int open_fds[101];
311fe325c3fSChristian Brauner struct rlimit rlimit;
312fe325c3fSChristian Brauner
313fe325c3fSChristian Brauner for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
314fe325c3fSChristian Brauner int fd;
315fe325c3fSChristian Brauner
316fe325c3fSChristian Brauner fd = open("/dev/null", O_RDONLY);
317fe325c3fSChristian Brauner ASSERT_GE(fd, 0) {
318fe325c3fSChristian Brauner if (errno == ENOENT)
319fe325c3fSChristian Brauner SKIP(return, "Skipping test since /dev/null does not exist");
320fe325c3fSChristian Brauner }
321fe325c3fSChristian Brauner
322fe325c3fSChristian Brauner open_fds[i] = fd;
323fe325c3fSChristian Brauner }
324fe325c3fSChristian Brauner
325fe325c3fSChristian Brauner ret = sys_close_range(1000, 1000, CLOSE_RANGE_CLOEXEC);
326fe325c3fSChristian Brauner if (ret < 0) {
327fe325c3fSChristian Brauner if (errno == ENOSYS)
328fe325c3fSChristian Brauner SKIP(return, "close_range() syscall not supported");
329fe325c3fSChristian Brauner if (errno == EINVAL)
330fe325c3fSChristian Brauner SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC");
331fe325c3fSChristian Brauner }
332fe325c3fSChristian Brauner
333fe325c3fSChristian Brauner /* Ensure the FD_CLOEXEC bit is set also with a resource limit in place. */
334fe325c3fSChristian Brauner ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit));
335fe325c3fSChristian Brauner rlimit.rlim_cur = 25;
336fe325c3fSChristian Brauner ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlimit));
337fe325c3fSChristian Brauner
338fe325c3fSChristian Brauner /* Set close-on-exec for two ranges: [0-50] and [75-100]. */
339fe325c3fSChristian Brauner ret = sys_close_range(open_fds[0], open_fds[50],
340fe325c3fSChristian Brauner CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
341fe325c3fSChristian Brauner ASSERT_EQ(0, ret);
342fe325c3fSChristian Brauner ret = sys_close_range(open_fds[75], open_fds[100],
343fe325c3fSChristian Brauner CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
344fe325c3fSChristian Brauner ASSERT_EQ(0, ret);
345fe325c3fSChristian Brauner
346fe325c3fSChristian Brauner for (i = 0; i <= 50; i++) {
347fe325c3fSChristian Brauner int flags = fcntl(open_fds[i], F_GETFD);
348fe325c3fSChristian Brauner
349fe325c3fSChristian Brauner EXPECT_GT(flags, -1);
350fe325c3fSChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
351fe325c3fSChristian Brauner }
352fe325c3fSChristian Brauner
353fe325c3fSChristian Brauner for (i = 51; i <= 74; i++) {
354fe325c3fSChristian Brauner int flags = fcntl(open_fds[i], F_GETFD);
355fe325c3fSChristian Brauner
356fe325c3fSChristian Brauner EXPECT_GT(flags, -1);
357fe325c3fSChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, 0);
358fe325c3fSChristian Brauner }
359fe325c3fSChristian Brauner
360fe325c3fSChristian Brauner for (i = 75; i <= 100; i++) {
361fe325c3fSChristian Brauner int flags = fcntl(open_fds[i], F_GETFD);
362fe325c3fSChristian Brauner
363fe325c3fSChristian Brauner EXPECT_GT(flags, -1);
364fe325c3fSChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
365fe325c3fSChristian Brauner }
366fe325c3fSChristian Brauner
367fe325c3fSChristian Brauner /* Test a common pattern. */
368fe325c3fSChristian Brauner ret = sys_close_range(3, UINT_MAX,
369fe325c3fSChristian Brauner CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
370fe325c3fSChristian Brauner for (i = 0; i <= 100; i++) {
371fe325c3fSChristian Brauner int flags = fcntl(open_fds[i], F_GETFD);
372fe325c3fSChristian Brauner
373fe325c3fSChristian Brauner EXPECT_GT(flags, -1);
374fe325c3fSChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
375fe325c3fSChristian Brauner }
376fe325c3fSChristian Brauner }
37723afeaefSGiuseppe Scrivano
3786abc20f8SChristian Brauner /*
3796abc20f8SChristian Brauner * Regression test for [email protected]
3806abc20f8SChristian Brauner */
TEST(close_range_cloexec_syzbot)3816abc20f8SChristian Brauner TEST(close_range_cloexec_syzbot)
3826abc20f8SChristian Brauner {
3834810ce7cSChristian Brauner int fd1, fd2, fd3, fd4, flags, ret, status;
3846abc20f8SChristian Brauner pid_t pid;
3856abc20f8SChristian Brauner struct __clone_args args = {
3866abc20f8SChristian Brauner .flags = CLONE_FILES,
3876abc20f8SChristian Brauner .exit_signal = SIGCHLD,
3886abc20f8SChristian Brauner };
3896abc20f8SChristian Brauner
3906abc20f8SChristian Brauner /* Create a huge gap in the fd table. */
3916abc20f8SChristian Brauner fd1 = open("/dev/null", O_RDWR);
3926abc20f8SChristian Brauner EXPECT_GT(fd1, 0);
3936abc20f8SChristian Brauner
3946abc20f8SChristian Brauner fd2 = dup2(fd1, 1000);
3956abc20f8SChristian Brauner EXPECT_GT(fd2, 0);
3966abc20f8SChristian Brauner
3974810ce7cSChristian Brauner flags = fcntl(fd1, F_DUPFD_QUERY, fd2);
3984810ce7cSChristian Brauner if (flags < 0) {
3994810ce7cSChristian Brauner EXPECT_EQ(errno, EINVAL);
4004810ce7cSChristian Brauner } else {
4014810ce7cSChristian Brauner EXPECT_EQ(flags, 1);
4024810ce7cSChristian Brauner }
4034810ce7cSChristian Brauner
4046abc20f8SChristian Brauner pid = sys_clone3(&args, sizeof(args));
4056abc20f8SChristian Brauner ASSERT_GE(pid, 0);
4066abc20f8SChristian Brauner
4076abc20f8SChristian Brauner if (pid == 0) {
4086abc20f8SChristian Brauner ret = sys_close_range(3, ~0U, CLOSE_RANGE_CLOEXEC);
4096abc20f8SChristian Brauner if (ret)
4106abc20f8SChristian Brauner exit(EXIT_FAILURE);
4116abc20f8SChristian Brauner
4126abc20f8SChristian Brauner /*
4136abc20f8SChristian Brauner * We now have a private file descriptor table and all
4146abc20f8SChristian Brauner * our open fds should still be open but made
4156abc20f8SChristian Brauner * close-on-exec.
4166abc20f8SChristian Brauner */
4176abc20f8SChristian Brauner flags = fcntl(fd1, F_GETFD);
4186abc20f8SChristian Brauner EXPECT_GT(flags, -1);
4196abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
4206abc20f8SChristian Brauner
4216abc20f8SChristian Brauner flags = fcntl(fd2, F_GETFD);
4226abc20f8SChristian Brauner EXPECT_GT(flags, -1);
4236abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
4246abc20f8SChristian Brauner
4256abc20f8SChristian Brauner fd3 = dup2(fd1, 42);
4266abc20f8SChristian Brauner EXPECT_GT(fd3, 0);
4276abc20f8SChristian Brauner
4284810ce7cSChristian Brauner flags = fcntl(fd1, F_DUPFD_QUERY, fd3);
4294810ce7cSChristian Brauner if (flags < 0) {
4304810ce7cSChristian Brauner EXPECT_EQ(errno, EINVAL);
4314810ce7cSChristian Brauner } else {
4324810ce7cSChristian Brauner EXPECT_EQ(flags, 1);
4334810ce7cSChristian Brauner }
4344810ce7cSChristian Brauner
4354810ce7cSChristian Brauner
4364810ce7cSChristian Brauner
4376abc20f8SChristian Brauner /*
4386abc20f8SChristian Brauner * Duplicating the file descriptor must remove the
4396abc20f8SChristian Brauner * FD_CLOEXEC flag.
4406abc20f8SChristian Brauner */
4416abc20f8SChristian Brauner flags = fcntl(fd3, F_GETFD);
4426abc20f8SChristian Brauner EXPECT_GT(flags, -1);
4436abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, 0);
4446abc20f8SChristian Brauner
4456abc20f8SChristian Brauner exit(EXIT_SUCCESS);
4466abc20f8SChristian Brauner }
4476abc20f8SChristian Brauner
4486abc20f8SChristian Brauner EXPECT_EQ(waitpid(pid, &status, 0), pid);
4496abc20f8SChristian Brauner EXPECT_EQ(true, WIFEXITED(status));
4506abc20f8SChristian Brauner EXPECT_EQ(0, WEXITSTATUS(status));
4516abc20f8SChristian Brauner
4526abc20f8SChristian Brauner /*
4536abc20f8SChristian Brauner * We had a shared file descriptor table before along with requesting
4546abc20f8SChristian Brauner * close-on-exec so the original fds must not be close-on-exec.
4556abc20f8SChristian Brauner */
4566abc20f8SChristian Brauner flags = fcntl(fd1, F_GETFD);
4576abc20f8SChristian Brauner EXPECT_GT(flags, -1);
4586abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
4596abc20f8SChristian Brauner
4606abc20f8SChristian Brauner flags = fcntl(fd2, F_GETFD);
4616abc20f8SChristian Brauner EXPECT_GT(flags, -1);
4626abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
4636abc20f8SChristian Brauner
4646abc20f8SChristian Brauner fd3 = dup2(fd1, 42);
4656abc20f8SChristian Brauner EXPECT_GT(fd3, 0);
4666abc20f8SChristian Brauner
4674810ce7cSChristian Brauner flags = fcntl(fd1, F_DUPFD_QUERY, fd3);
4684810ce7cSChristian Brauner if (flags < 0) {
4694810ce7cSChristian Brauner EXPECT_EQ(errno, EINVAL);
4704810ce7cSChristian Brauner } else {
4714810ce7cSChristian Brauner EXPECT_EQ(flags, 1);
4724810ce7cSChristian Brauner }
4734810ce7cSChristian Brauner
4744810ce7cSChristian Brauner fd4 = open("/dev/null", O_RDWR);
4754810ce7cSChristian Brauner EXPECT_GT(fd4, 0);
4764810ce7cSChristian Brauner
4774810ce7cSChristian Brauner /* Same inode, different file pointers. */
4784810ce7cSChristian Brauner flags = fcntl(fd1, F_DUPFD_QUERY, fd4);
4794810ce7cSChristian Brauner if (flags < 0) {
4804810ce7cSChristian Brauner EXPECT_EQ(errno, EINVAL);
4814810ce7cSChristian Brauner } else {
4824810ce7cSChristian Brauner EXPECT_EQ(flags, 0);
4834810ce7cSChristian Brauner }
4844810ce7cSChristian Brauner
4856abc20f8SChristian Brauner flags = fcntl(fd3, F_GETFD);
4866abc20f8SChristian Brauner EXPECT_GT(flags, -1);
4876abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, 0);
4886abc20f8SChristian Brauner
4896abc20f8SChristian Brauner EXPECT_EQ(close(fd1), 0);
4906abc20f8SChristian Brauner EXPECT_EQ(close(fd2), 0);
4916abc20f8SChristian Brauner EXPECT_EQ(close(fd3), 0);
4924810ce7cSChristian Brauner EXPECT_EQ(close(fd4), 0);
4936abc20f8SChristian Brauner }
4946abc20f8SChristian Brauner
4956abc20f8SChristian Brauner /*
4966abc20f8SChristian Brauner * Regression test for [email protected]
4976abc20f8SChristian Brauner */
TEST(close_range_cloexec_unshare_syzbot)4986abc20f8SChristian Brauner TEST(close_range_cloexec_unshare_syzbot)
4996abc20f8SChristian Brauner {
5006abc20f8SChristian Brauner int i, fd1, fd2, fd3, flags, ret, status;
5016abc20f8SChristian Brauner pid_t pid;
5026abc20f8SChristian Brauner struct __clone_args args = {
5036abc20f8SChristian Brauner .flags = CLONE_FILES,
5046abc20f8SChristian Brauner .exit_signal = SIGCHLD,
5056abc20f8SChristian Brauner };
5066abc20f8SChristian Brauner
5076abc20f8SChristian Brauner /*
5086abc20f8SChristian Brauner * Create a huge gap in the fd table. When we now call
5096abc20f8SChristian Brauner * CLOSE_RANGE_UNSHARE with a shared fd table and and with ~0U as upper
5106abc20f8SChristian Brauner * bound the kernel will only copy up to fd1 file descriptors into the
5116abc20f8SChristian Brauner * new fd table. If the kernel is buggy and doesn't handle
5126abc20f8SChristian Brauner * CLOSE_RANGE_CLOEXEC correctly it will not have copied all file
5136abc20f8SChristian Brauner * descriptors and we will oops!
5146abc20f8SChristian Brauner *
5156abc20f8SChristian Brauner * On a buggy kernel this should immediately oops. But let's loop just
5166abc20f8SChristian Brauner * to be sure.
5176abc20f8SChristian Brauner */
5186abc20f8SChristian Brauner fd1 = open("/dev/null", O_RDWR);
5196abc20f8SChristian Brauner EXPECT_GT(fd1, 0);
5206abc20f8SChristian Brauner
5216abc20f8SChristian Brauner fd2 = dup2(fd1, 1000);
5226abc20f8SChristian Brauner EXPECT_GT(fd2, 0);
5236abc20f8SChristian Brauner
5246abc20f8SChristian Brauner for (i = 0; i < 100; i++) {
5256abc20f8SChristian Brauner
5266abc20f8SChristian Brauner pid = sys_clone3(&args, sizeof(args));
5276abc20f8SChristian Brauner ASSERT_GE(pid, 0);
5286abc20f8SChristian Brauner
5296abc20f8SChristian Brauner if (pid == 0) {
5306abc20f8SChristian Brauner ret = sys_close_range(3, ~0U, CLOSE_RANGE_UNSHARE |
5316abc20f8SChristian Brauner CLOSE_RANGE_CLOEXEC);
5326abc20f8SChristian Brauner if (ret)
5336abc20f8SChristian Brauner exit(EXIT_FAILURE);
5346abc20f8SChristian Brauner
5356abc20f8SChristian Brauner /*
5366abc20f8SChristian Brauner * We now have a private file descriptor table and all
5376abc20f8SChristian Brauner * our open fds should still be open but made
5386abc20f8SChristian Brauner * close-on-exec.
5396abc20f8SChristian Brauner */
5406abc20f8SChristian Brauner flags = fcntl(fd1, F_GETFD);
5416abc20f8SChristian Brauner EXPECT_GT(flags, -1);
5426abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
5436abc20f8SChristian Brauner
5446abc20f8SChristian Brauner flags = fcntl(fd2, F_GETFD);
5456abc20f8SChristian Brauner EXPECT_GT(flags, -1);
5466abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
5476abc20f8SChristian Brauner
5486abc20f8SChristian Brauner fd3 = dup2(fd1, 42);
5496abc20f8SChristian Brauner EXPECT_GT(fd3, 0);
5506abc20f8SChristian Brauner
5516abc20f8SChristian Brauner /*
5526abc20f8SChristian Brauner * Duplicating the file descriptor must remove the
5536abc20f8SChristian Brauner * FD_CLOEXEC flag.
5546abc20f8SChristian Brauner */
5556abc20f8SChristian Brauner flags = fcntl(fd3, F_GETFD);
5566abc20f8SChristian Brauner EXPECT_GT(flags, -1);
5576abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, 0);
5586abc20f8SChristian Brauner
5596abc20f8SChristian Brauner EXPECT_EQ(close(fd1), 0);
5606abc20f8SChristian Brauner EXPECT_EQ(close(fd2), 0);
5616abc20f8SChristian Brauner EXPECT_EQ(close(fd3), 0);
5626abc20f8SChristian Brauner
5636abc20f8SChristian Brauner exit(EXIT_SUCCESS);
5646abc20f8SChristian Brauner }
5656abc20f8SChristian Brauner
5666abc20f8SChristian Brauner EXPECT_EQ(waitpid(pid, &status, 0), pid);
5676abc20f8SChristian Brauner EXPECT_EQ(true, WIFEXITED(status));
5686abc20f8SChristian Brauner EXPECT_EQ(0, WEXITSTATUS(status));
5696abc20f8SChristian Brauner }
5706abc20f8SChristian Brauner
5716abc20f8SChristian Brauner /*
5726abc20f8SChristian Brauner * We created a private file descriptor table before along with
5736abc20f8SChristian Brauner * requesting close-on-exec so the original fds must not be
5746abc20f8SChristian Brauner * close-on-exec.
5756abc20f8SChristian Brauner */
5766abc20f8SChristian Brauner flags = fcntl(fd1, F_GETFD);
5776abc20f8SChristian Brauner EXPECT_GT(flags, -1);
5786abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, 0);
5796abc20f8SChristian Brauner
5806abc20f8SChristian Brauner flags = fcntl(fd2, F_GETFD);
5816abc20f8SChristian Brauner EXPECT_GT(flags, -1);
5826abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, 0);
5836abc20f8SChristian Brauner
5846abc20f8SChristian Brauner fd3 = dup2(fd1, 42);
5856abc20f8SChristian Brauner EXPECT_GT(fd3, 0);
5866abc20f8SChristian Brauner
5876abc20f8SChristian Brauner flags = fcntl(fd3, F_GETFD);
5886abc20f8SChristian Brauner EXPECT_GT(flags, -1);
5896abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, 0);
5906abc20f8SChristian Brauner
5916abc20f8SChristian Brauner EXPECT_EQ(close(fd1), 0);
5926abc20f8SChristian Brauner EXPECT_EQ(close(fd2), 0);
5936abc20f8SChristian Brauner EXPECT_EQ(close(fd3), 0);
5946abc20f8SChristian Brauner }
5956abc20f8SChristian Brauner
TEST(close_range_bitmap_corruption)5969a2fa147SAl Viro TEST(close_range_bitmap_corruption)
5979a2fa147SAl Viro {
5989a2fa147SAl Viro pid_t pid;
5999a2fa147SAl Viro int status;
6009a2fa147SAl Viro struct __clone_args args = {
6019a2fa147SAl Viro .flags = CLONE_FILES,
6029a2fa147SAl Viro .exit_signal = SIGCHLD,
6039a2fa147SAl Viro };
6049a2fa147SAl Viro
6059a2fa147SAl Viro /* get the first 128 descriptors open */
6069a2fa147SAl Viro for (int i = 2; i < 128; i++)
6079a2fa147SAl Viro EXPECT_GE(dup2(0, i), 0);
6089a2fa147SAl Viro
6099a2fa147SAl Viro /* get descriptor table shared */
6109a2fa147SAl Viro pid = sys_clone3(&args, sizeof(args));
6119a2fa147SAl Viro ASSERT_GE(pid, 0);
6129a2fa147SAl Viro
6139a2fa147SAl Viro if (pid == 0) {
6149a2fa147SAl Viro /* unshare and truncate descriptor table down to 64 */
6159a2fa147SAl Viro if (sys_close_range(64, ~0U, CLOSE_RANGE_UNSHARE))
6169a2fa147SAl Viro exit(EXIT_FAILURE);
6179a2fa147SAl Viro
6189a2fa147SAl Viro ASSERT_EQ(fcntl(64, F_GETFD), -1);
6199a2fa147SAl Viro /* ... and verify that the range 64..127 is not
6209a2fa147SAl Viro stuck "fully used" according to secondary bitmap */
6219a2fa147SAl Viro EXPECT_EQ(dup(0), 64)
6229a2fa147SAl Viro exit(EXIT_FAILURE);
6239a2fa147SAl Viro exit(EXIT_SUCCESS);
6249a2fa147SAl Viro }
6259a2fa147SAl Viro
6269a2fa147SAl Viro EXPECT_EQ(waitpid(pid, &status, 0), pid);
6279a2fa147SAl Viro EXPECT_EQ(true, WIFEXITED(status));
6289a2fa147SAl Viro EXPECT_EQ(0, WEXITSTATUS(status));
6299a2fa147SAl Viro }
6309a2fa147SAl Viro
TEST(fcntl_created)631*d0fe8920SChristian Brauner TEST(fcntl_created)
632*d0fe8920SChristian Brauner {
633*d0fe8920SChristian Brauner for (int i = 0; i < 101; i++) {
634*d0fe8920SChristian Brauner int fd;
635*d0fe8920SChristian Brauner char path[PATH_MAX];
636*d0fe8920SChristian Brauner
637*d0fe8920SChristian Brauner fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
638*d0fe8920SChristian Brauner ASSERT_GE(fd, 0) {
639*d0fe8920SChristian Brauner if (errno == ENOENT)
640*d0fe8920SChristian Brauner SKIP(return,
641*d0fe8920SChristian Brauner "Skipping test since /dev/null does not exist");
642*d0fe8920SChristian Brauner }
643*d0fe8920SChristian Brauner
644*d0fe8920SChristian Brauner /* We didn't create "/dev/null". */
645*d0fe8920SChristian Brauner EXPECT_EQ(fcntl(fd, F_CREATED_QUERY, 0), 0);
646*d0fe8920SChristian Brauner close(fd);
647*d0fe8920SChristian Brauner
648*d0fe8920SChristian Brauner sprintf(path, "aaaa_%d", i);
649*d0fe8920SChristian Brauner fd = open(path, O_CREAT | O_RDONLY | O_CLOEXEC, 0600);
650*d0fe8920SChristian Brauner ASSERT_GE(fd, 0);
651*d0fe8920SChristian Brauner
652*d0fe8920SChristian Brauner /* We created "aaaa_%d". */
653*d0fe8920SChristian Brauner EXPECT_EQ(fcntl(fd, F_CREATED_QUERY, 0), 1);
654*d0fe8920SChristian Brauner close(fd);
655*d0fe8920SChristian Brauner
656*d0fe8920SChristian Brauner fd = open(path, O_RDONLY | O_CLOEXEC);
657*d0fe8920SChristian Brauner ASSERT_GE(fd, 0);
658*d0fe8920SChristian Brauner
659*d0fe8920SChristian Brauner /* We're opening it again, so no positive creation check. */
660*d0fe8920SChristian Brauner EXPECT_EQ(fcntl(fd, F_CREATED_QUERY, 0), 0);
661*d0fe8920SChristian Brauner close(fd);
662*d0fe8920SChristian Brauner unlink(path);
663*d0fe8920SChristian Brauner }
664*d0fe8920SChristian Brauner }
665*d0fe8920SChristian Brauner
6662c5db60eSChristian Brauner TEST_HARNESS_MAIN
667