pidns.c 1.7 KB

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