Blame support/support_become_root.c

Packit 6c4009
/* Acquire root privileges.
Packit 6c4009
   Copyright (C) 2016-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <support/namespace.h>
Packit 6c4009
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <fcntl.h>
Packit 6c4009
#include <sched.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <support/check.h>
Packit 6c4009
#include <support/xunistd.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
Packit 6c4009
#ifdef CLONE_NEWUSER
Packit 6c4009
/* The necessary steps to allow file creation in user namespaces.  */
Packit 6c4009
static void
Packit 6c4009
setup_uid_gid_mapping (uid_t original_uid, gid_t original_gid)
Packit 6c4009
{
Packit 6c4009
  int fd = open64 ("/proc/self/uid_map", O_WRONLY);
Packit 6c4009
  if (fd < 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("warning: could not open /proc/self/uid_map: %m\n"
Packit 6c4009
              "warning: file creation may not be possible\n");
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* We map our original UID to the same UID in the container so we
Packit 6c4009
     own our own files normally.  Without that, file creation could
Packit 6c4009
     fail with EOVERFLOW (sic!).  */
Packit 6c4009
  char buf[100];
Packit 6c4009
  int ret = snprintf (buf, sizeof (buf), "%llu %llu 1\n",
Packit 6c4009
                      (unsigned long long) original_uid,
Packit 6c4009
                      (unsigned long long) original_uid);
Packit 6c4009
  TEST_VERIFY_EXIT (ret < sizeof (buf));
Packit 6c4009
  xwrite (fd, buf, ret);
Packit 6c4009
  xclose (fd);
Packit 6c4009
Packit 6c4009
  /* Linux 3.19 introduced the setgroups file.  We need write "deny" to this
Packit 6c4009
     file otherwise writing to gid_map will fail with EPERM.  */
Packit 6c4009
  fd = open64 ("/proc/self/setgroups", O_WRONLY, 0);
Packit 6c4009
  if (fd < 0)
Packit 6c4009
    {
Packit 6c4009
      if (errno != ENOENT)
Packit 6c4009
        FAIL_EXIT1 ("open64 (\"/proc/self/setgroups\", 0x%x, 0%o): %m",
Packit 6c4009
                    O_WRONLY, 0);
Packit 6c4009
      /* This kernel doesn't expose the setgroups file so simply move on.  */
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      xwrite (fd, "deny\n", strlen ("deny\n"));
Packit 6c4009
      xclose (fd);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Now map our own GID, like we did for the user ID.  */
Packit 6c4009
  fd = xopen ("/proc/self/gid_map", O_WRONLY, 0);
Packit 6c4009
  ret = snprintf (buf, sizeof (buf), "%llu %llu 1\n",
Packit 6c4009
                  (unsigned long long) original_gid,
Packit 6c4009
                  (unsigned long long) original_gid);
Packit 6c4009
  TEST_VERIFY_EXIT (ret < sizeof (buf));
Packit 6c4009
  xwrite (fd, buf, ret);
Packit 6c4009
  xclose (fd);
Packit 6c4009
}
Packit 6c4009
#endif /* CLONE_NEWUSER */
Packit 6c4009
Packit 6c4009
bool
Packit 6c4009
support_become_root (void)
Packit 6c4009
{
Packit 6c4009
#ifdef CLONE_NEWUSER
Packit 6c4009
  uid_t original_uid = getuid ();
Packit 6c4009
  gid_t original_gid = getgid ();
Packit 6c4009
Packit 6c4009
  if (unshare (CLONE_NEWUSER | CLONE_NEWNS) == 0)
Packit 6c4009
    {
Packit 6c4009
      setup_uid_gid_mapping (original_uid, original_gid);
Packit 6c4009
      /* Even if we do not have UID zero, we have extended privileges at
Packit 6c4009
         this point.  */
Packit 6c4009
      return true;
Packit 6c4009
    }
Packit 6c4009
#endif
Packit 6c4009
  if (setuid (0) != 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("warning: could not become root outside namespace (%m)\n");
Packit 6c4009
      return false;
Packit 6c4009
    }
Packit 6c4009
  return true;
Packit 6c4009
}