pidfd_setns_test.c (13651B)
1// SPDX-License-Identifier: GPL-2.0 2 3#define _GNU_SOURCE 4#include <errno.h> 5#include <fcntl.h> 6#include <limits.h> 7#include <linux/types.h> 8#include <sched.h> 9#include <signal.h> 10#include <stdio.h> 11#include <stdlib.h> 12#include <string.h> 13#include <syscall.h> 14#include <sys/prctl.h> 15#include <sys/wait.h> 16#include <unistd.h> 17#include <sys/socket.h> 18#include <sys/stat.h> 19 20#include "pidfd.h" 21#include "../clone3/clone3_selftests.h" 22#include "../kselftest_harness.h" 23 24enum { 25 PIDFD_NS_USER, 26 PIDFD_NS_MNT, 27 PIDFD_NS_PID, 28 PIDFD_NS_UTS, 29 PIDFD_NS_IPC, 30 PIDFD_NS_NET, 31 PIDFD_NS_CGROUP, 32 PIDFD_NS_PIDCLD, 33 PIDFD_NS_TIME, 34 PIDFD_NS_MAX 35}; 36 37const struct ns_info { 38 const char *name; 39 int flag; 40} ns_info[] = { 41 [PIDFD_NS_USER] = { "user", CLONE_NEWUSER, }, 42 [PIDFD_NS_MNT] = { "mnt", CLONE_NEWNS, }, 43 [PIDFD_NS_PID] = { "pid", CLONE_NEWPID, }, 44 [PIDFD_NS_UTS] = { "uts", CLONE_NEWUTS, }, 45 [PIDFD_NS_IPC] = { "ipc", CLONE_NEWIPC, }, 46 [PIDFD_NS_NET] = { "net", CLONE_NEWNET, }, 47 [PIDFD_NS_CGROUP] = { "cgroup", CLONE_NEWCGROUP, }, 48 [PIDFD_NS_PIDCLD] = { "pid_for_children", 0, }, 49 [PIDFD_NS_TIME] = { "time", CLONE_NEWTIME, }, 50}; 51 52FIXTURE(current_nsset) 53{ 54 pid_t pid; 55 int pidfd; 56 int nsfds[PIDFD_NS_MAX]; 57 58 pid_t child_pid_exited; 59 int child_pidfd_exited; 60 61 pid_t child_pid1; 62 int child_pidfd1; 63 int child_nsfds1[PIDFD_NS_MAX]; 64 65 pid_t child_pid2; 66 int child_pidfd2; 67 int child_nsfds2[PIDFD_NS_MAX]; 68}; 69 70static int sys_waitid(int which, pid_t pid, int options) 71{ 72 return syscall(__NR_waitid, which, pid, NULL, options, NULL); 73} 74 75pid_t create_child(int *pidfd, unsigned flags) 76{ 77 struct __clone_args args = { 78 .flags = CLONE_PIDFD | flags, 79 .exit_signal = SIGCHLD, 80 .pidfd = ptr_to_u64(pidfd), 81 }; 82 83 return sys_clone3(&args, sizeof(struct clone_args)); 84} 85 86static bool switch_timens(void) 87{ 88 int fd, ret; 89 90 if (unshare(CLONE_NEWTIME)) 91 return false; 92 93 fd = open("/proc/self/ns/time_for_children", O_RDONLY | O_CLOEXEC); 94 if (fd < 0) 95 return false; 96 97 ret = setns(fd, CLONE_NEWTIME); 98 close(fd); 99 return ret == 0; 100} 101 102static ssize_t read_nointr(int fd, void *buf, size_t count) 103{ 104 ssize_t ret; 105 106 do { 107 ret = read(fd, buf, count); 108 } while (ret < 0 && errno == EINTR); 109 110 return ret; 111} 112 113static ssize_t write_nointr(int fd, const void *buf, size_t count) 114{ 115 ssize_t ret; 116 117 do { 118 ret = write(fd, buf, count); 119 } while (ret < 0 && errno == EINTR); 120 121 return ret; 122} 123 124FIXTURE_SETUP(current_nsset) 125{ 126 int i, proc_fd, ret; 127 int ipc_sockets[2]; 128 char c; 129 130 for (i = 0; i < PIDFD_NS_MAX; i++) { 131 self->nsfds[i] = -EBADF; 132 self->child_nsfds1[i] = -EBADF; 133 self->child_nsfds2[i] = -EBADF; 134 } 135 136 proc_fd = open("/proc/self/ns", O_DIRECTORY | O_CLOEXEC); 137 ASSERT_GE(proc_fd, 0) { 138 TH_LOG("%m - Failed to open /proc/self/ns"); 139 } 140 141 self->pid = getpid(); 142 for (i = 0; i < PIDFD_NS_MAX; i++) { 143 const struct ns_info *info = &ns_info[i]; 144 self->nsfds[i] = openat(proc_fd, info->name, O_RDONLY | O_CLOEXEC); 145 if (self->nsfds[i] < 0) { 146 EXPECT_EQ(errno, ENOENT) { 147 TH_LOG("%m - Failed to open %s namespace for process %d", 148 info->name, self->pid); 149 } 150 } 151 } 152 153 self->pidfd = sys_pidfd_open(self->pid, 0); 154 EXPECT_GT(self->pidfd, 0) { 155 TH_LOG("%m - Failed to open pidfd for process %d", self->pid); 156 } 157 158 /* Create task that exits right away. */ 159 self->child_pid_exited = create_child(&self->child_pidfd_exited, 160 CLONE_NEWUSER | CLONE_NEWNET); 161 EXPECT_GT(self->child_pid_exited, 0); 162 163 if (self->child_pid_exited == 0) 164 _exit(EXIT_SUCCESS); 165 166 ASSERT_EQ(sys_waitid(P_PID, self->child_pid_exited, WEXITED | WNOWAIT), 0); 167 168 self->pidfd = sys_pidfd_open(self->pid, 0); 169 EXPECT_GE(self->pidfd, 0) { 170 TH_LOG("%m - Failed to open pidfd for process %d", self->pid); 171 } 172 173 ret = socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 174 EXPECT_EQ(ret, 0); 175 176 /* Create tasks that will be stopped. */ 177 self->child_pid1 = create_child(&self->child_pidfd1, 178 CLONE_NEWUSER | CLONE_NEWNS | 179 CLONE_NEWCGROUP | CLONE_NEWIPC | 180 CLONE_NEWUTS | CLONE_NEWPID | 181 CLONE_NEWNET); 182 EXPECT_GE(self->child_pid1, 0); 183 184 if (self->child_pid1 == 0) { 185 close(ipc_sockets[0]); 186 187 if (!switch_timens()) 188 _exit(EXIT_FAILURE); 189 190 if (write_nointr(ipc_sockets[1], "1", 1) < 0) 191 _exit(EXIT_FAILURE); 192 193 close(ipc_sockets[1]); 194 195 pause(); 196 _exit(EXIT_SUCCESS); 197 } 198 199 close(ipc_sockets[1]); 200 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 201 close(ipc_sockets[0]); 202 203 ret = socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 204 EXPECT_EQ(ret, 0); 205 206 self->child_pid2 = create_child(&self->child_pidfd2, 207 CLONE_NEWUSER | CLONE_NEWNS | 208 CLONE_NEWCGROUP | CLONE_NEWIPC | 209 CLONE_NEWUTS | CLONE_NEWPID | 210 CLONE_NEWNET); 211 EXPECT_GE(self->child_pid2, 0); 212 213 if (self->child_pid2 == 0) { 214 close(ipc_sockets[0]); 215 216 if (!switch_timens()) 217 _exit(EXIT_FAILURE); 218 219 if (write_nointr(ipc_sockets[1], "1", 1) < 0) 220 _exit(EXIT_FAILURE); 221 222 close(ipc_sockets[1]); 223 224 pause(); 225 _exit(EXIT_SUCCESS); 226 } 227 228 close(ipc_sockets[1]); 229 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 230 close(ipc_sockets[0]); 231 232 for (i = 0; i < PIDFD_NS_MAX; i++) { 233 char p[100]; 234 235 const struct ns_info *info = &ns_info[i]; 236 237 self->nsfds[i] = openat(proc_fd, info->name, O_RDONLY | O_CLOEXEC); 238 if (self->nsfds[i] < 0) { 239 EXPECT_EQ(errno, ENOENT) { 240 TH_LOG("%m - Failed to open %s namespace for process %d", 241 info->name, self->pid); 242 } 243 } 244 245 ret = snprintf(p, sizeof(p), "/proc/%d/ns/%s", 246 self->child_pid1, info->name); 247 EXPECT_GT(ret, 0); 248 EXPECT_LT(ret, sizeof(p)); 249 250 self->child_nsfds1[i] = open(p, O_RDONLY | O_CLOEXEC); 251 if (self->child_nsfds1[i] < 0) { 252 EXPECT_EQ(errno, ENOENT) { 253 TH_LOG("%m - Failed to open %s namespace for process %d", 254 info->name, self->child_pid1); 255 } 256 } 257 258 ret = snprintf(p, sizeof(p), "/proc/%d/ns/%s", 259 self->child_pid2, info->name); 260 EXPECT_GT(ret, 0); 261 EXPECT_LT(ret, sizeof(p)); 262 263 self->child_nsfds2[i] = open(p, O_RDONLY | O_CLOEXEC); 264 if (self->child_nsfds2[i] < 0) { 265 EXPECT_EQ(errno, ENOENT) { 266 TH_LOG("%m - Failed to open %s namespace for process %d", 267 info->name, self->child_pid1); 268 } 269 } 270 } 271 272 close(proc_fd); 273} 274 275FIXTURE_TEARDOWN(current_nsset) 276{ 277 int i; 278 279 ASSERT_EQ(sys_pidfd_send_signal(self->child_pidfd1, 280 SIGKILL, NULL, 0), 0); 281 ASSERT_EQ(sys_pidfd_send_signal(self->child_pidfd2, 282 SIGKILL, NULL, 0), 0); 283 284 for (i = 0; i < PIDFD_NS_MAX; i++) { 285 if (self->nsfds[i] >= 0) 286 close(self->nsfds[i]); 287 if (self->child_nsfds1[i] >= 0) 288 close(self->child_nsfds1[i]); 289 if (self->child_nsfds2[i] >= 0) 290 close(self->child_nsfds2[i]); 291 } 292 293 if (self->child_pidfd1 >= 0) 294 EXPECT_EQ(0, close(self->child_pidfd1)); 295 if (self->child_pidfd2 >= 0) 296 EXPECT_EQ(0, close(self->child_pidfd2)); 297 ASSERT_EQ(sys_waitid(P_PID, self->child_pid_exited, WEXITED), 0); 298 ASSERT_EQ(sys_waitid(P_PID, self->child_pid1, WEXITED), 0); 299 ASSERT_EQ(sys_waitid(P_PID, self->child_pid2, WEXITED), 0); 300} 301 302static int preserve_ns(const int pid, const char *ns) 303{ 304 int ret; 305 char path[50]; 306 307 ret = snprintf(path, sizeof(path), "/proc/%d/ns/%s", pid, ns); 308 if (ret < 0 || (size_t)ret >= sizeof(path)) 309 return -EIO; 310 311 return open(path, O_RDONLY | O_CLOEXEC); 312} 313 314static int in_same_namespace(int ns_fd1, pid_t pid2, const char *ns) 315{ 316 int ns_fd2 = -EBADF; 317 int ret = -1; 318 struct stat ns_st1, ns_st2; 319 320 ret = fstat(ns_fd1, &ns_st1); 321 if (ret < 0) 322 return -1; 323 324 ns_fd2 = preserve_ns(pid2, ns); 325 if (ns_fd2 < 0) 326 return -1; 327 328 ret = fstat(ns_fd2, &ns_st2); 329 close(ns_fd2); 330 if (ret < 0) 331 return -1; 332 333 /* processes are in the same namespace */ 334 if ((ns_st1.st_dev == ns_st2.st_dev) && 335 (ns_st1.st_ino == ns_st2.st_ino)) 336 return 1; 337 338 /* processes are in different namespaces */ 339 return 0; 340} 341 342/* Test that we can't pass garbage to the kernel. */ 343TEST_F(current_nsset, invalid_flags) 344{ 345 ASSERT_NE(setns(self->pidfd, 0), 0); 346 EXPECT_EQ(errno, EINVAL); 347 348 ASSERT_NE(setns(self->pidfd, -1), 0); 349 EXPECT_EQ(errno, EINVAL); 350 351 ASSERT_NE(setns(self->pidfd, CLONE_VM), 0); 352 EXPECT_EQ(errno, EINVAL); 353 354 ASSERT_NE(setns(self->pidfd, CLONE_NEWUSER | CLONE_VM), 0); 355 EXPECT_EQ(errno, EINVAL); 356} 357 358/* Test that we can't attach to a task that has already exited. */ 359TEST_F(current_nsset, pidfd_exited_child) 360{ 361 int i; 362 pid_t pid; 363 364 ASSERT_NE(setns(self->child_pidfd_exited, CLONE_NEWUSER | CLONE_NEWNET), 365 0); 366 EXPECT_EQ(errno, ESRCH); 367 368 pid = getpid(); 369 for (i = 0; i < PIDFD_NS_MAX; i++) { 370 const struct ns_info *info = &ns_info[i]; 371 /* Verify that we haven't changed any namespaces. */ 372 if (self->nsfds[i] >= 0) 373 ASSERT_EQ(in_same_namespace(self->nsfds[i], pid, info->name), 1); 374 } 375} 376 377TEST_F(current_nsset, pidfd_incremental_setns) 378{ 379 int i; 380 pid_t pid; 381 382 pid = getpid(); 383 for (i = 0; i < PIDFD_NS_MAX; i++) { 384 const struct ns_info *info = &ns_info[i]; 385 int nsfd; 386 387 if (self->child_nsfds1[i] < 0) 388 continue; 389 390 if (info->flag) { 391 ASSERT_EQ(setns(self->child_pidfd1, info->flag), 0) { 392 TH_LOG("%m - Failed to setns to %s namespace of %d via pidfd %d", 393 info->name, self->child_pid1, 394 self->child_pidfd1); 395 } 396 } 397 398 /* Verify that we have changed to the correct namespaces. */ 399 if (info->flag == CLONE_NEWPID) 400 nsfd = self->nsfds[i]; 401 else 402 nsfd = self->child_nsfds1[i]; 403 ASSERT_EQ(in_same_namespace(nsfd, pid, info->name), 1) { 404 TH_LOG("setns failed to place us correctly into %s namespace of %d via pidfd %d", 405 info->name, self->child_pid1, 406 self->child_pidfd1); 407 } 408 TH_LOG("Managed to correctly setns to %s namespace of %d via pidfd %d", 409 info->name, self->child_pid1, self->child_pidfd1); 410 } 411} 412 413TEST_F(current_nsset, nsfd_incremental_setns) 414{ 415 int i; 416 pid_t pid; 417 418 pid = getpid(); 419 for (i = 0; i < PIDFD_NS_MAX; i++) { 420 const struct ns_info *info = &ns_info[i]; 421 int nsfd; 422 423 if (self->child_nsfds1[i] < 0) 424 continue; 425 426 if (info->flag) { 427 ASSERT_EQ(setns(self->child_nsfds1[i], info->flag), 0) { 428 TH_LOG("%m - Failed to setns to %s namespace of %d via nsfd %d", 429 info->name, self->child_pid1, 430 self->child_nsfds1[i]); 431 } 432 } 433 434 /* Verify that we have changed to the correct namespaces. */ 435 if (info->flag == CLONE_NEWPID) 436 nsfd = self->nsfds[i]; 437 else 438 nsfd = self->child_nsfds1[i]; 439 ASSERT_EQ(in_same_namespace(nsfd, pid, info->name), 1) { 440 TH_LOG("setns failed to place us correctly into %s namespace of %d via nsfd %d", 441 info->name, self->child_pid1, 442 self->child_nsfds1[i]); 443 } 444 TH_LOG("Managed to correctly setns to %s namespace of %d via nsfd %d", 445 info->name, self->child_pid1, self->child_nsfds1[i]); 446 } 447} 448 449TEST_F(current_nsset, pidfd_one_shot_setns) 450{ 451 unsigned flags = 0; 452 int i; 453 pid_t pid; 454 455 for (i = 0; i < PIDFD_NS_MAX; i++) { 456 const struct ns_info *info = &ns_info[i]; 457 458 if (self->child_nsfds1[i] < 0) 459 continue; 460 461 flags |= info->flag; 462 TH_LOG("Adding %s namespace of %d to list of namespaces to attach to", 463 info->name, self->child_pid1); 464 } 465 466 ASSERT_EQ(setns(self->child_pidfd1, flags), 0) { 467 TH_LOG("%m - Failed to setns to namespaces of %d", 468 self->child_pid1); 469 } 470 471 pid = getpid(); 472 for (i = 0; i < PIDFD_NS_MAX; i++) { 473 const struct ns_info *info = &ns_info[i]; 474 int nsfd; 475 476 if (self->child_nsfds1[i] < 0) 477 continue; 478 479 /* Verify that we have changed to the correct namespaces. */ 480 if (info->flag == CLONE_NEWPID) 481 nsfd = self->nsfds[i]; 482 else 483 nsfd = self->child_nsfds1[i]; 484 ASSERT_EQ(in_same_namespace(nsfd, pid, info->name), 1) { 485 TH_LOG("setns failed to place us correctly into %s namespace of %d", 486 info->name, self->child_pid1); 487 } 488 TH_LOG("Managed to correctly setns to %s namespace of %d", 489 info->name, self->child_pid1); 490 } 491} 492 493TEST_F(current_nsset, no_foul_play) 494{ 495 unsigned flags = 0; 496 int i; 497 498 for (i = 0; i < PIDFD_NS_MAX; i++) { 499 const struct ns_info *info = &ns_info[i]; 500 501 if (self->child_nsfds1[i] < 0) 502 continue; 503 504 flags |= info->flag; 505 if (info->flag) /* No use logging pid_for_children. */ 506 TH_LOG("Adding %s namespace of %d to list of namespaces to attach to", 507 info->name, self->child_pid1); 508 } 509 510 ASSERT_EQ(setns(self->child_pidfd1, flags), 0) { 511 TH_LOG("%m - Failed to setns to namespaces of %d vid pidfd %d", 512 self->child_pid1, self->child_pidfd1); 513 } 514 515 /* 516 * Can't setns to a user namespace outside of our hierarchy since we 517 * don't have caps in there and didn't create it. That means that under 518 * no circumstances should we be able to setns to any of the other 519 * ones since they aren't owned by our user namespace. 520 */ 521 for (i = 0; i < PIDFD_NS_MAX; i++) { 522 const struct ns_info *info = &ns_info[i]; 523 524 if (self->child_nsfds2[i] < 0 || !info->flag) 525 continue; 526 527 ASSERT_NE(setns(self->child_pidfd2, info->flag), 0) { 528 TH_LOG("Managed to setns to %s namespace of %d via pidfd %d", 529 info->name, self->child_pid2, 530 self->child_pidfd2); 531 } 532 TH_LOG("%m - Correctly failed to setns to %s namespace of %d via pidfd %d", 533 info->name, self->child_pid2, 534 self->child_pidfd2); 535 536 ASSERT_NE(setns(self->child_nsfds2[i], info->flag), 0) { 537 TH_LOG("Managed to setns to %s namespace of %d via nsfd %d", 538 info->name, self->child_pid2, 539 self->child_nsfds2[i]); 540 } 541 TH_LOG("%m - Correctly failed to setns to %s namespace of %d via nsfd %d", 542 info->name, self->child_pid2, 543 self->child_nsfds2[i]); 544 } 545} 546 547TEST(setns_einval) 548{ 549 int fd; 550 551 fd = sys_memfd_create("rostock", 0); 552 EXPECT_GT(fd, 0); 553 554 ASSERT_NE(setns(fd, 0), 0); 555 EXPECT_EQ(errno, EINVAL); 556 close(fd); 557} 558 559TEST_HARNESS_MAIN