[Toybox] [PATCH] unshare: fix -r

Samuel Holland samuel at sholland.net
Sun Apr 12 11:52:52 PDT 2015


Calling unshare(2) immediately puts us in the new namespace
with the "overflow" user and group ID. By calling geteuid()
and getegid() in handle_r() after calling unshare(), we try
to map that to root, which Linux refuses to let us do.

What we really want to map to root is the caller's uid/gid
in the original namespace. So we have to save them before
calling unshare().
---
  toys/other/nsenter.c | 39 +++++++++++++++++++--------------------
  1 file changed, 19 insertions(+), 20 deletions(-)

diff --git a/toys/other/nsenter.c b/toys/other/nsenter.c
index d0a5cd6..18a2cd2 100644
--- a/toys/other/nsenter.c
+++ b/toys/other/nsenter.c
@@ -79,31 +79,27 @@ GLOBALS(
  static void write_ugid_map(char *map, unsigned eugid)
  {
    int bytes = sprintf(toybuf, "0 %u 1", eugid), fd = xopen(map, O_WRONLY);
-
+
    xwrite(fd, toybuf, bytes);
    xclose(fd);
  }

-
-static int handle_r(int test)
+static void handle_r(int euid, int egid)
  {
    int fd;

-  if (!CFG_UNSHARE || !(toys.optflags & FLAG_r) || *toys.which->name!='u')
-    return 0;
-  if (!test) return 1;
-
-  if (toys.optflags & FLAG_r) {
-    if ((fd = open("/proc/self/setgroups", O_WRONLY)) >= 0) {
-      xwrite(fd, "deny", 4);
-      close(fd);
-    }
-
-    write_ugid_map("/proc/self/uid_map", geteuid());
-    write_ugid_map("/proc/self/gid_map", getegid());
+  if ((fd = open("/proc/self/setgroups", O_WRONLY)) >= 0) {
+    xwrite(fd, "deny", 4);
+    close(fd);
    }

-  return 0;
+  write_ugid_map("/proc/self/uid_map", euid);
+  write_ugid_map("/proc/self/gid_map", egid);
+}
+
+static int test_r()
+{
+  return toys.optflags & FLAG_r;
  }

  // Shift back to the context GLOBALS lives in (I.E. matching the 
filename).
@@ -117,16 +113,19 @@ void unshare_main(void)
                      CLONE_NEWNS, CLONE_NEWIPC}, f = 0;
    int i, fd;

-  // unshare -U does not imply -r, so we cannot use [+rU]
-  if (handle_r(0))  toys.optflags |= FLAG_U;
-
    // Create new namespace(s)?
    if (CFG_UNSHARE && *toys.which->name=='u') {
+    // For -r, we have to save our original [ug]id before calling unshare()
+    int euid = geteuid(), egid = getegid();
+
+    // unshare -U does not imply -r, so we cannot use [+rU]
+    if (test_r()) toys.optflags |= FLAG_U;
+
      for (i = 0; i<ARRAY_LEN(flags); i++)
        if (toys.optflags & (1<<i)) f |= flags[i];

      if (unshare(f)) perror_exit(0);
-    handle_r(1);
+    if (test_r()) handle_r(euid, egid);

    // Bind to existing namespace(s)?
    } else if (CFG_NSENTER) {
-- 
2.2.1



More information about the Toybox mailing list