diff options
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | support/support_become_root.c | 57 |
2 files changed, 60 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog index 4ab52b2fd9..a5530971a0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2017-11-17 Florian Weimer <fweimer@redhat.com> + + support_become_root: Enable file creation in namespaces. + * support/support_become_root.c (setup_mapping): New function. + (support_become_root): Call it. + 2017-11-17 Joseph Myers <joseph@codesourcery.com> * sysdeps/unix/sysv/linux/aarch64/bits/hwcap.h (HWCAP_DCPOP): New diff --git a/support/support_become_root.c b/support/support_become_root.c index 3fa0bd4ac0..5086570251 100644 --- a/support/support_become_root.c +++ b/support/support_become_root.c @@ -18,18 +18,69 @@ #include <support/namespace.h> +#include <fcntl.h> #include <sched.h> #include <stdio.h> +#include <string.h> +#include <support/check.h> +#include <support/xunistd.h> #include <unistd.h> +#ifdef CLONE_NEWUSER +/* The necessary steps to allow file creation in user namespaces. */ +static void +setup_uid_gid_mapping (uid_t original_uid, gid_t original_gid) +{ + int fd = open64 ("/proc/self/uid_map", O_WRONLY); + if (fd < 0) + { + printf ("warning: could not open /proc/self/uid_map: %m\n" + "warning: file creation may not be possible\n"); + return; + } + + /* We map our original UID to the same UID in the container so we + own our own files normally. Without that, file creation could + fail with EOVERFLOW (sic!). */ + char buf[100]; + int ret = snprintf (buf, sizeof (buf), "%llu %llu 1\n", + (unsigned long long) original_uid, + (unsigned long long) original_uid); + TEST_VERIFY_EXIT (ret < sizeof (buf)); + xwrite (fd, buf, ret); + xclose (fd); + + /* Disable setgroups before mapping groups, otherwise that would + fail with EPERM. */ + fd = xopen ("/proc/self/setgroups", O_WRONLY, 0); + xwrite (fd, "deny\n", strlen ("deny\n")); + xclose (fd); + + /* Now map our own GID, like we did for the user ID. */ + fd = xopen ("/proc/self/gid_map", O_WRONLY, 0); + ret = snprintf (buf, sizeof (buf), "%llu %llu 1\n", + (unsigned long long) original_gid, + (unsigned long long) original_gid); + TEST_VERIFY_EXIT (ret < sizeof (buf)); + xwrite (fd, buf, ret); + xclose (fd); +} +#endif /* CLONE_NEWUSER */ + bool support_become_root (void) { #ifdef CLONE_NEWUSER + uid_t original_uid = getuid (); + gid_t original_gid = getgid (); + if (unshare (CLONE_NEWUSER | CLONE_NEWNS) == 0) - /* Even if we do not have UID zero, we have extended privileges at - this point. */ - return true; + { + setup_uid_gid_mapping (original_uid, original_gid); + /* Even if we do not have UID zero, we have extended privileges at + this point. */ + return true; + } #endif if (setuid (0) != 0) { |