1/* nsenter.c - Enter existing namespaces 2 * 3 * Copyright 2014 Andy Lutomirski <luto@amacapital.net> 4 * 5 * See http://man7.org/linux/man-pages/man1/nsenter.1.html 6 * 7 * unshare.c - run command in new context 8 * 9 * Copyright 2011 Rob Landley <rob@landley.net> 10 * 11 * See http://man7.org/linux/man-pages/man1/unshare.1.html 12 * 13 14// Note: flags go in same order (right to left) for shared subset 15USE_NSENTER(NEWTOY(nsenter, "<1a(all)F(no-fork)t#<1(target)C(cgroup):; i(ipc):; m(mount):; n(net):; p(pid):; u(uts):; U(user):; ", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT)) 16USE_UNSHARE(NEWTOY(unshare, "<1^a(all)f(fork)r(map-root-user)C(cgroup):; i(ipc):; m(mount):; n(net):; p(pid):; u(uts):; U(user):; ", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT)) 17 18config UNSHARE 19 bool "unshare" 20 default y 21 help 22 usage: unshare [-imnpuUr] COMMAND... 23 24 Create new container namespace(s) for this process and its children, allowing 25 the new set of processes to have a different view of the system than the 26 parent process. 27 28 -a Unshare all supported namespaces 29 -f Fork command in the background (--fork) 30 -r Become root (map current euid/egid to 0/0, implies -U) (--map-root-user) 31 32 Available namespaces: 33 -C Control groups (--cgroup) 34 -i SysV IPC (message queues, semaphores, shared memory) (--ipc) 35 -m Mount/unmount tree (--mount) 36 -n Network address, sockets, routing, iptables (--net) 37 -p Process IDs and init (--pid) 38 -u Host and domain names (--uts) 39 -U UIDs, GIDs, capabilities (--user) 40 41 Each namespace can take an optional argument, a persistent mountpoint usable 42 by the nsenter command to add new processes to that the namespace. (Specify 43 multiple namespaces to unshare seperately, ala -c -i -m because -cim is -c 44 with persistent mount "im".) 45 46config NSENTER 47 bool "nsenter" 48 default y 49 help 50 usage: nsenter [-t pid] [-F] [-i] [-m] [-n] [-p] [-u] [-U] COMMAND... 51 52 Run COMMAND in an existing (set of) namespace(s). 53 54 -a Enter all supported namespaces (--all) 55 -F don't fork, even if -p is used (--no-fork) 56 -t PID to take namespaces from (--target) 57 58 The namespaces to switch are: 59 60 -C Control groups (--cgroup) 61 -i SysV IPC: message queues, semaphores, shared memory (--ipc) 62 -m Mount/unmount tree (--mount) 63 -n Network address, sockets, routing, iptables (--net) 64 -p Process IDs and init, will fork unless -F is used (--pid) 65 -u Host and domain names (--uts) 66 -U UIDs, GIDs, capabilities (--user) 67 68 If -t isn't specified, each namespace argument must provide a path 69 to a namespace file, ala "-i=/proc/$PID/ns/ipc" 70*/ 71 72#define FOR_nsenter 73#include "toys.h" 74#include <linux/sched.h> 75 76#define unshare(flags) syscall(SYS_unshare, flags) 77#define setns(fd, nstype) syscall(SYS_setns, fd, nstype) 78 79GLOBALS( 80 char *UupnmiC[6]; 81 long t; 82) 83 84// Code that must run in unshare's flag context 85#define FOR_unshare 86#include <generated/flags.h> 87 88static void write_ugid_map(char *map, unsigned eugid) 89{ 90 int fd = xopen(map, O_WRONLY); 91 92 dprintf(fd, "0 %u 1", eugid); 93 xclose(fd); 94} 95 96static int test_a() { return FLAG(a); } 97static int test_r() { return FLAG(r); } 98static int test_f() { return FLAG(f); } 99 100// Shift back to the context GLOBALS lives in (I.E. matching the filename). 101#define FOR_nsenter 102#include <generated/flags.h> 103 104void unshare_main(void) 105{ 106 char *nsnames = "user\0uts\0pid\0net\0mnt\0ipc\0cgroup"; 107 unsigned flags[]={CLONE_NEWUSER, CLONE_NEWUTS, CLONE_NEWPID, CLONE_NEWNET, 108 CLONE_NEWNS, CLONE_NEWIPC, CLONE_NEWCGROUP}, f = 0; 109 int i, fd; 110 111 // Create new namespace(s)? 112 if (CFG_UNSHARE && *toys.which->name=='u') { 113 // For -r, we have to save our original [ug]id before calling unshare() 114 int euid = geteuid(), egid = getegid(); 115 116 // unshare -U does not imply -r, so we cannot use [+rU] 117 if (test_r()) toys.optflags |= FLAG_U; 118 119 for (i = 0; i<ARRAY_LEN(flags); i++) 120 if (test_a() || (toys.optflags & (1<<i))) f |= flags[i]; 121 if (unshare(f)) perror_exit(0); 122 if (test_r()) { 123 if ((fd = open("/proc/self/setgroups", O_WRONLY)) >= 0) { 124 xwrite(fd, "deny", 4); 125 close(fd); 126 } 127 128 write_ugid_map("/proc/self/uid_map", euid); 129 write_ugid_map("/proc/self/gid_map", egid); 130 } 131 132 if (test_f()) { 133 toys.exitval = xrun(toys.optargs); 134 135 return; 136 } 137 // Bind to existing namespace(s)? 138 } else if (CFG_NSENTER) { 139 for (i = 0; i<ARRAY_LEN(flags); i++, nsnames += strlen(nsnames)+1) { 140 if (FLAG(a) || (toys.optflags & (1<<i))) { 141 char *filename = TT.UupnmiC[i]; 142 143 if (!filename || !*filename) { 144 if (!FLAG(t)) error_exit("need -t or =filename"); 145 sprintf(filename = toybuf, "/proc/%ld/ns/%s", TT.t, nsnames); 146 } 147 148 if (setns(fd = xopenro(filename), flags[i])) perror_exit("setns"); 149 close(fd); 150 } 151 } 152 153 if (FLAG(p) && !FLAG(F)) { 154 toys.exitval = xrun(toys.optargs); 155 156 return; 157 } 158 } 159 160 xexec(toys.optargs); 161} 162 163void nsenter_main(void) 164{ 165 unshare_main(); 166} 167