From ce003e5d4cd94c5380699b0dadeaaf825813afbe Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Fri, 17 Nov 2017 22:11:28 +0100 Subject: support_become_root: Enable file creation in user namespaces Without UID/GID maps, file creation will file with EOVERFLOW. This patch is based on DJ Delorie's work on container testing. Reviewed-by: Jonathan Nieder --- support/support_become_root.c | 57 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 3 deletions(-) (limited to 'support') 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 +#include #include #include +#include +#include +#include #include +#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) { -- cgit v1.2.3