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>
152c5db60eSChristian Brauner
162c5db60eSChristian Brauner #include "../kselftest_harness.h"
17a5161eeeSChristian Brauner #include "../clone3/clone3_selftests.h"
182c5db60eSChristian Brauner
192c5db60eSChristian Brauner #ifndef __NR_close_range
20ae78ba8dSChristian Brauner #if defined __alpha__
21ae78ba8dSChristian Brauner #define __NR_close_range 546
22ae78ba8dSChristian Brauner #elif defined _MIPS_SIM
23ae78ba8dSChristian Brauner #if _MIPS_SIM == _MIPS_SIM_ABI32 /* o32 */
24ae78ba8dSChristian Brauner #define __NR_close_range (436 + 4000)
25ae78ba8dSChristian Brauner #endif
26ae78ba8dSChristian Brauner #if _MIPS_SIM == _MIPS_SIM_NABI32 /* n32 */
27ae78ba8dSChristian Brauner #define __NR_close_range (436 + 6000)
28ae78ba8dSChristian Brauner #endif
29ae78ba8dSChristian Brauner #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */
30ae78ba8dSChristian Brauner #define __NR_close_range (436 + 5000)
31ae78ba8dSChristian Brauner #endif
32ae78ba8dSChristian Brauner #elif defined __ia64__
33ae78ba8dSChristian Brauner #define __NR_close_range (436 + 1024)
34ae78ba8dSChristian Brauner #else
35ae78ba8dSChristian Brauner #define __NR_close_range 436
36ae78ba8dSChristian Brauner #endif
372c5db60eSChristian Brauner #endif
382c5db60eSChristian Brauner
39a5161eeeSChristian Brauner #ifndef CLOSE_RANGE_UNSHARE
40a5161eeeSChristian Brauner #define CLOSE_RANGE_UNSHARE (1U << 1)
41a5161eeeSChristian Brauner #endif
42a5161eeeSChristian Brauner
4323afeaefSGiuseppe Scrivano #ifndef CLOSE_RANGE_CLOEXEC
4423afeaefSGiuseppe Scrivano #define CLOSE_RANGE_CLOEXEC (1U << 2)
4523afeaefSGiuseppe Scrivano #endif
4623afeaefSGiuseppe Scrivano
sys_close_range(unsigned int fd,unsigned int max_fd,unsigned int flags)472c5db60eSChristian Brauner static inline int sys_close_range(unsigned int fd, unsigned int max_fd,
482c5db60eSChristian Brauner unsigned int flags)
492c5db60eSChristian Brauner {
502c5db60eSChristian Brauner return syscall(__NR_close_range, fd, max_fd, flags);
512c5db60eSChristian Brauner }
522c5db60eSChristian Brauner
TEST(core_close_range)53*f35dcaa0SShuah Khan TEST(core_close_range)
542c5db60eSChristian Brauner {
552c5db60eSChristian Brauner int i, ret;
562c5db60eSChristian Brauner int open_fds[101];
572c5db60eSChristian Brauner
582c5db60eSChristian Brauner for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
592c5db60eSChristian Brauner int fd;
602c5db60eSChristian Brauner
612c5db60eSChristian Brauner fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
622c5db60eSChristian Brauner ASSERT_GE(fd, 0) {
632c5db60eSChristian Brauner if (errno == ENOENT)
641d44d0ddSTommi Rantala SKIP(return, "Skipping test since /dev/null does not exist");
652c5db60eSChristian Brauner }
662c5db60eSChristian Brauner
672c5db60eSChristian Brauner open_fds[i] = fd;
682c5db60eSChristian Brauner }
692c5db60eSChristian Brauner
702c5db60eSChristian Brauner EXPECT_EQ(-1, sys_close_range(open_fds[0], open_fds[100], -1)) {
712c5db60eSChristian Brauner if (errno == ENOSYS)
721d44d0ddSTommi Rantala SKIP(return, "close_range() syscall not supported");
732c5db60eSChristian Brauner }
742c5db60eSChristian Brauner
752c5db60eSChristian Brauner EXPECT_EQ(0, sys_close_range(open_fds[0], open_fds[50], 0));
762c5db60eSChristian Brauner
772c5db60eSChristian Brauner for (i = 0; i <= 50; i++)
782c5db60eSChristian Brauner EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
792c5db60eSChristian Brauner
802c5db60eSChristian Brauner for (i = 51; i <= 100; i++)
812c5db60eSChristian Brauner EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
822c5db60eSChristian Brauner
832c5db60eSChristian Brauner /* create a couple of gaps */
842c5db60eSChristian Brauner close(57);
852c5db60eSChristian Brauner close(78);
862c5db60eSChristian Brauner close(81);
872c5db60eSChristian Brauner close(82);
882c5db60eSChristian Brauner close(84);
892c5db60eSChristian Brauner close(90);
902c5db60eSChristian Brauner
912c5db60eSChristian Brauner EXPECT_EQ(0, sys_close_range(open_fds[51], open_fds[92], 0));
922c5db60eSChristian Brauner
932c5db60eSChristian Brauner for (i = 51; i <= 92; i++)
942c5db60eSChristian Brauner EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
952c5db60eSChristian Brauner
962c5db60eSChristian Brauner for (i = 93; i <= 100; i++)
972c5db60eSChristian Brauner EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
982c5db60eSChristian Brauner
992c5db60eSChristian Brauner /* test that the kernel caps and still closes all fds */
1002c5db60eSChristian Brauner EXPECT_EQ(0, sys_close_range(open_fds[93], open_fds[99], 0));
1012c5db60eSChristian Brauner
1022c5db60eSChristian Brauner for (i = 93; i <= 99; i++)
1032c5db60eSChristian Brauner EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
1042c5db60eSChristian Brauner
1052c5db60eSChristian Brauner EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
1062c5db60eSChristian Brauner
1072c5db60eSChristian Brauner EXPECT_EQ(0, sys_close_range(open_fds[100], open_fds[100], 0));
1082c5db60eSChristian Brauner
1092c5db60eSChristian Brauner EXPECT_EQ(-1, fcntl(open_fds[100], F_GETFL));
1102c5db60eSChristian Brauner }
1112c5db60eSChristian Brauner
TEST(close_range_unshare)112a5161eeeSChristian Brauner TEST(close_range_unshare)
113a5161eeeSChristian Brauner {
114a5161eeeSChristian Brauner int i, ret, status;
115a5161eeeSChristian Brauner pid_t pid;
116a5161eeeSChristian Brauner int open_fds[101];
117ca202504STobias Klauser struct __clone_args args = {
118a5161eeeSChristian Brauner .flags = CLONE_FILES,
119a5161eeeSChristian Brauner .exit_signal = SIGCHLD,
120a5161eeeSChristian Brauner };
121a5161eeeSChristian Brauner
122a5161eeeSChristian Brauner for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
123a5161eeeSChristian Brauner int fd;
124a5161eeeSChristian Brauner
125a5161eeeSChristian Brauner fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
126a5161eeeSChristian Brauner ASSERT_GE(fd, 0) {
127a5161eeeSChristian Brauner if (errno == ENOENT)
1281d44d0ddSTommi Rantala SKIP(return, "Skipping test since /dev/null does not exist");
129a5161eeeSChristian Brauner }
130a5161eeeSChristian Brauner
131a5161eeeSChristian Brauner open_fds[i] = fd;
132a5161eeeSChristian Brauner }
133a5161eeeSChristian Brauner
134a5161eeeSChristian Brauner pid = sys_clone3(&args, sizeof(args));
135a5161eeeSChristian Brauner ASSERT_GE(pid, 0);
136a5161eeeSChristian Brauner
137a5161eeeSChristian Brauner if (pid == 0) {
138a5161eeeSChristian Brauner ret = sys_close_range(open_fds[0], open_fds[50],
139a5161eeeSChristian Brauner CLOSE_RANGE_UNSHARE);
140a5161eeeSChristian Brauner if (ret)
141a5161eeeSChristian Brauner exit(EXIT_FAILURE);
142a5161eeeSChristian Brauner
143a5161eeeSChristian Brauner for (i = 0; i <= 50; i++)
144a5161eeeSChristian Brauner if (fcntl(open_fds[i], F_GETFL) != -1)
145a5161eeeSChristian Brauner exit(EXIT_FAILURE);
146a5161eeeSChristian Brauner
147a5161eeeSChristian Brauner for (i = 51; i <= 100; i++)
148a5161eeeSChristian Brauner if (fcntl(open_fds[i], F_GETFL) == -1)
149a5161eeeSChristian Brauner exit(EXIT_FAILURE);
150a5161eeeSChristian Brauner
151a5161eeeSChristian Brauner /* create a couple of gaps */
152a5161eeeSChristian Brauner close(57);
153a5161eeeSChristian Brauner close(78);
154a5161eeeSChristian Brauner close(81);
155a5161eeeSChristian Brauner close(82);
156a5161eeeSChristian Brauner close(84);
157a5161eeeSChristian Brauner close(90);
158a5161eeeSChristian Brauner
159a5161eeeSChristian Brauner ret = sys_close_range(open_fds[51], open_fds[92],
160a5161eeeSChristian Brauner CLOSE_RANGE_UNSHARE);
161a5161eeeSChristian Brauner if (ret)
162a5161eeeSChristian Brauner exit(EXIT_FAILURE);
163a5161eeeSChristian Brauner
164a5161eeeSChristian Brauner for (i = 51; i <= 92; i++)
165a5161eeeSChristian Brauner if (fcntl(open_fds[i], F_GETFL) != -1)
166a5161eeeSChristian Brauner exit(EXIT_FAILURE);
167a5161eeeSChristian Brauner
168a5161eeeSChristian Brauner for (i = 93; i <= 100; i++)
169a5161eeeSChristian Brauner if (fcntl(open_fds[i], F_GETFL) == -1)
170a5161eeeSChristian Brauner exit(EXIT_FAILURE);
171a5161eeeSChristian Brauner
172a5161eeeSChristian Brauner /* test that the kernel caps and still closes all fds */
173a5161eeeSChristian Brauner ret = sys_close_range(open_fds[93], open_fds[99],
174a5161eeeSChristian Brauner CLOSE_RANGE_UNSHARE);
175a5161eeeSChristian Brauner if (ret)
176a5161eeeSChristian Brauner exit(EXIT_FAILURE);
177a5161eeeSChristian Brauner
178a5161eeeSChristian Brauner for (i = 93; i <= 99; i++)
179a5161eeeSChristian Brauner if (fcntl(open_fds[i], F_GETFL) != -1)
180a5161eeeSChristian Brauner exit(EXIT_FAILURE);
181a5161eeeSChristian Brauner
182a5161eeeSChristian Brauner if (fcntl(open_fds[100], F_GETFL) == -1)
183a5161eeeSChristian Brauner exit(EXIT_FAILURE);
184a5161eeeSChristian Brauner
185a5161eeeSChristian Brauner ret = sys_close_range(open_fds[100], open_fds[100],
186a5161eeeSChristian Brauner CLOSE_RANGE_UNSHARE);
187a5161eeeSChristian Brauner if (ret)
188a5161eeeSChristian Brauner exit(EXIT_FAILURE);
189a5161eeeSChristian Brauner
190a5161eeeSChristian Brauner if (fcntl(open_fds[100], F_GETFL) != -1)
191a5161eeeSChristian Brauner exit(EXIT_FAILURE);
192a5161eeeSChristian Brauner
193a5161eeeSChristian Brauner exit(EXIT_SUCCESS);
194a5161eeeSChristian Brauner }
195a5161eeeSChristian Brauner
196a5161eeeSChristian Brauner EXPECT_EQ(waitpid(pid, &status, 0), pid);
197a5161eeeSChristian Brauner EXPECT_EQ(true, WIFEXITED(status));
198a5161eeeSChristian Brauner EXPECT_EQ(0, WEXITSTATUS(status));
199a5161eeeSChristian Brauner }
200a5161eeeSChristian Brauner
TEST(close_range_unshare_capped)201a5161eeeSChristian Brauner TEST(close_range_unshare_capped)
202a5161eeeSChristian Brauner {
203a5161eeeSChristian Brauner int i, ret, status;
204a5161eeeSChristian Brauner pid_t pid;
205a5161eeeSChristian Brauner int open_fds[101];
206ca202504STobias Klauser struct __clone_args args = {
207a5161eeeSChristian Brauner .flags = CLONE_FILES,
208a5161eeeSChristian Brauner .exit_signal = SIGCHLD,
209a5161eeeSChristian Brauner };
210a5161eeeSChristian Brauner
211a5161eeeSChristian Brauner for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
212a5161eeeSChristian Brauner int fd;
213a5161eeeSChristian Brauner
214a5161eeeSChristian Brauner fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
215a5161eeeSChristian Brauner ASSERT_GE(fd, 0) {
216a5161eeeSChristian Brauner if (errno == ENOENT)
2171d44d0ddSTommi Rantala SKIP(return, "Skipping test since /dev/null does not exist");
218a5161eeeSChristian Brauner }
219a5161eeeSChristian Brauner
220a5161eeeSChristian Brauner open_fds[i] = fd;
221a5161eeeSChristian Brauner }
222a5161eeeSChristian Brauner
223a5161eeeSChristian Brauner pid = sys_clone3(&args, sizeof(args));
224a5161eeeSChristian Brauner ASSERT_GE(pid, 0);
225a5161eeeSChristian Brauner
226a5161eeeSChristian Brauner if (pid == 0) {
227a5161eeeSChristian Brauner ret = sys_close_range(open_fds[0], UINT_MAX,
228a5161eeeSChristian Brauner CLOSE_RANGE_UNSHARE);
229a5161eeeSChristian Brauner if (ret)
230a5161eeeSChristian Brauner exit(EXIT_FAILURE);
231a5161eeeSChristian Brauner
232a5161eeeSChristian Brauner for (i = 0; i <= 100; i++)
233a5161eeeSChristian Brauner if (fcntl(open_fds[i], F_GETFL) != -1)
234a5161eeeSChristian Brauner exit(EXIT_FAILURE);
235a5161eeeSChristian Brauner
236a5161eeeSChristian Brauner exit(EXIT_SUCCESS);
237a5161eeeSChristian Brauner }
238a5161eeeSChristian Brauner
239a5161eeeSChristian Brauner EXPECT_EQ(waitpid(pid, &status, 0), pid);
240a5161eeeSChristian Brauner EXPECT_EQ(true, WIFEXITED(status));
241a5161eeeSChristian Brauner EXPECT_EQ(0, WEXITSTATUS(status));
242a5161eeeSChristian Brauner }
243a5161eeeSChristian Brauner
TEST(close_range_cloexec)24423afeaefSGiuseppe Scrivano TEST(close_range_cloexec)
24523afeaefSGiuseppe Scrivano {
24623afeaefSGiuseppe Scrivano int i, ret;
24723afeaefSGiuseppe Scrivano int open_fds[101];
24823afeaefSGiuseppe Scrivano struct rlimit rlimit;
24923afeaefSGiuseppe Scrivano
25023afeaefSGiuseppe Scrivano for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
25123afeaefSGiuseppe Scrivano int fd;
25223afeaefSGiuseppe Scrivano
25323afeaefSGiuseppe Scrivano fd = open("/dev/null", O_RDONLY);
25423afeaefSGiuseppe Scrivano ASSERT_GE(fd, 0) {
25523afeaefSGiuseppe Scrivano if (errno == ENOENT)
256ca202504STobias Klauser SKIP(return, "Skipping test since /dev/null does not exist");
25723afeaefSGiuseppe Scrivano }
25823afeaefSGiuseppe Scrivano
25923afeaefSGiuseppe Scrivano open_fds[i] = fd;
26023afeaefSGiuseppe Scrivano }
26123afeaefSGiuseppe Scrivano
26223afeaefSGiuseppe Scrivano ret = sys_close_range(1000, 1000, CLOSE_RANGE_CLOEXEC);
26323afeaefSGiuseppe Scrivano if (ret < 0) {
26423afeaefSGiuseppe Scrivano if (errno == ENOSYS)
265ca202504STobias Klauser SKIP(return, "close_range() syscall not supported");
26623afeaefSGiuseppe Scrivano if (errno == EINVAL)
267ca202504STobias Klauser SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC");
26823afeaefSGiuseppe Scrivano }
26923afeaefSGiuseppe Scrivano
27023afeaefSGiuseppe Scrivano /* Ensure the FD_CLOEXEC bit is set also with a resource limit in place. */
27123afeaefSGiuseppe Scrivano ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit));
27223afeaefSGiuseppe Scrivano rlimit.rlim_cur = 25;
27323afeaefSGiuseppe Scrivano ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlimit));
27423afeaefSGiuseppe Scrivano
27523afeaefSGiuseppe Scrivano /* Set close-on-exec for two ranges: [0-50] and [75-100]. */
27623afeaefSGiuseppe Scrivano ret = sys_close_range(open_fds[0], open_fds[50], CLOSE_RANGE_CLOEXEC);
27723afeaefSGiuseppe Scrivano ASSERT_EQ(0, ret);
27823afeaefSGiuseppe Scrivano ret = sys_close_range(open_fds[75], open_fds[100], CLOSE_RANGE_CLOEXEC);
27923afeaefSGiuseppe Scrivano ASSERT_EQ(0, ret);
28023afeaefSGiuseppe Scrivano
28123afeaefSGiuseppe Scrivano for (i = 0; i <= 50; i++) {
28223afeaefSGiuseppe Scrivano int flags = fcntl(open_fds[i], F_GETFD);
28323afeaefSGiuseppe Scrivano
28423afeaefSGiuseppe Scrivano EXPECT_GT(flags, -1);
28523afeaefSGiuseppe Scrivano EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
28623afeaefSGiuseppe Scrivano }
28723afeaefSGiuseppe Scrivano
28823afeaefSGiuseppe Scrivano for (i = 51; i <= 74; i++) {
28923afeaefSGiuseppe Scrivano int flags = fcntl(open_fds[i], F_GETFD);
29023afeaefSGiuseppe Scrivano
29123afeaefSGiuseppe Scrivano EXPECT_GT(flags, -1);
29223afeaefSGiuseppe Scrivano EXPECT_EQ(flags & FD_CLOEXEC, 0);
29323afeaefSGiuseppe Scrivano }
29423afeaefSGiuseppe Scrivano
29523afeaefSGiuseppe Scrivano for (i = 75; i <= 100; i++) {
29623afeaefSGiuseppe Scrivano int flags = fcntl(open_fds[i], F_GETFD);
29723afeaefSGiuseppe Scrivano
29823afeaefSGiuseppe Scrivano EXPECT_GT(flags, -1);
29923afeaefSGiuseppe Scrivano EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
30023afeaefSGiuseppe Scrivano }
30123afeaefSGiuseppe Scrivano
30223afeaefSGiuseppe Scrivano /* Test a common pattern. */
30323afeaefSGiuseppe Scrivano ret = sys_close_range(3, UINT_MAX, CLOSE_RANGE_CLOEXEC);
30423afeaefSGiuseppe Scrivano for (i = 0; i <= 100; i++) {
30523afeaefSGiuseppe Scrivano int flags = fcntl(open_fds[i], F_GETFD);
30623afeaefSGiuseppe Scrivano
30723afeaefSGiuseppe Scrivano EXPECT_GT(flags, -1);
30823afeaefSGiuseppe Scrivano EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
30923afeaefSGiuseppe Scrivano }
31023afeaefSGiuseppe Scrivano }
31123afeaefSGiuseppe Scrivano
TEST(close_range_cloexec_unshare)312fe325c3fSChristian Brauner TEST(close_range_cloexec_unshare)
313fe325c3fSChristian Brauner {
314fe325c3fSChristian Brauner int i, ret;
315fe325c3fSChristian Brauner int open_fds[101];
316fe325c3fSChristian Brauner struct rlimit rlimit;
317fe325c3fSChristian Brauner
318fe325c3fSChristian Brauner for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
319fe325c3fSChristian Brauner int fd;
320fe325c3fSChristian Brauner
321fe325c3fSChristian Brauner fd = open("/dev/null", O_RDONLY);
322fe325c3fSChristian Brauner ASSERT_GE(fd, 0) {
323fe325c3fSChristian Brauner if (errno == ENOENT)
324fe325c3fSChristian Brauner SKIP(return, "Skipping test since /dev/null does not exist");
325fe325c3fSChristian Brauner }
326fe325c3fSChristian Brauner
327fe325c3fSChristian Brauner open_fds[i] = fd;
328fe325c3fSChristian Brauner }
329fe325c3fSChristian Brauner
330fe325c3fSChristian Brauner ret = sys_close_range(1000, 1000, CLOSE_RANGE_CLOEXEC);
331fe325c3fSChristian Brauner if (ret < 0) {
332fe325c3fSChristian Brauner if (errno == ENOSYS)
333fe325c3fSChristian Brauner SKIP(return, "close_range() syscall not supported");
334fe325c3fSChristian Brauner if (errno == EINVAL)
335fe325c3fSChristian Brauner SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC");
336fe325c3fSChristian Brauner }
337fe325c3fSChristian Brauner
338fe325c3fSChristian Brauner /* Ensure the FD_CLOEXEC bit is set also with a resource limit in place. */
339fe325c3fSChristian Brauner ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit));
340fe325c3fSChristian Brauner rlimit.rlim_cur = 25;
341fe325c3fSChristian Brauner ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlimit));
342fe325c3fSChristian Brauner
343fe325c3fSChristian Brauner /* Set close-on-exec for two ranges: [0-50] and [75-100]. */
344fe325c3fSChristian Brauner ret = sys_close_range(open_fds[0], open_fds[50],
345fe325c3fSChristian Brauner CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
346fe325c3fSChristian Brauner ASSERT_EQ(0, ret);
347fe325c3fSChristian Brauner ret = sys_close_range(open_fds[75], open_fds[100],
348fe325c3fSChristian Brauner CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
349fe325c3fSChristian Brauner ASSERT_EQ(0, ret);
350fe325c3fSChristian Brauner
351fe325c3fSChristian Brauner for (i = 0; i <= 50; i++) {
352fe325c3fSChristian Brauner int flags = fcntl(open_fds[i], F_GETFD);
353fe325c3fSChristian Brauner
354fe325c3fSChristian Brauner EXPECT_GT(flags, -1);
355fe325c3fSChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
356fe325c3fSChristian Brauner }
357fe325c3fSChristian Brauner
358fe325c3fSChristian Brauner for (i = 51; i <= 74; i++) {
359fe325c3fSChristian Brauner int flags = fcntl(open_fds[i], F_GETFD);
360fe325c3fSChristian Brauner
361fe325c3fSChristian Brauner EXPECT_GT(flags, -1);
362fe325c3fSChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, 0);
363fe325c3fSChristian Brauner }
364fe325c3fSChristian Brauner
365fe325c3fSChristian Brauner for (i = 75; i <= 100; i++) {
366fe325c3fSChristian Brauner int flags = fcntl(open_fds[i], F_GETFD);
367fe325c3fSChristian Brauner
368fe325c3fSChristian Brauner EXPECT_GT(flags, -1);
369fe325c3fSChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
370fe325c3fSChristian Brauner }
371fe325c3fSChristian Brauner
372fe325c3fSChristian Brauner /* Test a common pattern. */
373fe325c3fSChristian Brauner ret = sys_close_range(3, UINT_MAX,
374fe325c3fSChristian Brauner CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
375fe325c3fSChristian Brauner for (i = 0; i <= 100; i++) {
376fe325c3fSChristian Brauner int flags = fcntl(open_fds[i], F_GETFD);
377fe325c3fSChristian Brauner
378fe325c3fSChristian Brauner EXPECT_GT(flags, -1);
379fe325c3fSChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
380fe325c3fSChristian Brauner }
381fe325c3fSChristian Brauner }
38223afeaefSGiuseppe Scrivano
3836abc20f8SChristian Brauner /*
3846abc20f8SChristian Brauner * Regression test for syzbot+96cfd2b22b3213646a93@syzkaller.appspotmail.com
3856abc20f8SChristian Brauner */
TEST(close_range_cloexec_syzbot)3866abc20f8SChristian Brauner TEST(close_range_cloexec_syzbot)
3876abc20f8SChristian Brauner {
3886abc20f8SChristian Brauner int fd1, fd2, fd3, flags, ret, status;
3896abc20f8SChristian Brauner pid_t pid;
3906abc20f8SChristian Brauner struct __clone_args args = {
3916abc20f8SChristian Brauner .flags = CLONE_FILES,
3926abc20f8SChristian Brauner .exit_signal = SIGCHLD,
3936abc20f8SChristian Brauner };
3946abc20f8SChristian Brauner
3956abc20f8SChristian Brauner /* Create a huge gap in the fd table. */
3966abc20f8SChristian Brauner fd1 = open("/dev/null", O_RDWR);
3976abc20f8SChristian Brauner EXPECT_GT(fd1, 0);
3986abc20f8SChristian Brauner
3996abc20f8SChristian Brauner fd2 = dup2(fd1, 1000);
4006abc20f8SChristian Brauner EXPECT_GT(fd2, 0);
4016abc20f8SChristian Brauner
4026abc20f8SChristian Brauner pid = sys_clone3(&args, sizeof(args));
4036abc20f8SChristian Brauner ASSERT_GE(pid, 0);
4046abc20f8SChristian Brauner
4056abc20f8SChristian Brauner if (pid == 0) {
4066abc20f8SChristian Brauner ret = sys_close_range(3, ~0U, CLOSE_RANGE_CLOEXEC);
4076abc20f8SChristian Brauner if (ret)
4086abc20f8SChristian Brauner exit(EXIT_FAILURE);
4096abc20f8SChristian Brauner
4106abc20f8SChristian Brauner /*
4116abc20f8SChristian Brauner * We now have a private file descriptor table and all
4126abc20f8SChristian Brauner * our open fds should still be open but made
4136abc20f8SChristian Brauner * close-on-exec.
4146abc20f8SChristian Brauner */
4156abc20f8SChristian Brauner flags = fcntl(fd1, F_GETFD);
4166abc20f8SChristian Brauner EXPECT_GT(flags, -1);
4176abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
4186abc20f8SChristian Brauner
4196abc20f8SChristian Brauner flags = fcntl(fd2, F_GETFD);
4206abc20f8SChristian Brauner EXPECT_GT(flags, -1);
4216abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
4226abc20f8SChristian Brauner
4236abc20f8SChristian Brauner fd3 = dup2(fd1, 42);
4246abc20f8SChristian Brauner EXPECT_GT(fd3, 0);
4256abc20f8SChristian Brauner
4266abc20f8SChristian Brauner /*
4276abc20f8SChristian Brauner * Duplicating the file descriptor must remove the
4286abc20f8SChristian Brauner * FD_CLOEXEC flag.
4296abc20f8SChristian Brauner */
4306abc20f8SChristian Brauner flags = fcntl(fd3, F_GETFD);
4316abc20f8SChristian Brauner EXPECT_GT(flags, -1);
4326abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, 0);
4336abc20f8SChristian Brauner
4346abc20f8SChristian Brauner exit(EXIT_SUCCESS);
4356abc20f8SChristian Brauner }
4366abc20f8SChristian Brauner
4376abc20f8SChristian Brauner EXPECT_EQ(waitpid(pid, &status, 0), pid);
4386abc20f8SChristian Brauner EXPECT_EQ(true, WIFEXITED(status));
4396abc20f8SChristian Brauner EXPECT_EQ(0, WEXITSTATUS(status));
4406abc20f8SChristian Brauner
4416abc20f8SChristian Brauner /*
4426abc20f8SChristian Brauner * We had a shared file descriptor table before along with requesting
4436abc20f8SChristian Brauner * close-on-exec so the original fds must not be close-on-exec.
4446abc20f8SChristian Brauner */
4456abc20f8SChristian Brauner flags = fcntl(fd1, F_GETFD);
4466abc20f8SChristian Brauner EXPECT_GT(flags, -1);
4476abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
4486abc20f8SChristian Brauner
4496abc20f8SChristian Brauner flags = fcntl(fd2, F_GETFD);
4506abc20f8SChristian Brauner EXPECT_GT(flags, -1);
4516abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
4526abc20f8SChristian Brauner
4536abc20f8SChristian Brauner fd3 = dup2(fd1, 42);
4546abc20f8SChristian Brauner EXPECT_GT(fd3, 0);
4556abc20f8SChristian Brauner
4566abc20f8SChristian Brauner flags = fcntl(fd3, F_GETFD);
4576abc20f8SChristian Brauner EXPECT_GT(flags, -1);
4586abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, 0);
4596abc20f8SChristian Brauner
4606abc20f8SChristian Brauner EXPECT_EQ(close(fd1), 0);
4616abc20f8SChristian Brauner EXPECT_EQ(close(fd2), 0);
4626abc20f8SChristian Brauner EXPECT_EQ(close(fd3), 0);
4636abc20f8SChristian Brauner }
4646abc20f8SChristian Brauner
4656abc20f8SChristian Brauner /*
4666abc20f8SChristian Brauner * Regression test for syzbot+96cfd2b22b3213646a93@syzkaller.appspotmail.com
4676abc20f8SChristian Brauner */
TEST(close_range_cloexec_unshare_syzbot)4686abc20f8SChristian Brauner TEST(close_range_cloexec_unshare_syzbot)
4696abc20f8SChristian Brauner {
4706abc20f8SChristian Brauner int i, fd1, fd2, fd3, flags, ret, status;
4716abc20f8SChristian Brauner pid_t pid;
4726abc20f8SChristian Brauner struct __clone_args args = {
4736abc20f8SChristian Brauner .flags = CLONE_FILES,
4746abc20f8SChristian Brauner .exit_signal = SIGCHLD,
4756abc20f8SChristian Brauner };
4766abc20f8SChristian Brauner
4776abc20f8SChristian Brauner /*
4786abc20f8SChristian Brauner * Create a huge gap in the fd table. When we now call
4796abc20f8SChristian Brauner * CLOSE_RANGE_UNSHARE with a shared fd table and and with ~0U as upper
4806abc20f8SChristian Brauner * bound the kernel will only copy up to fd1 file descriptors into the
4816abc20f8SChristian Brauner * new fd table. If the kernel is buggy and doesn't handle
4826abc20f8SChristian Brauner * CLOSE_RANGE_CLOEXEC correctly it will not have copied all file
4836abc20f8SChristian Brauner * descriptors and we will oops!
4846abc20f8SChristian Brauner *
4856abc20f8SChristian Brauner * On a buggy kernel this should immediately oops. But let's loop just
4866abc20f8SChristian Brauner * to be sure.
4876abc20f8SChristian Brauner */
4886abc20f8SChristian Brauner fd1 = open("/dev/null", O_RDWR);
4896abc20f8SChristian Brauner EXPECT_GT(fd1, 0);
4906abc20f8SChristian Brauner
4916abc20f8SChristian Brauner fd2 = dup2(fd1, 1000);
4926abc20f8SChristian Brauner EXPECT_GT(fd2, 0);
4936abc20f8SChristian Brauner
4946abc20f8SChristian Brauner for (i = 0; i < 100; i++) {
4956abc20f8SChristian Brauner
4966abc20f8SChristian Brauner pid = sys_clone3(&args, sizeof(args));
4976abc20f8SChristian Brauner ASSERT_GE(pid, 0);
4986abc20f8SChristian Brauner
4996abc20f8SChristian Brauner if (pid == 0) {
5006abc20f8SChristian Brauner ret = sys_close_range(3, ~0U, CLOSE_RANGE_UNSHARE |
5016abc20f8SChristian Brauner CLOSE_RANGE_CLOEXEC);
5026abc20f8SChristian Brauner if (ret)
5036abc20f8SChristian Brauner exit(EXIT_FAILURE);
5046abc20f8SChristian Brauner
5056abc20f8SChristian Brauner /*
5066abc20f8SChristian Brauner * We now have a private file descriptor table and all
5076abc20f8SChristian Brauner * our open fds should still be open but made
5086abc20f8SChristian Brauner * close-on-exec.
5096abc20f8SChristian Brauner */
5106abc20f8SChristian Brauner flags = fcntl(fd1, F_GETFD);
5116abc20f8SChristian Brauner EXPECT_GT(flags, -1);
5126abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
5136abc20f8SChristian Brauner
5146abc20f8SChristian Brauner flags = fcntl(fd2, F_GETFD);
5156abc20f8SChristian Brauner EXPECT_GT(flags, -1);
5166abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
5176abc20f8SChristian Brauner
5186abc20f8SChristian Brauner fd3 = dup2(fd1, 42);
5196abc20f8SChristian Brauner EXPECT_GT(fd3, 0);
5206abc20f8SChristian Brauner
5216abc20f8SChristian Brauner /*
5226abc20f8SChristian Brauner * Duplicating the file descriptor must remove the
5236abc20f8SChristian Brauner * FD_CLOEXEC flag.
5246abc20f8SChristian Brauner */
5256abc20f8SChristian Brauner flags = fcntl(fd3, F_GETFD);
5266abc20f8SChristian Brauner EXPECT_GT(flags, -1);
5276abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, 0);
5286abc20f8SChristian Brauner
5296abc20f8SChristian Brauner EXPECT_EQ(close(fd1), 0);
5306abc20f8SChristian Brauner EXPECT_EQ(close(fd2), 0);
5316abc20f8SChristian Brauner EXPECT_EQ(close(fd3), 0);
5326abc20f8SChristian Brauner
5336abc20f8SChristian Brauner exit(EXIT_SUCCESS);
5346abc20f8SChristian Brauner }
5356abc20f8SChristian Brauner
5366abc20f8SChristian Brauner EXPECT_EQ(waitpid(pid, &status, 0), pid);
5376abc20f8SChristian Brauner EXPECT_EQ(true, WIFEXITED(status));
5386abc20f8SChristian Brauner EXPECT_EQ(0, WEXITSTATUS(status));
5396abc20f8SChristian Brauner }
5406abc20f8SChristian Brauner
5416abc20f8SChristian Brauner /*
5426abc20f8SChristian Brauner * We created a private file descriptor table before along with
5436abc20f8SChristian Brauner * requesting close-on-exec so the original fds must not be
5446abc20f8SChristian Brauner * close-on-exec.
5456abc20f8SChristian Brauner */
5466abc20f8SChristian Brauner flags = fcntl(fd1, F_GETFD);
5476abc20f8SChristian Brauner EXPECT_GT(flags, -1);
5486abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, 0);
5496abc20f8SChristian Brauner
5506abc20f8SChristian Brauner flags = fcntl(fd2, F_GETFD);
5516abc20f8SChristian Brauner EXPECT_GT(flags, -1);
5526abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, 0);
5536abc20f8SChristian Brauner
5546abc20f8SChristian Brauner fd3 = dup2(fd1, 42);
5556abc20f8SChristian Brauner EXPECT_GT(fd3, 0);
5566abc20f8SChristian Brauner
5576abc20f8SChristian Brauner flags = fcntl(fd3, F_GETFD);
5586abc20f8SChristian Brauner EXPECT_GT(flags, -1);
5596abc20f8SChristian Brauner EXPECT_EQ(flags & FD_CLOEXEC, 0);
5606abc20f8SChristian Brauner
5616abc20f8SChristian Brauner EXPECT_EQ(close(fd1), 0);
5626abc20f8SChristian Brauner EXPECT_EQ(close(fd2), 0);
5636abc20f8SChristian Brauner EXPECT_EQ(close(fd3), 0);
5646abc20f8SChristian Brauner }
5656abc20f8SChristian Brauner
5662c5db60eSChristian Brauner TEST_HARNESS_MAIN
567