unshare -r runs a command in a new PID namespace where the user is root.
(In other words, uid:gid 0:0)

geteuid()/getegid() will return (short)-1 if called after unshare(),
notwithstanding the documentation.

This is useful for making an archive that purports to belong to root,
fooling programs that don't need global root, and similar tricks;
for example, to create an initrd:
find . |unshare -r cpio -o -H newc |gzip -9c > ../initrd
---
 toys/other/unshare.c | 32 ++++++++++++++++++++++++++++----
 1 file changed, 28 insertions(+), 4 deletions(-)

diff --git a/toys/other/unshare.c b/toys/other/unshare.c
index 68c1ebd..4230848 100644
--- a/toys/other/unshare.c
+++ b/toys/other/unshare.c
@@ -2,14 +2,14 @@
  *
  * Copyright 2011 Rob Landley <[email protected]>
 
-USE_UNSHARE(NEWTOY(unshare, "<1^imnpuU", TOYFLAG_USR|TOYFLAG_BIN))
+USE_UNSHARE(NEWTOY(unshare, "<1^rimnpuU", TOYFLAG_USR|TOYFLAG_BIN))
 
 config UNSHARE
   bool "unshare"
   default y
   depends on TOYBOX_CONTAINER
   help
-    usage: unshare [-imnpuU] COMMAND...
+    usage: unshare [-imnpuUr] COMMAND...
 
     Create new namespace(s) for this process and its children, so some
     attribute is not shared with the parent process.  This is part of
@@ -21,22 +21,46 @@ config UNSHARE
     -p Process IDs and init
     -u Host and domain names
     -U UIDs, GIDs, capabilities
+
+    Other options:
+    -r Map current euid/egid to 0/0 (implies -U)
 */
 
+#define FOR_unshare
 #include "toys.h"
 #include <linux/sched.h>
 extern int unshare (int __flags);
 
+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);
+}
+
 void unshare_main(void)
 {
   unsigned flags[]={CLONE_NEWUSER, CLONE_NEWUTS, CLONE_NEWPID, CLONE_NEWNET,
                     CLONE_NEWNS, CLONE_NEWIPC, 0};
-  unsigned f=0;
-  int i;
+  unsigned f=0, euid = geteuid(), egid = getegid();
+  int i, fd;
+
+  // -U does not imply -r, so we cannot use [+rU]
+  if (toys.optflags & FLAG_r)  toys.optflags |= FLAG_U;
 
   for (i=0; flags[i]; i++) if (toys.optflags & (1<<i)) f |= flags[i];
 
   if (unshare(f)) perror_exit("failed");
 
+  if (toys.optflags & FLAG_r) {
+    if (-1 < (fd = open("/proc/self/setgroups", O_WRONLY))) {
+      xwrite(fd, "deny", 4);
+      close(fd);
+    }
+    write_ugid_map("/proc/self/uid_map", euid);
+    write_ugid_map("/proc/self/gid_map", egid);
+  }
+
   xexec_optargs(0);
 }
-- 
2.2.1

_______________________________________________
Toybox mailing list
[email protected]
http://lists.landley.net/listinfo.cgi/toybox-landley.net

Reply via email to