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