pidns.c 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. // SPDX-License-Identifier: GPL-2.0
  2. #define _GNU_SOURCE
  3. #include <sched.h>
  4. #include <unistd.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <signal.h>
  8. #include <errno.h>
  9. #include <sys/types.h>
  10. #include <sys/stat.h>
  11. #include <fcntl.h>
  12. #include <sys/ioctl.h>
  13. #include <sys/prctl.h>
  14. #include <sys/wait.h>
  15. #define pr_err(fmt, ...) \
  16. ({ \
  17. fprintf(stderr, "%s:%d:" fmt ": %m\n", \
  18. __func__, __LINE__, ##__VA_ARGS__); \
  19. 1; \
  20. })
  21. #define NSIO 0xb7
  22. #define NS_GET_USERNS _IO(NSIO, 0x1)
  23. #define NS_GET_PARENT _IO(NSIO, 0x2)
  24. #define __stack_aligned__ __attribute__((aligned(16)))
  25. struct cr_clone_arg {
  26. char stack[128] __stack_aligned__;
  27. char stack_ptr[0];
  28. };
  29. static int child(void *args)
  30. {
  31. prctl(PR_SET_PDEATHSIG, SIGKILL);
  32. while (1)
  33. sleep(1);
  34. exit(0);
  35. }
  36. int main(int argc, char *argv[])
  37. {
  38. char *ns_strs[] = {"pid", "user"};
  39. char path[] = "/proc/0123456789/ns/pid";
  40. struct cr_clone_arg ca;
  41. struct stat st1, st2;
  42. int ns, pns, i;
  43. pid_t pid;
  44. pid = clone(child, ca.stack_ptr, CLONE_NEWUSER | CLONE_NEWPID | SIGCHLD, NULL);
  45. if (pid < 0)
  46. return pr_err("clone");
  47. for (i = 0; i < 2; i++) {
  48. snprintf(path, sizeof(path), "/proc/%d/ns/%s", pid, ns_strs[i]);
  49. ns = open(path, O_RDONLY);
  50. if (ns < 0)
  51. return pr_err("Unable to open %s", path);
  52. pns = ioctl(ns, NS_GET_PARENT);
  53. if (pns < 0)
  54. return pr_err("Unable to get a parent pidns");
  55. snprintf(path, sizeof(path), "/proc/self/ns/%s", ns_strs[i]);
  56. if (stat(path, &st2))
  57. return pr_err("Unable to stat %s", path);
  58. if (fstat(pns, &st1))
  59. return pr_err("Unable to stat the parent pidns");
  60. if (st1.st_ino != st2.st_ino)
  61. return pr_err("NS_GET_PARENT returned a wrong namespace");
  62. if (ioctl(pns, NS_GET_PARENT) >= 0 || errno != EPERM)
  63. return pr_err("Don't get EPERM");
  64. }
  65. kill(pid, SIGKILL);
  66. wait(NULL);
  67. return 0;
  68. }