1 // SPDX-License-Identifier: GPL-2.0 2 #define _GNU_SOURCE 3 #include <errno.h> 4 #include <fcntl.h> 5 #include <grp.h> 6 #include <limits.h> 7 #include <sched.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include <sys/mount.h> 12 #include <sys/stat.h> 13 #include <sys/types.h> 14 #include <sys/wait.h> 15 #include <unistd.h> 16 #include <linux/unistd.h> 17 #include "../kselftest_harness.h" 18 19 #ifndef FD_NSFS_ROOT 20 #define FD_NSFS_ROOT -10003 /* Root of the nsfs filesystem */ 21 #endif 22 23 TEST(nsfs_net_handle) 24 { 25 struct file_handle *handle; 26 int mount_id; 27 int ret; 28 int fd; 29 int ns_fd; 30 struct stat st1, st2; 31 32 /* Drop to unprivileged uid/gid */ 33 ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */ 34 ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */ 35 36 handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 37 ASSERT_NE(handle, NULL); 38 39 /* Open a namespace file descriptor */ 40 ns_fd = open("/proc/self/ns/net", O_RDONLY); 41 ASSERT_GE(ns_fd, 0); 42 43 /* Get handle for the namespace */ 44 handle->handle_bytes = MAX_HANDLE_SZ; 45 ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 46 if (ret < 0 && errno == EOPNOTSUPP) { 47 SKIP(free(handle); close(ns_fd); 48 return, "nsfs doesn't support file handles"); 49 } 50 ASSERT_EQ(ret, 0); 51 ASSERT_GT(handle->handle_bytes, 0); 52 53 /* Try to open using FD_NSFS_ROOT as unprivileged user */ 54 fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 55 if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) { 56 SKIP(free(handle); close(ns_fd); 57 return, 58 "open_by_handle_at with FD_NSFS_ROOT not supported"); 59 } 60 if (fd < 0 && errno == EPERM) { 61 SKIP(free(handle); close(ns_fd); 62 return, 63 "Permission denied for unprivileged user (expected)"); 64 } 65 ASSERT_GE(fd, 0); 66 67 /* Verify we opened the correct namespace */ 68 ASSERT_EQ(fstat(ns_fd, &st1), 0); 69 ASSERT_EQ(fstat(fd, &st2), 0); 70 ASSERT_EQ(st1.st_ino, st2.st_ino); 71 ASSERT_EQ(st1.st_dev, st2.st_dev); 72 73 close(fd); 74 close(ns_fd); 75 free(handle); 76 } 77 78 TEST(nsfs_uts_handle) 79 { 80 struct file_handle *handle; 81 int mount_id; 82 int ret; 83 int fd; 84 int ns_fd; 85 struct stat st1, st2; 86 87 /* Drop to unprivileged uid/gid */ 88 ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */ 89 ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */ 90 91 handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 92 ASSERT_NE(handle, NULL); 93 94 /* Open UTS namespace file descriptor */ 95 ns_fd = open("/proc/self/ns/uts", O_RDONLY); 96 ASSERT_GE(ns_fd, 0); 97 98 /* Get handle for the namespace */ 99 handle->handle_bytes = MAX_HANDLE_SZ; 100 ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 101 if (ret < 0 && errno == EOPNOTSUPP) { 102 SKIP(free(handle); close(ns_fd); 103 return, "nsfs doesn't support file handles"); 104 } 105 ASSERT_EQ(ret, 0); 106 ASSERT_GT(handle->handle_bytes, 0); 107 108 /* Try to open using FD_NSFS_ROOT */ 109 fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 110 if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) { 111 SKIP(free(handle); close(ns_fd); 112 return, 113 "open_by_handle_at with FD_NSFS_ROOT not supported"); 114 } 115 ASSERT_GE(fd, 0); 116 117 /* Verify we opened the correct namespace */ 118 ASSERT_EQ(fstat(ns_fd, &st1), 0); 119 ASSERT_EQ(fstat(fd, &st2), 0); 120 ASSERT_EQ(st1.st_ino, st2.st_ino); 121 ASSERT_EQ(st1.st_dev, st2.st_dev); 122 123 close(fd); 124 close(ns_fd); 125 free(handle); 126 } 127 128 TEST(nsfs_ipc_handle) 129 { 130 struct file_handle *handle; 131 int mount_id; 132 int ret; 133 int fd; 134 int ns_fd; 135 struct stat st1, st2; 136 137 /* Drop to unprivileged uid/gid */ 138 ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */ 139 ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */ 140 141 handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 142 ASSERT_NE(handle, NULL); 143 144 /* Open IPC namespace file descriptor */ 145 ns_fd = open("/proc/self/ns/ipc", O_RDONLY); 146 ASSERT_GE(ns_fd, 0); 147 148 /* Get handle for the namespace */ 149 handle->handle_bytes = MAX_HANDLE_SZ; 150 ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 151 if (ret < 0 && errno == EOPNOTSUPP) { 152 SKIP(free(handle); close(ns_fd); 153 return, "nsfs doesn't support file handles"); 154 } 155 ASSERT_EQ(ret, 0); 156 ASSERT_GT(handle->handle_bytes, 0); 157 158 /* Try to open using FD_NSFS_ROOT */ 159 fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 160 if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) { 161 SKIP(free(handle); close(ns_fd); 162 return, 163 "open_by_handle_at with FD_NSFS_ROOT not supported"); 164 } 165 ASSERT_GE(fd, 0); 166 167 /* Verify we opened the correct namespace */ 168 ASSERT_EQ(fstat(ns_fd, &st1), 0); 169 ASSERT_EQ(fstat(fd, &st2), 0); 170 ASSERT_EQ(st1.st_ino, st2.st_ino); 171 ASSERT_EQ(st1.st_dev, st2.st_dev); 172 173 close(fd); 174 close(ns_fd); 175 free(handle); 176 } 177 178 TEST(nsfs_pid_handle) 179 { 180 struct file_handle *handle; 181 int mount_id; 182 int ret; 183 int fd; 184 int ns_fd; 185 struct stat st1, st2; 186 187 /* Drop to unprivileged uid/gid */ 188 ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */ 189 ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */ 190 191 handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 192 ASSERT_NE(handle, NULL); 193 194 /* Open PID namespace file descriptor */ 195 ns_fd = open("/proc/self/ns/pid", O_RDONLY); 196 ASSERT_GE(ns_fd, 0); 197 198 /* Get handle for the namespace */ 199 handle->handle_bytes = MAX_HANDLE_SZ; 200 ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 201 if (ret < 0 && errno == EOPNOTSUPP) { 202 SKIP(free(handle); close(ns_fd); 203 return, "nsfs doesn't support file handles"); 204 } 205 ASSERT_EQ(ret, 0); 206 ASSERT_GT(handle->handle_bytes, 0); 207 208 /* Try to open using FD_NSFS_ROOT */ 209 fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 210 if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) { 211 SKIP(free(handle); close(ns_fd); 212 return, 213 "open_by_handle_at with FD_NSFS_ROOT not supported"); 214 } 215 ASSERT_GE(fd, 0); 216 217 /* Verify we opened the correct namespace */ 218 ASSERT_EQ(fstat(ns_fd, &st1), 0); 219 ASSERT_EQ(fstat(fd, &st2), 0); 220 ASSERT_EQ(st1.st_ino, st2.st_ino); 221 ASSERT_EQ(st1.st_dev, st2.st_dev); 222 223 close(fd); 224 close(ns_fd); 225 free(handle); 226 } 227 228 TEST(nsfs_mnt_handle) 229 { 230 struct file_handle *handle; 231 int mount_id; 232 int ret; 233 int fd; 234 int ns_fd; 235 struct stat st1, st2; 236 237 /* Drop to unprivileged uid/gid */ 238 ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */ 239 ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */ 240 241 handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 242 ASSERT_NE(handle, NULL); 243 244 /* Open mount namespace file descriptor */ 245 ns_fd = open("/proc/self/ns/mnt", O_RDONLY); 246 ASSERT_GE(ns_fd, 0); 247 248 /* Get handle for the namespace */ 249 handle->handle_bytes = MAX_HANDLE_SZ; 250 ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 251 if (ret < 0 && errno == EOPNOTSUPP) { 252 SKIP(free(handle); close(ns_fd); 253 return, "nsfs doesn't support file handles"); 254 } 255 ASSERT_EQ(ret, 0); 256 ASSERT_GT(handle->handle_bytes, 0); 257 258 /* Try to open using FD_NSFS_ROOT */ 259 fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 260 if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) { 261 SKIP(free(handle); close(ns_fd); 262 return, 263 "open_by_handle_at with FD_NSFS_ROOT not supported"); 264 } 265 ASSERT_GE(fd, 0); 266 267 /* Verify we opened the correct namespace */ 268 ASSERT_EQ(fstat(ns_fd, &st1), 0); 269 ASSERT_EQ(fstat(fd, &st2), 0); 270 ASSERT_EQ(st1.st_ino, st2.st_ino); 271 ASSERT_EQ(st1.st_dev, st2.st_dev); 272 273 close(fd); 274 close(ns_fd); 275 free(handle); 276 } 277 278 TEST(nsfs_user_handle) 279 { 280 struct file_handle *handle; 281 int mount_id; 282 int ret; 283 int fd; 284 int ns_fd; 285 struct stat st1, st2; 286 287 /* Drop to unprivileged uid/gid */ 288 ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */ 289 ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */ 290 291 handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 292 ASSERT_NE(handle, NULL); 293 294 /* Open user namespace file descriptor */ 295 ns_fd = open("/proc/self/ns/user", O_RDONLY); 296 ASSERT_GE(ns_fd, 0); 297 298 /* Get handle for the namespace */ 299 handle->handle_bytes = MAX_HANDLE_SZ; 300 ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 301 if (ret < 0 && errno == EOPNOTSUPP) { 302 SKIP(free(handle); close(ns_fd); 303 return, "nsfs doesn't support file handles"); 304 } 305 ASSERT_EQ(ret, 0); 306 ASSERT_GT(handle->handle_bytes, 0); 307 308 /* Try to open using FD_NSFS_ROOT */ 309 fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 310 if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) { 311 SKIP(free(handle); close(ns_fd); 312 return, 313 "open_by_handle_at with FD_NSFS_ROOT not supported"); 314 } 315 ASSERT_GE(fd, 0); 316 317 /* Verify we opened the correct namespace */ 318 ASSERT_EQ(fstat(ns_fd, &st1), 0); 319 ASSERT_EQ(fstat(fd, &st2), 0); 320 ASSERT_EQ(st1.st_ino, st2.st_ino); 321 ASSERT_EQ(st1.st_dev, st2.st_dev); 322 323 close(fd); 324 close(ns_fd); 325 free(handle); 326 } 327 328 TEST(nsfs_cgroup_handle) 329 { 330 struct file_handle *handle; 331 int mount_id; 332 int ret; 333 int fd; 334 int ns_fd; 335 struct stat st1, st2; 336 337 /* Drop to unprivileged uid/gid */ 338 ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */ 339 ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */ 340 341 handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 342 ASSERT_NE(handle, NULL); 343 344 /* Open cgroup namespace file descriptor */ 345 ns_fd = open("/proc/self/ns/cgroup", O_RDONLY); 346 if (ns_fd < 0) { 347 SKIP(free(handle); return, "cgroup namespace not available"); 348 } 349 350 /* Get handle for the namespace */ 351 handle->handle_bytes = MAX_HANDLE_SZ; 352 ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 353 if (ret < 0 && errno == EOPNOTSUPP) { 354 SKIP(free(handle); close(ns_fd); 355 return, "nsfs doesn't support file handles"); 356 } 357 ASSERT_EQ(ret, 0); 358 ASSERT_GT(handle->handle_bytes, 0); 359 360 /* Try to open using FD_NSFS_ROOT */ 361 fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 362 if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) { 363 SKIP(free(handle); close(ns_fd); 364 return, 365 "open_by_handle_at with FD_NSFS_ROOT not supported"); 366 } 367 ASSERT_GE(fd, 0); 368 369 /* Verify we opened the correct namespace */ 370 ASSERT_EQ(fstat(ns_fd, &st1), 0); 371 ASSERT_EQ(fstat(fd, &st2), 0); 372 ASSERT_EQ(st1.st_ino, st2.st_ino); 373 ASSERT_EQ(st1.st_dev, st2.st_dev); 374 375 close(fd); 376 close(ns_fd); 377 free(handle); 378 } 379 380 TEST(nsfs_time_handle) 381 { 382 struct file_handle *handle; 383 int mount_id; 384 int ret; 385 int fd; 386 int ns_fd; 387 struct stat st1, st2; 388 389 /* Drop to unprivileged uid/gid */ 390 ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */ 391 ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */ 392 393 handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 394 ASSERT_NE(handle, NULL); 395 396 /* Open time namespace file descriptor */ 397 ns_fd = open("/proc/self/ns/time", O_RDONLY); 398 if (ns_fd < 0) { 399 SKIP(free(handle); return, "time namespace not available"); 400 } 401 402 /* Get handle for the namespace */ 403 handle->handle_bytes = MAX_HANDLE_SZ; 404 ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 405 if (ret < 0 && errno == EOPNOTSUPP) { 406 SKIP(free(handle); close(ns_fd); 407 return, "nsfs doesn't support file handles"); 408 } 409 ASSERT_EQ(ret, 0); 410 ASSERT_GT(handle->handle_bytes, 0); 411 412 /* Try to open using FD_NSFS_ROOT */ 413 fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 414 if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) { 415 SKIP(free(handle); close(ns_fd); 416 return, 417 "open_by_handle_at with FD_NSFS_ROOT not supported"); 418 } 419 ASSERT_GE(fd, 0); 420 421 /* Verify we opened the correct namespace */ 422 ASSERT_EQ(fstat(ns_fd, &st1), 0); 423 ASSERT_EQ(fstat(fd, &st2), 0); 424 ASSERT_EQ(st1.st_ino, st2.st_ino); 425 ASSERT_EQ(st1.st_dev, st2.st_dev); 426 427 close(fd); 428 close(ns_fd); 429 free(handle); 430 } 431 432 TEST(nsfs_user_net_namespace_isolation) 433 { 434 struct file_handle *handle; 435 int mount_id; 436 int ret; 437 int fd; 438 int ns_fd; 439 pid_t pid; 440 int status; 441 int pipefd[2]; 442 char result; 443 444 handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 445 ASSERT_NE(handle, NULL); 446 447 /* Create pipe for communication */ 448 ASSERT_EQ(pipe(pipefd), 0); 449 450 /* Get handle for current network namespace */ 451 ns_fd = open("/proc/self/ns/net", O_RDONLY); 452 ASSERT_GE(ns_fd, 0); 453 454 handle->handle_bytes = MAX_HANDLE_SZ; 455 ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 456 if (ret < 0 && errno == EOPNOTSUPP) { 457 SKIP(free(handle); close(ns_fd); close(pipefd[0]); 458 close(pipefd[1]); 459 return, "nsfs doesn't support file handles"); 460 } 461 ASSERT_EQ(ret, 0); 462 close(ns_fd); 463 464 pid = fork(); 465 ASSERT_GE(pid, 0); 466 467 if (pid == 0) { 468 /* Child process */ 469 close(pipefd[0]); 470 471 /* First create new user namespace to drop privileges */ 472 ret = unshare(CLONE_NEWUSER); 473 if (ret < 0) { 474 write(pipefd[1], "U", 475 1); /* Unable to create user namespace */ 476 close(pipefd[1]); 477 exit(0); 478 } 479 480 /* Write uid/gid mappings to maintain some capabilities */ 481 int uid_map_fd = open("/proc/self/uid_map", O_WRONLY); 482 int gid_map_fd = open("/proc/self/gid_map", O_WRONLY); 483 int setgroups_fd = open("/proc/self/setgroups", O_WRONLY); 484 485 if (uid_map_fd < 0 || gid_map_fd < 0 || setgroups_fd < 0) { 486 write(pipefd[1], "M", 1); /* Unable to set mappings */ 487 close(pipefd[1]); 488 exit(0); 489 } 490 491 /* Disable setgroups to allow gid mapping */ 492 write(setgroups_fd, "deny", 4); 493 close(setgroups_fd); 494 495 /* Map current uid/gid to root in the new namespace */ 496 char mapping[64]; 497 snprintf(mapping, sizeof(mapping), "0 %d 1", getuid()); 498 write(uid_map_fd, mapping, strlen(mapping)); 499 close(uid_map_fd); 500 501 snprintf(mapping, sizeof(mapping), "0 %d 1", getgid()); 502 write(gid_map_fd, mapping, strlen(mapping)); 503 close(gid_map_fd); 504 505 /* Now create new network namespace */ 506 ret = unshare(CLONE_NEWNET); 507 if (ret < 0) { 508 write(pipefd[1], "N", 509 1); /* Unable to create network namespace */ 510 close(pipefd[1]); 511 exit(0); 512 } 513 514 /* Try to open parent's network namespace handle from new user+net namespace */ 515 fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 516 517 if (fd >= 0) { 518 /* Should NOT succeed - we're in a different user namespace */ 519 write(pipefd[1], "S", 1); /* Unexpected success */ 520 close(fd); 521 } else if (errno == ESTALE) { 522 /* Expected: Stale file handle */ 523 write(pipefd[1], "P", 1); 524 } else { 525 /* Other error */ 526 write(pipefd[1], "F", 1); 527 } 528 529 close(pipefd[1]); 530 exit(0); 531 } 532 533 /* Parent process */ 534 close(pipefd[1]); 535 ASSERT_EQ(read(pipefd[0], &result, 1), 1); 536 537 waitpid(pid, &status, 0); 538 ASSERT_TRUE(WIFEXITED(status)); 539 ASSERT_EQ(WEXITSTATUS(status), 0); 540 541 if (result == 'U') { 542 SKIP(free(handle); close(pipefd[0]); 543 return, "Cannot create new user namespace"); 544 } 545 if (result == 'M') { 546 SKIP(free(handle); close(pipefd[0]); 547 return, "Cannot set uid/gid mappings"); 548 } 549 if (result == 'N') { 550 SKIP(free(handle); close(pipefd[0]); 551 return, "Cannot create new network namespace"); 552 } 553 554 /* Should fail with permission denied since we're in a different user namespace */ 555 ASSERT_EQ(result, 'P'); 556 557 close(pipefd[0]); 558 free(handle); 559 } 560 561 TEST(nsfs_user_uts_namespace_isolation) 562 { 563 struct file_handle *handle; 564 int mount_id; 565 int ret; 566 int fd; 567 int ns_fd; 568 pid_t pid; 569 int status; 570 int pipefd[2]; 571 char result; 572 573 handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 574 ASSERT_NE(handle, NULL); 575 576 /* Create pipe for communication */ 577 ASSERT_EQ(pipe(pipefd), 0); 578 579 /* Get handle for current UTS namespace */ 580 ns_fd = open("/proc/self/ns/uts", O_RDONLY); 581 ASSERT_GE(ns_fd, 0); 582 583 handle->handle_bytes = MAX_HANDLE_SZ; 584 ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 585 if (ret < 0 && errno == EOPNOTSUPP) { 586 SKIP(free(handle); close(ns_fd); close(pipefd[0]); 587 close(pipefd[1]); 588 return, "nsfs doesn't support file handles"); 589 } 590 ASSERT_EQ(ret, 0); 591 close(ns_fd); 592 593 pid = fork(); 594 ASSERT_GE(pid, 0); 595 596 if (pid == 0) { 597 /* Child process */ 598 close(pipefd[0]); 599 600 /* First create new user namespace to drop privileges */ 601 ret = unshare(CLONE_NEWUSER); 602 if (ret < 0) { 603 write(pipefd[1], "U", 604 1); /* Unable to create user namespace */ 605 close(pipefd[1]); 606 exit(0); 607 } 608 609 /* Write uid/gid mappings to maintain some capabilities */ 610 int uid_map_fd = open("/proc/self/uid_map", O_WRONLY); 611 int gid_map_fd = open("/proc/self/gid_map", O_WRONLY); 612 int setgroups_fd = open("/proc/self/setgroups", O_WRONLY); 613 614 if (uid_map_fd < 0 || gid_map_fd < 0 || setgroups_fd < 0) { 615 write(pipefd[1], "M", 1); /* Unable to set mappings */ 616 close(pipefd[1]); 617 exit(0); 618 } 619 620 /* Disable setgroups to allow gid mapping */ 621 write(setgroups_fd, "deny", 4); 622 close(setgroups_fd); 623 624 /* Map current uid/gid to root in the new namespace */ 625 char mapping[64]; 626 snprintf(mapping, sizeof(mapping), "0 %d 1", getuid()); 627 write(uid_map_fd, mapping, strlen(mapping)); 628 close(uid_map_fd); 629 630 snprintf(mapping, sizeof(mapping), "0 %d 1", getgid()); 631 write(gid_map_fd, mapping, strlen(mapping)); 632 close(gid_map_fd); 633 634 /* Now create new UTS namespace */ 635 ret = unshare(CLONE_NEWUTS); 636 if (ret < 0) { 637 write(pipefd[1], "N", 638 1); /* Unable to create UTS namespace */ 639 close(pipefd[1]); 640 exit(0); 641 } 642 643 /* Try to open parent's UTS namespace handle from new user+uts namespace */ 644 fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 645 646 if (fd >= 0) { 647 /* Should NOT succeed - we're in a different user namespace */ 648 write(pipefd[1], "S", 1); /* Unexpected success */ 649 close(fd); 650 } else if (errno == ESTALE) { 651 /* Expected: Stale file handle */ 652 write(pipefd[1], "P", 1); 653 } else { 654 /* Other error */ 655 write(pipefd[1], "F", 1); 656 } 657 658 close(pipefd[1]); 659 exit(0); 660 } 661 662 /* Parent process */ 663 close(pipefd[1]); 664 ASSERT_EQ(read(pipefd[0], &result, 1), 1); 665 666 waitpid(pid, &status, 0); 667 ASSERT_TRUE(WIFEXITED(status)); 668 ASSERT_EQ(WEXITSTATUS(status), 0); 669 670 if (result == 'U') { 671 SKIP(free(handle); close(pipefd[0]); 672 return, "Cannot create new user namespace"); 673 } 674 if (result == 'M') { 675 SKIP(free(handle); close(pipefd[0]); 676 return, "Cannot set uid/gid mappings"); 677 } 678 if (result == 'N') { 679 SKIP(free(handle); close(pipefd[0]); 680 return, "Cannot create new UTS namespace"); 681 } 682 683 /* Should fail with ESTALE since we're in a different user namespace */ 684 ASSERT_EQ(result, 'P'); 685 686 close(pipefd[0]); 687 free(handle); 688 } 689 690 TEST(nsfs_user_ipc_namespace_isolation) 691 { 692 struct file_handle *handle; 693 int mount_id; 694 int ret; 695 int fd; 696 int ns_fd; 697 pid_t pid; 698 int status; 699 int pipefd[2]; 700 char result; 701 702 handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 703 ASSERT_NE(handle, NULL); 704 705 /* Create pipe for communication */ 706 ASSERT_EQ(pipe(pipefd), 0); 707 708 /* Get handle for current IPC namespace */ 709 ns_fd = open("/proc/self/ns/ipc", O_RDONLY); 710 ASSERT_GE(ns_fd, 0); 711 712 handle->handle_bytes = MAX_HANDLE_SZ; 713 ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 714 if (ret < 0 && errno == EOPNOTSUPP) { 715 SKIP(free(handle); close(ns_fd); close(pipefd[0]); 716 close(pipefd[1]); 717 return, "nsfs doesn't support file handles"); 718 } 719 ASSERT_EQ(ret, 0); 720 close(ns_fd); 721 722 pid = fork(); 723 ASSERT_GE(pid, 0); 724 725 if (pid == 0) { 726 /* Child process */ 727 close(pipefd[0]); 728 729 /* First create new user namespace to drop privileges */ 730 ret = unshare(CLONE_NEWUSER); 731 if (ret < 0) { 732 write(pipefd[1], "U", 733 1); /* Unable to create user namespace */ 734 close(pipefd[1]); 735 exit(0); 736 } 737 738 /* Write uid/gid mappings to maintain some capabilities */ 739 int uid_map_fd = open("/proc/self/uid_map", O_WRONLY); 740 int gid_map_fd = open("/proc/self/gid_map", O_WRONLY); 741 int setgroups_fd = open("/proc/self/setgroups", O_WRONLY); 742 743 if (uid_map_fd < 0 || gid_map_fd < 0 || setgroups_fd < 0) { 744 write(pipefd[1], "M", 1); /* Unable to set mappings */ 745 close(pipefd[1]); 746 exit(0); 747 } 748 749 /* Disable setgroups to allow gid mapping */ 750 write(setgroups_fd, "deny", 4); 751 close(setgroups_fd); 752 753 /* Map current uid/gid to root in the new namespace */ 754 char mapping[64]; 755 snprintf(mapping, sizeof(mapping), "0 %d 1", getuid()); 756 write(uid_map_fd, mapping, strlen(mapping)); 757 close(uid_map_fd); 758 759 snprintf(mapping, sizeof(mapping), "0 %d 1", getgid()); 760 write(gid_map_fd, mapping, strlen(mapping)); 761 close(gid_map_fd); 762 763 /* Now create new IPC namespace */ 764 ret = unshare(CLONE_NEWIPC); 765 if (ret < 0) { 766 write(pipefd[1], "N", 767 1); /* Unable to create IPC namespace */ 768 close(pipefd[1]); 769 exit(0); 770 } 771 772 /* Try to open parent's IPC namespace handle from new user+ipc namespace */ 773 fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 774 775 if (fd >= 0) { 776 /* Should NOT succeed - we're in a different user namespace */ 777 write(pipefd[1], "S", 1); /* Unexpected success */ 778 close(fd); 779 } else if (errno == ESTALE) { 780 /* Expected: Stale file handle */ 781 write(pipefd[1], "P", 1); 782 } else { 783 /* Other error */ 784 write(pipefd[1], "F", 1); 785 } 786 787 close(pipefd[1]); 788 exit(0); 789 } 790 791 /* Parent process */ 792 close(pipefd[1]); 793 ASSERT_EQ(read(pipefd[0], &result, 1), 1); 794 795 waitpid(pid, &status, 0); 796 ASSERT_TRUE(WIFEXITED(status)); 797 ASSERT_EQ(WEXITSTATUS(status), 0); 798 799 if (result == 'U') { 800 SKIP(free(handle); close(pipefd[0]); 801 return, "Cannot create new user namespace"); 802 } 803 if (result == 'M') { 804 SKIP(free(handle); close(pipefd[0]); 805 return, "Cannot set uid/gid mappings"); 806 } 807 if (result == 'N') { 808 SKIP(free(handle); close(pipefd[0]); 809 return, "Cannot create new IPC namespace"); 810 } 811 812 /* Should fail with ESTALE since we're in a different user namespace */ 813 ASSERT_EQ(result, 'P'); 814 815 close(pipefd[0]); 816 free(handle); 817 } 818 819 TEST(nsfs_user_mnt_namespace_isolation) 820 { 821 struct file_handle *handle; 822 int mount_id; 823 int ret; 824 int fd; 825 int ns_fd; 826 pid_t pid; 827 int status; 828 int pipefd[2]; 829 char result; 830 831 handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 832 ASSERT_NE(handle, NULL); 833 834 /* Create pipe for communication */ 835 ASSERT_EQ(pipe(pipefd), 0); 836 837 /* Get handle for current mount namespace */ 838 ns_fd = open("/proc/self/ns/mnt", O_RDONLY); 839 ASSERT_GE(ns_fd, 0); 840 841 handle->handle_bytes = MAX_HANDLE_SZ; 842 ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 843 if (ret < 0 && errno == EOPNOTSUPP) { 844 SKIP(free(handle); close(ns_fd); close(pipefd[0]); 845 close(pipefd[1]); 846 return, "nsfs doesn't support file handles"); 847 } 848 ASSERT_EQ(ret, 0); 849 close(ns_fd); 850 851 pid = fork(); 852 ASSERT_GE(pid, 0); 853 854 if (pid == 0) { 855 /* Child process */ 856 close(pipefd[0]); 857 858 /* First create new user namespace to drop privileges */ 859 ret = unshare(CLONE_NEWUSER); 860 if (ret < 0) { 861 write(pipefd[1], "U", 862 1); /* Unable to create user namespace */ 863 close(pipefd[1]); 864 exit(0); 865 } 866 867 /* Write uid/gid mappings to maintain some capabilities */ 868 int uid_map_fd = open("/proc/self/uid_map", O_WRONLY); 869 int gid_map_fd = open("/proc/self/gid_map", O_WRONLY); 870 int setgroups_fd = open("/proc/self/setgroups", O_WRONLY); 871 872 if (uid_map_fd < 0 || gid_map_fd < 0 || setgroups_fd < 0) { 873 write(pipefd[1], "M", 1); /* Unable to set mappings */ 874 close(pipefd[1]); 875 exit(0); 876 } 877 878 /* Disable setgroups to allow gid mapping */ 879 write(setgroups_fd, "deny", 4); 880 close(setgroups_fd); 881 882 /* Map current uid/gid to root in the new namespace */ 883 char mapping[64]; 884 snprintf(mapping, sizeof(mapping), "0 %d 1", getuid()); 885 write(uid_map_fd, mapping, strlen(mapping)); 886 close(uid_map_fd); 887 888 snprintf(mapping, sizeof(mapping), "0 %d 1", getgid()); 889 write(gid_map_fd, mapping, strlen(mapping)); 890 close(gid_map_fd); 891 892 /* Now create new mount namespace */ 893 ret = unshare(CLONE_NEWNS); 894 if (ret < 0) { 895 write(pipefd[1], "N", 896 1); /* Unable to create mount namespace */ 897 close(pipefd[1]); 898 exit(0); 899 } 900 901 /* Try to open parent's mount namespace handle from new user+mnt namespace */ 902 fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 903 904 if (fd >= 0) { 905 /* Should NOT succeed - we're in a different user namespace */ 906 write(pipefd[1], "S", 1); /* Unexpected success */ 907 close(fd); 908 } else if (errno == ESTALE) { 909 /* Expected: Stale file handle */ 910 write(pipefd[1], "P", 1); 911 } else { 912 /* Other error */ 913 write(pipefd[1], "F", 1); 914 } 915 916 close(pipefd[1]); 917 exit(0); 918 } 919 920 /* Parent process */ 921 close(pipefd[1]); 922 ASSERT_EQ(read(pipefd[0], &result, 1), 1); 923 924 waitpid(pid, &status, 0); 925 ASSERT_TRUE(WIFEXITED(status)); 926 ASSERT_EQ(WEXITSTATUS(status), 0); 927 928 if (result == 'U') { 929 SKIP(free(handle); close(pipefd[0]); 930 return, "Cannot create new user namespace"); 931 } 932 if (result == 'M') { 933 SKIP(free(handle); close(pipefd[0]); 934 return, "Cannot set uid/gid mappings"); 935 } 936 if (result == 'N') { 937 SKIP(free(handle); close(pipefd[0]); 938 return, "Cannot create new mount namespace"); 939 } 940 941 /* Should fail with ESTALE since we're in a different user namespace */ 942 ASSERT_EQ(result, 'P'); 943 944 close(pipefd[0]); 945 free(handle); 946 } 947 948 TEST(nsfs_user_cgroup_namespace_isolation) 949 { 950 struct file_handle *handle; 951 int mount_id; 952 int ret; 953 int fd; 954 int ns_fd; 955 pid_t pid; 956 int status; 957 int pipefd[2]; 958 char result; 959 960 handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 961 ASSERT_NE(handle, NULL); 962 963 /* Create pipe for communication */ 964 ASSERT_EQ(pipe(pipefd), 0); 965 966 /* Get handle for current cgroup namespace */ 967 ns_fd = open("/proc/self/ns/cgroup", O_RDONLY); 968 if (ns_fd < 0) { 969 SKIP(free(handle); close(pipefd[0]); close(pipefd[1]); 970 return, "cgroup namespace not available"); 971 } 972 973 handle->handle_bytes = MAX_HANDLE_SZ; 974 ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 975 if (ret < 0 && errno == EOPNOTSUPP) { 976 SKIP(free(handle); close(ns_fd); close(pipefd[0]); 977 close(pipefd[1]); 978 return, "nsfs doesn't support file handles"); 979 } 980 ASSERT_EQ(ret, 0); 981 close(ns_fd); 982 983 pid = fork(); 984 ASSERT_GE(pid, 0); 985 986 if (pid == 0) { 987 /* Child process */ 988 close(pipefd[0]); 989 990 /* First create new user namespace to drop privileges */ 991 ret = unshare(CLONE_NEWUSER); 992 if (ret < 0) { 993 write(pipefd[1], "U", 994 1); /* Unable to create user namespace */ 995 close(pipefd[1]); 996 exit(0); 997 } 998 999 /* Write uid/gid mappings to maintain some capabilities */ 1000 int uid_map_fd = open("/proc/self/uid_map", O_WRONLY); 1001 int gid_map_fd = open("/proc/self/gid_map", O_WRONLY); 1002 int setgroups_fd = open("/proc/self/setgroups", O_WRONLY); 1003 1004 if (uid_map_fd < 0 || gid_map_fd < 0 || setgroups_fd < 0) { 1005 write(pipefd[1], "M", 1); /* Unable to set mappings */ 1006 close(pipefd[1]); 1007 exit(0); 1008 } 1009 1010 /* Disable setgroups to allow gid mapping */ 1011 write(setgroups_fd, "deny", 4); 1012 close(setgroups_fd); 1013 1014 /* Map current uid/gid to root in the new namespace */ 1015 char mapping[64]; 1016 snprintf(mapping, sizeof(mapping), "0 %d 1", getuid()); 1017 write(uid_map_fd, mapping, strlen(mapping)); 1018 close(uid_map_fd); 1019 1020 snprintf(mapping, sizeof(mapping), "0 %d 1", getgid()); 1021 write(gid_map_fd, mapping, strlen(mapping)); 1022 close(gid_map_fd); 1023 1024 /* Now create new cgroup namespace */ 1025 ret = unshare(CLONE_NEWCGROUP); 1026 if (ret < 0) { 1027 write(pipefd[1], "N", 1028 1); /* Unable to create cgroup namespace */ 1029 close(pipefd[1]); 1030 exit(0); 1031 } 1032 1033 /* Try to open parent's cgroup namespace handle from new user+cgroup namespace */ 1034 fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 1035 1036 if (fd >= 0) { 1037 /* Should NOT succeed - we're in a different user namespace */ 1038 write(pipefd[1], "S", 1); /* Unexpected success */ 1039 close(fd); 1040 } else if (errno == ESTALE) { 1041 /* Expected: Stale file handle */ 1042 write(pipefd[1], "P", 1); 1043 } else { 1044 /* Other error */ 1045 write(pipefd[1], "F", 1); 1046 } 1047 1048 close(pipefd[1]); 1049 exit(0); 1050 } 1051 1052 /* Parent process */ 1053 close(pipefd[1]); 1054 ASSERT_EQ(read(pipefd[0], &result, 1), 1); 1055 1056 waitpid(pid, &status, 0); 1057 ASSERT_TRUE(WIFEXITED(status)); 1058 ASSERT_EQ(WEXITSTATUS(status), 0); 1059 1060 if (result == 'U') { 1061 SKIP(free(handle); close(pipefd[0]); 1062 return, "Cannot create new user namespace"); 1063 } 1064 if (result == 'M') { 1065 SKIP(free(handle); close(pipefd[0]); 1066 return, "Cannot set uid/gid mappings"); 1067 } 1068 if (result == 'N') { 1069 SKIP(free(handle); close(pipefd[0]); 1070 return, "Cannot create new cgroup namespace"); 1071 } 1072 1073 /* Should fail with ESTALE since we're in a different user namespace */ 1074 ASSERT_EQ(result, 'P'); 1075 1076 close(pipefd[0]); 1077 free(handle); 1078 } 1079 1080 TEST(nsfs_user_pid_namespace_isolation) 1081 { 1082 struct file_handle *handle; 1083 int mount_id; 1084 int ret; 1085 int fd; 1086 int ns_fd; 1087 pid_t pid; 1088 int status; 1089 int pipefd[2]; 1090 char result; 1091 1092 handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 1093 ASSERT_NE(handle, NULL); 1094 1095 /* Create pipe for communication */ 1096 ASSERT_EQ(pipe(pipefd), 0); 1097 1098 /* Get handle for current PID namespace */ 1099 ns_fd = open("/proc/self/ns/pid", O_RDONLY); 1100 ASSERT_GE(ns_fd, 0); 1101 1102 handle->handle_bytes = MAX_HANDLE_SZ; 1103 ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 1104 if (ret < 0 && errno == EOPNOTSUPP) { 1105 SKIP(free(handle); close(ns_fd); close(pipefd[0]); 1106 close(pipefd[1]); 1107 return, "nsfs doesn't support file handles"); 1108 } 1109 ASSERT_EQ(ret, 0); 1110 close(ns_fd); 1111 1112 pid = fork(); 1113 ASSERT_GE(pid, 0); 1114 1115 if (pid == 0) { 1116 /* Child process */ 1117 close(pipefd[0]); 1118 1119 /* First create new user namespace to drop privileges */ 1120 ret = unshare(CLONE_NEWUSER); 1121 if (ret < 0) { 1122 write(pipefd[1], "U", 1123 1); /* Unable to create user namespace */ 1124 close(pipefd[1]); 1125 exit(0); 1126 } 1127 1128 /* Write uid/gid mappings to maintain some capabilities */ 1129 int uid_map_fd = open("/proc/self/uid_map", O_WRONLY); 1130 int gid_map_fd = open("/proc/self/gid_map", O_WRONLY); 1131 int setgroups_fd = open("/proc/self/setgroups", O_WRONLY); 1132 1133 if (uid_map_fd < 0 || gid_map_fd < 0 || setgroups_fd < 0) { 1134 write(pipefd[1], "M", 1); /* Unable to set mappings */ 1135 close(pipefd[1]); 1136 exit(0); 1137 } 1138 1139 /* Disable setgroups to allow gid mapping */ 1140 write(setgroups_fd, "deny", 4); 1141 close(setgroups_fd); 1142 1143 /* Map current uid/gid to root in the new namespace */ 1144 char mapping[64]; 1145 snprintf(mapping, sizeof(mapping), "0 %d 1", getuid()); 1146 write(uid_map_fd, mapping, strlen(mapping)); 1147 close(uid_map_fd); 1148 1149 snprintf(mapping, sizeof(mapping), "0 %d 1", getgid()); 1150 write(gid_map_fd, mapping, strlen(mapping)); 1151 close(gid_map_fd); 1152 1153 /* Now create new PID namespace - requires fork to take effect */ 1154 ret = unshare(CLONE_NEWPID); 1155 if (ret < 0) { 1156 write(pipefd[1], "N", 1157 1); /* Unable to create PID namespace */ 1158 close(pipefd[1]); 1159 exit(0); 1160 } 1161 1162 /* Fork again for PID namespace to take effect */ 1163 pid_t child_pid = fork(); 1164 if (child_pid < 0) { 1165 write(pipefd[1], "N", 1166 1); /* Unable to fork in PID namespace */ 1167 close(pipefd[1]); 1168 exit(0); 1169 } 1170 1171 if (child_pid == 0) { 1172 /* Grandchild in new PID namespace */ 1173 /* Try to open parent's PID namespace handle from new user+pid namespace */ 1174 fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 1175 1176 if (fd >= 0) { 1177 /* Should NOT succeed - we're in a different user namespace */ 1178 write(pipefd[1], "S", 1179 1); /* Unexpected success */ 1180 close(fd); 1181 } else if (errno == ESTALE) { 1182 /* Expected: Stale file handle */ 1183 write(pipefd[1], "P", 1); 1184 } else { 1185 /* Other error */ 1186 write(pipefd[1], "F", 1); 1187 } 1188 1189 close(pipefd[1]); 1190 exit(0); 1191 } 1192 1193 /* Wait for grandchild */ 1194 waitpid(child_pid, NULL, 0); 1195 exit(0); 1196 } 1197 1198 /* Parent process */ 1199 close(pipefd[1]); 1200 ASSERT_EQ(read(pipefd[0], &result, 1), 1); 1201 1202 waitpid(pid, &status, 0); 1203 ASSERT_TRUE(WIFEXITED(status)); 1204 ASSERT_EQ(WEXITSTATUS(status), 0); 1205 1206 if (result == 'U') { 1207 SKIP(free(handle); close(pipefd[0]); 1208 return, "Cannot create new user namespace"); 1209 } 1210 if (result == 'M') { 1211 SKIP(free(handle); close(pipefd[0]); 1212 return, "Cannot set uid/gid mappings"); 1213 } 1214 if (result == 'N') { 1215 SKIP(free(handle); close(pipefd[0]); 1216 return, "Cannot create new PID namespace"); 1217 } 1218 1219 /* Should fail with ESTALE since we're in a different user namespace */ 1220 ASSERT_EQ(result, 'P'); 1221 1222 close(pipefd[0]); 1223 free(handle); 1224 } 1225 1226 TEST(nsfs_user_time_namespace_isolation) 1227 { 1228 struct file_handle *handle; 1229 int mount_id; 1230 int ret; 1231 int fd; 1232 int ns_fd; 1233 pid_t pid; 1234 int status; 1235 int pipefd[2]; 1236 char result; 1237 1238 handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 1239 ASSERT_NE(handle, NULL); 1240 1241 /* Create pipe for communication */ 1242 ASSERT_EQ(pipe(pipefd), 0); 1243 1244 /* Get handle for current time namespace */ 1245 ns_fd = open("/proc/self/ns/time", O_RDONLY); 1246 if (ns_fd < 0) { 1247 SKIP(free(handle); close(pipefd[0]); close(pipefd[1]); 1248 return, "time namespace not available"); 1249 } 1250 1251 handle->handle_bytes = MAX_HANDLE_SZ; 1252 ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 1253 if (ret < 0 && errno == EOPNOTSUPP) { 1254 SKIP(free(handle); close(ns_fd); close(pipefd[0]); 1255 close(pipefd[1]); 1256 return, "nsfs doesn't support file handles"); 1257 } 1258 ASSERT_EQ(ret, 0); 1259 close(ns_fd); 1260 1261 pid = fork(); 1262 ASSERT_GE(pid, 0); 1263 1264 if (pid == 0) { 1265 /* Child process */ 1266 close(pipefd[0]); 1267 1268 /* First create new user namespace to drop privileges */ 1269 ret = unshare(CLONE_NEWUSER); 1270 if (ret < 0) { 1271 write(pipefd[1], "U", 1272 1); /* Unable to create user namespace */ 1273 close(pipefd[1]); 1274 exit(0); 1275 } 1276 1277 /* Write uid/gid mappings to maintain some capabilities */ 1278 int uid_map_fd = open("/proc/self/uid_map", O_WRONLY); 1279 int gid_map_fd = open("/proc/self/gid_map", O_WRONLY); 1280 int setgroups_fd = open("/proc/self/setgroups", O_WRONLY); 1281 1282 if (uid_map_fd < 0 || gid_map_fd < 0 || setgroups_fd < 0) { 1283 write(pipefd[1], "M", 1); /* Unable to set mappings */ 1284 close(pipefd[1]); 1285 exit(0); 1286 } 1287 1288 /* Disable setgroups to allow gid mapping */ 1289 write(setgroups_fd, "deny", 4); 1290 close(setgroups_fd); 1291 1292 /* Map current uid/gid to root in the new namespace */ 1293 char mapping[64]; 1294 snprintf(mapping, sizeof(mapping), "0 %d 1", getuid()); 1295 write(uid_map_fd, mapping, strlen(mapping)); 1296 close(uid_map_fd); 1297 1298 snprintf(mapping, sizeof(mapping), "0 %d 1", getgid()); 1299 write(gid_map_fd, mapping, strlen(mapping)); 1300 close(gid_map_fd); 1301 1302 /* Now create new time namespace - requires fork to take effect */ 1303 ret = unshare(CLONE_NEWTIME); 1304 if (ret < 0) { 1305 write(pipefd[1], "N", 1306 1); /* Unable to create time namespace */ 1307 close(pipefd[1]); 1308 exit(0); 1309 } 1310 1311 /* Fork again for time namespace to take effect */ 1312 pid_t child_pid = fork(); 1313 if (child_pid < 0) { 1314 write(pipefd[1], "N", 1315 1); /* Unable to fork in time namespace */ 1316 close(pipefd[1]); 1317 exit(0); 1318 } 1319 1320 if (child_pid == 0) { 1321 /* Grandchild in new time namespace */ 1322 /* Try to open parent's time namespace handle from new user+time namespace */ 1323 fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 1324 1325 if (fd >= 0) { 1326 /* Should NOT succeed - we're in a different user namespace */ 1327 write(pipefd[1], "S", 1328 1); /* Unexpected success */ 1329 close(fd); 1330 } else if (errno == ESTALE) { 1331 /* Expected: Stale file handle */ 1332 write(pipefd[1], "P", 1); 1333 } else { 1334 /* Other error */ 1335 write(pipefd[1], "F", 1); 1336 } 1337 1338 close(pipefd[1]); 1339 exit(0); 1340 } 1341 1342 /* Wait for grandchild */ 1343 waitpid(child_pid, NULL, 0); 1344 exit(0); 1345 } 1346 1347 /* Parent process */ 1348 close(pipefd[1]); 1349 ASSERT_EQ(read(pipefd[0], &result, 1), 1); 1350 1351 waitpid(pid, &status, 0); 1352 ASSERT_TRUE(WIFEXITED(status)); 1353 ASSERT_EQ(WEXITSTATUS(status), 0); 1354 1355 if (result == 'U') { 1356 SKIP(free(handle); close(pipefd[0]); 1357 return, "Cannot create new user namespace"); 1358 } 1359 if (result == 'M') { 1360 SKIP(free(handle); close(pipefd[0]); 1361 return, "Cannot set uid/gid mappings"); 1362 } 1363 if (result == 'N') { 1364 SKIP(free(handle); close(pipefd[0]); 1365 return, "Cannot create new time namespace"); 1366 } 1367 1368 /* Should fail with ESTALE since we're in a different user namespace */ 1369 ASSERT_EQ(result, 'P'); 1370 1371 close(pipefd[0]); 1372 free(handle); 1373 } 1374 1375 TEST(nsfs_open_flags) 1376 { 1377 struct file_handle *handle; 1378 int mount_id; 1379 int ret; 1380 int fd; 1381 int ns_fd; 1382 1383 handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 1384 ASSERT_NE(handle, NULL); 1385 1386 /* Open a namespace file descriptor */ 1387 ns_fd = open("/proc/self/ns/net", O_RDONLY); 1388 ASSERT_GE(ns_fd, 0); 1389 1390 /* Get handle for the namespace */ 1391 handle->handle_bytes = MAX_HANDLE_SZ; 1392 ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 1393 if (ret < 0 && errno == EOPNOTSUPP) { 1394 SKIP(free(handle); close(ns_fd); 1395 return, "nsfs doesn't support file handles"); 1396 } 1397 ASSERT_EQ(ret, 0); 1398 ASSERT_GT(handle->handle_bytes, 0); 1399 1400 /* Test invalid flags that should fail */ 1401 fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_WRONLY); 1402 ASSERT_LT(fd, 0); 1403 ASSERT_EQ(errno, EPERM); 1404 1405 fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDWR); 1406 ASSERT_LT(fd, 0); 1407 ASSERT_EQ(errno, EPERM); 1408 1409 fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_TRUNC); 1410 ASSERT_LT(fd, 0); 1411 ASSERT_EQ(errno, EPERM); 1412 1413 fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_DIRECT); 1414 ASSERT_LT(fd, 0); 1415 ASSERT_EQ(errno, EINVAL); 1416 1417 fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_TMPFILE); 1418 ASSERT_LT(fd, 0); 1419 ASSERT_EQ(errno, EINVAL); 1420 1421 fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_DIRECTORY); 1422 ASSERT_LT(fd, 0); 1423 ASSERT_EQ(errno, ENOTDIR); 1424 1425 close(ns_fd); 1426 free(handle); 1427 } 1428 1429 TEST_HARNESS_MAIN 1430