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 #include <sys/resource.h> 15 16 #include "../kselftest_harness.h" 17 #include "../clone3/clone3_selftests.h" 18 19 #ifndef __NR_close_range 20 #define __NR_close_range -1 21 #endif 22 23 #ifndef CLOSE_RANGE_UNSHARE 24 #define CLOSE_RANGE_UNSHARE (1U << 1) 25 #endif 26 27 #ifndef CLOSE_RANGE_CLOEXEC 28 #define CLOSE_RANGE_CLOEXEC (1U << 2) 29 #endif 30 31 static inline int sys_close_range(unsigned int fd, unsigned int max_fd, 32 unsigned int flags) 33 { 34 return syscall(__NR_close_range, fd, max_fd, flags); 35 } 36 37 #ifndef ARRAY_SIZE 38 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 39 #endif 40 41 TEST(close_range) 42 { 43 int i, ret; 44 int open_fds[101]; 45 46 for (i = 0; i < ARRAY_SIZE(open_fds); i++) { 47 int fd; 48 49 fd = open("/dev/null", O_RDONLY | O_CLOEXEC); 50 ASSERT_GE(fd, 0) { 51 if (errno == ENOENT) 52 SKIP(return, "Skipping test since /dev/null does not exist"); 53 } 54 55 open_fds[i] = fd; 56 } 57 58 EXPECT_EQ(-1, sys_close_range(open_fds[0], open_fds[100], -1)) { 59 if (errno == ENOSYS) 60 SKIP(return, "close_range() syscall not supported"); 61 } 62 63 EXPECT_EQ(0, sys_close_range(open_fds[0], open_fds[50], 0)); 64 65 for (i = 0; i <= 50; i++) 66 EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL)); 67 68 for (i = 51; i <= 100; i++) 69 EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1); 70 71 /* create a couple of gaps */ 72 close(57); 73 close(78); 74 close(81); 75 close(82); 76 close(84); 77 close(90); 78 79 EXPECT_EQ(0, sys_close_range(open_fds[51], open_fds[92], 0)); 80 81 for (i = 51; i <= 92; i++) 82 EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL)); 83 84 for (i = 93; i <= 100; i++) 85 EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1); 86 87 /* test that the kernel caps and still closes all fds */ 88 EXPECT_EQ(0, sys_close_range(open_fds[93], open_fds[99], 0)); 89 90 for (i = 93; i <= 99; i++) 91 EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL)); 92 93 EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1); 94 95 EXPECT_EQ(0, sys_close_range(open_fds[100], open_fds[100], 0)); 96 97 EXPECT_EQ(-1, fcntl(open_fds[100], F_GETFL)); 98 } 99 100 TEST(close_range_unshare) 101 { 102 int i, ret, status; 103 pid_t pid; 104 int open_fds[101]; 105 struct clone_args args = { 106 .flags = CLONE_FILES, 107 .exit_signal = SIGCHLD, 108 }; 109 110 for (i = 0; i < ARRAY_SIZE(open_fds); i++) { 111 int fd; 112 113 fd = open("/dev/null", O_RDONLY | O_CLOEXEC); 114 ASSERT_GE(fd, 0) { 115 if (errno == ENOENT) 116 SKIP(return, "Skipping test since /dev/null does not exist"); 117 } 118 119 open_fds[i] = fd; 120 } 121 122 pid = sys_clone3(&args, sizeof(args)); 123 ASSERT_GE(pid, 0); 124 125 if (pid == 0) { 126 ret = sys_close_range(open_fds[0], open_fds[50], 127 CLOSE_RANGE_UNSHARE); 128 if (ret) 129 exit(EXIT_FAILURE); 130 131 for (i = 0; i <= 50; i++) 132 if (fcntl(open_fds[i], F_GETFL) != -1) 133 exit(EXIT_FAILURE); 134 135 for (i = 51; i <= 100; i++) 136 if (fcntl(open_fds[i], F_GETFL) == -1) 137 exit(EXIT_FAILURE); 138 139 /* create a couple of gaps */ 140 close(57); 141 close(78); 142 close(81); 143 close(82); 144 close(84); 145 close(90); 146 147 ret = sys_close_range(open_fds[51], open_fds[92], 148 CLOSE_RANGE_UNSHARE); 149 if (ret) 150 exit(EXIT_FAILURE); 151 152 for (i = 51; i <= 92; i++) 153 if (fcntl(open_fds[i], F_GETFL) != -1) 154 exit(EXIT_FAILURE); 155 156 for (i = 93; i <= 100; i++) 157 if (fcntl(open_fds[i], F_GETFL) == -1) 158 exit(EXIT_FAILURE); 159 160 /* test that the kernel caps and still closes all fds */ 161 ret = sys_close_range(open_fds[93], open_fds[99], 162 CLOSE_RANGE_UNSHARE); 163 if (ret) 164 exit(EXIT_FAILURE); 165 166 for (i = 93; i <= 99; i++) 167 if (fcntl(open_fds[i], F_GETFL) != -1) 168 exit(EXIT_FAILURE); 169 170 if (fcntl(open_fds[100], F_GETFL) == -1) 171 exit(EXIT_FAILURE); 172 173 ret = sys_close_range(open_fds[100], open_fds[100], 174 CLOSE_RANGE_UNSHARE); 175 if (ret) 176 exit(EXIT_FAILURE); 177 178 if (fcntl(open_fds[100], F_GETFL) != -1) 179 exit(EXIT_FAILURE); 180 181 exit(EXIT_SUCCESS); 182 } 183 184 EXPECT_EQ(waitpid(pid, &status, 0), pid); 185 EXPECT_EQ(true, WIFEXITED(status)); 186 EXPECT_EQ(0, WEXITSTATUS(status)); 187 } 188 189 TEST(close_range_unshare_capped) 190 { 191 int i, ret, status; 192 pid_t pid; 193 int open_fds[101]; 194 struct clone_args args = { 195 .flags = CLONE_FILES, 196 .exit_signal = SIGCHLD, 197 }; 198 199 for (i = 0; i < ARRAY_SIZE(open_fds); i++) { 200 int fd; 201 202 fd = open("/dev/null", O_RDONLY | O_CLOEXEC); 203 ASSERT_GE(fd, 0) { 204 if (errno == ENOENT) 205 SKIP(return, "Skipping test since /dev/null does not exist"); 206 } 207 208 open_fds[i] = fd; 209 } 210 211 pid = sys_clone3(&args, sizeof(args)); 212 ASSERT_GE(pid, 0); 213 214 if (pid == 0) { 215 ret = sys_close_range(open_fds[0], UINT_MAX, 216 CLOSE_RANGE_UNSHARE); 217 if (ret) 218 exit(EXIT_FAILURE); 219 220 for (i = 0; i <= 100; i++) 221 if (fcntl(open_fds[i], F_GETFL) != -1) 222 exit(EXIT_FAILURE); 223 224 exit(EXIT_SUCCESS); 225 } 226 227 EXPECT_EQ(waitpid(pid, &status, 0), pid); 228 EXPECT_EQ(true, WIFEXITED(status)); 229 EXPECT_EQ(0, WEXITSTATUS(status)); 230 } 231 232 TEST(close_range_cloexec) 233 { 234 int i, ret; 235 int open_fds[101]; 236 struct rlimit rlimit; 237 238 for (i = 0; i < ARRAY_SIZE(open_fds); i++) { 239 int fd; 240 241 fd = open("/dev/null", O_RDONLY); 242 ASSERT_GE(fd, 0) { 243 if (errno == ENOENT) 244 XFAIL(return, "Skipping test since /dev/null does not exist"); 245 } 246 247 open_fds[i] = fd; 248 } 249 250 ret = sys_close_range(1000, 1000, CLOSE_RANGE_CLOEXEC); 251 if (ret < 0) { 252 if (errno == ENOSYS) 253 XFAIL(return, "close_range() syscall not supported"); 254 if (errno == EINVAL) 255 XFAIL(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC"); 256 } 257 258 /* Ensure the FD_CLOEXEC bit is set also with a resource limit in place. */ 259 ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit)); 260 rlimit.rlim_cur = 25; 261 ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlimit)); 262 263 /* Set close-on-exec for two ranges: [0-50] and [75-100]. */ 264 ret = sys_close_range(open_fds[0], open_fds[50], CLOSE_RANGE_CLOEXEC); 265 ASSERT_EQ(0, ret); 266 ret = sys_close_range(open_fds[75], open_fds[100], CLOSE_RANGE_CLOEXEC); 267 ASSERT_EQ(0, ret); 268 269 for (i = 0; i <= 50; i++) { 270 int flags = fcntl(open_fds[i], F_GETFD); 271 272 EXPECT_GT(flags, -1); 273 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC); 274 } 275 276 for (i = 51; i <= 74; i++) { 277 int flags = fcntl(open_fds[i], F_GETFD); 278 279 EXPECT_GT(flags, -1); 280 EXPECT_EQ(flags & FD_CLOEXEC, 0); 281 } 282 283 for (i = 75; i <= 100; i++) { 284 int flags = fcntl(open_fds[i], F_GETFD); 285 286 EXPECT_GT(flags, -1); 287 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC); 288 } 289 290 /* Test a common pattern. */ 291 ret = sys_close_range(3, UINT_MAX, CLOSE_RANGE_CLOEXEC); 292 for (i = 0; i <= 100; i++) { 293 int flags = fcntl(open_fds[i], F_GETFD); 294 295 EXPECT_GT(flags, -1); 296 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC); 297 } 298 } 299 300 301 TEST_HARNESS_MAIN 302