support_become_root.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. /* Acquire root privileges.
  2. Copyright (C) 2016-2019 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <http://www.gnu.org/licenses/>. */
  15. #include <support/namespace.h>
  16. #include <errno.h>
  17. #include <fcntl.h>
  18. #include <sched.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <support/check.h>
  22. #include <support/xunistd.h>
  23. #include <unistd.h>
  24. #ifdef CLONE_NEWUSER
  25. /* The necessary steps to allow file creation in user namespaces. */
  26. static void
  27. setup_uid_gid_mapping (uid_t original_uid, gid_t original_gid)
  28. {
  29. int fd = open64 ("/proc/self/uid_map", O_WRONLY);
  30. if (fd < 0)
  31. {
  32. printf ("warning: could not open /proc/self/uid_map: %m\n"
  33. "warning: file creation may not be possible\n");
  34. return;
  35. }
  36. /* We map our original UID to the same UID in the container so we
  37. own our own files normally. Without that, file creation could
  38. fail with EOVERFLOW (sic!). */
  39. char buf[100];
  40. int ret = snprintf (buf, sizeof (buf), "%llu %llu 1\n",
  41. (unsigned long long) original_uid,
  42. (unsigned long long) original_uid);
  43. TEST_VERIFY_EXIT (ret < sizeof (buf));
  44. xwrite (fd, buf, ret);
  45. xclose (fd);
  46. /* Linux 3.19 introduced the setgroups file. We need write "deny" to this
  47. file otherwise writing to gid_map will fail with EPERM. */
  48. fd = open64 ("/proc/self/setgroups", O_WRONLY, 0);
  49. if (fd < 0)
  50. {
  51. if (errno != ENOENT)
  52. FAIL_EXIT1 ("open64 (\"/proc/self/setgroups\", 0x%x, 0%o): %m",
  53. O_WRONLY, 0);
  54. /* This kernel doesn't expose the setgroups file so simply move on. */
  55. }
  56. else
  57. {
  58. xwrite (fd, "deny\n", strlen ("deny\n"));
  59. xclose (fd);
  60. }
  61. /* Now map our own GID, like we did for the user ID. */
  62. fd = xopen ("/proc/self/gid_map", O_WRONLY, 0);
  63. ret = snprintf (buf, sizeof (buf), "%llu %llu 1\n",
  64. (unsigned long long) original_gid,
  65. (unsigned long long) original_gid);
  66. TEST_VERIFY_EXIT (ret < sizeof (buf));
  67. xwrite (fd, buf, ret);
  68. xclose (fd);
  69. }
  70. #endif /* CLONE_NEWUSER */
  71. bool
  72. support_become_root (void)
  73. {
  74. #ifdef CLONE_NEWUSER
  75. uid_t original_uid = getuid ();
  76. gid_t original_gid = getgid ();
  77. if (unshare (CLONE_NEWUSER | CLONE_NEWNS) == 0)
  78. {
  79. setup_uid_gid_mapping (original_uid, original_gid);
  80. /* Even if we do not have UID zero, we have extended privileges at
  81. this point. */
  82. return true;
  83. }
  84. #endif
  85. if (setuid (0) != 0)
  86. {
  87. printf ("warning: could not become root outside namespace (%m)\n");
  88. return false;
  89. }
  90. return true;
  91. }