10f66f451Sopenharmony_ci/* nsenter.c - Enter existing namespaces 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2014 Andy Lutomirski <luto@amacapital.net> 40f66f451Sopenharmony_ci * 50f66f451Sopenharmony_ci * See http://man7.org/linux/man-pages/man1/nsenter.1.html 60f66f451Sopenharmony_ci * 70f66f451Sopenharmony_ci * unshare.c - run command in new context 80f66f451Sopenharmony_ci * 90f66f451Sopenharmony_ci * Copyright 2011 Rob Landley <rob@landley.net> 100f66f451Sopenharmony_ci * 110f66f451Sopenharmony_ci * See http://man7.org/linux/man-pages/man1/unshare.1.html 120f66f451Sopenharmony_ci * 130f66f451Sopenharmony_ci 140f66f451Sopenharmony_ci// Note: flags go in same order (right to left) for shared subset 150f66f451Sopenharmony_ciUSE_NSENTER(NEWTOY(nsenter, "<1F(no-fork)t#<1(target)i:(ipc);m:(mount);n:(net);p:(pid);u:(uts);U:(user);", TOYFLAG_USR|TOYFLAG_BIN)) 160f66f451Sopenharmony_ciUSE_UNSHARE(NEWTOY(unshare, "<1^f(fork);r(map-root-user);i:(ipc);m:(mount);n:(net);p:(pid);u:(uts);U:(user);", TOYFLAG_USR|TOYFLAG_BIN)) 170f66f451Sopenharmony_ci 180f66f451Sopenharmony_ciconfig UNSHARE 190f66f451Sopenharmony_ci bool "unshare" 200f66f451Sopenharmony_ci default y 210f66f451Sopenharmony_ci depends on TOYBOX_CONTAINER 220f66f451Sopenharmony_ci help 230f66f451Sopenharmony_ci usage: unshare [-imnpuUr] COMMAND... 240f66f451Sopenharmony_ci 250f66f451Sopenharmony_ci Create new container namespace(s) for this process and its children, so 260f66f451Sopenharmony_ci some attribute is not shared with the parent process. 270f66f451Sopenharmony_ci 280f66f451Sopenharmony_ci -f Fork command in the background (--fork) 290f66f451Sopenharmony_ci -i SysV IPC (message queues, semaphores, shared memory) (--ipc) 300f66f451Sopenharmony_ci -m Mount/unmount tree (--mount) 310f66f451Sopenharmony_ci -n Network address, sockets, routing, iptables (--net) 320f66f451Sopenharmony_ci -p Process IDs and init (--pid) 330f66f451Sopenharmony_ci -r Become root (map current euid/egid to 0/0, implies -U) (--map-root-user) 340f66f451Sopenharmony_ci -u Host and domain names (--uts) 350f66f451Sopenharmony_ci -U UIDs, GIDs, capabilities (--user) 360f66f451Sopenharmony_ci 370f66f451Sopenharmony_ci A namespace allows a set of processes to have a different view of the 380f66f451Sopenharmony_ci system than other sets of processes. 390f66f451Sopenharmony_ci 400f66f451Sopenharmony_ciconfig NSENTER 410f66f451Sopenharmony_ci bool "nsenter" 420f66f451Sopenharmony_ci depends on TOYBOX_CONTAINER 430f66f451Sopenharmony_ci default y 440f66f451Sopenharmony_ci help 450f66f451Sopenharmony_ci usage: nsenter [-t pid] [-F] [-i] [-m] [-n] [-p] [-u] [-U] COMMAND... 460f66f451Sopenharmony_ci 470f66f451Sopenharmony_ci Run COMMAND in an existing (set of) namespace(s). 480f66f451Sopenharmony_ci 490f66f451Sopenharmony_ci -t PID to take namespaces from (--target) 500f66f451Sopenharmony_ci -F don't fork, even if -p is used (--no-fork) 510f66f451Sopenharmony_ci 520f66f451Sopenharmony_ci The namespaces to switch are: 530f66f451Sopenharmony_ci 540f66f451Sopenharmony_ci -i SysV IPC: message queues, semaphores, shared memory (--ipc) 550f66f451Sopenharmony_ci -m Mount/unmount tree (--mount) 560f66f451Sopenharmony_ci -n Network address, sockets, routing, iptables (--net) 570f66f451Sopenharmony_ci -p Process IDs and init, will fork unless -F is used (--pid) 580f66f451Sopenharmony_ci -u Host and domain names (--uts) 590f66f451Sopenharmony_ci -U UIDs, GIDs, capabilities (--user) 600f66f451Sopenharmony_ci 610f66f451Sopenharmony_ci If -t isn't specified, each namespace argument must provide a path 620f66f451Sopenharmony_ci to a namespace file, ala "-i=/proc/$PID/ns/ipc" 630f66f451Sopenharmony_ci*/ 640f66f451Sopenharmony_ci 650f66f451Sopenharmony_ci#define FOR_nsenter 660f66f451Sopenharmony_ci#include "toys.h" 670f66f451Sopenharmony_ci#include <sys/syscall.h> 680f66f451Sopenharmony_ci#include <linux/sched.h> 690f66f451Sopenharmony_ci 700f66f451Sopenharmony_ci#define unshare(flags) syscall(SYS_unshare, flags) 710f66f451Sopenharmony_ci#define setns(fd, nstype) syscall(SYS_setns, fd, nstype) 720f66f451Sopenharmony_ci 730f66f451Sopenharmony_ciGLOBALS( 740f66f451Sopenharmony_ci char *Uupnmi[6]; 750f66f451Sopenharmony_ci long t; 760f66f451Sopenharmony_ci) 770f66f451Sopenharmony_ci 780f66f451Sopenharmony_ci// Code that must run in unshare's flag context 790f66f451Sopenharmony_ci#define CLEANUP_nsenter 800f66f451Sopenharmony_ci#define FOR_unshare 810f66f451Sopenharmony_ci#include <generated/flags.h> 820f66f451Sopenharmony_ci 830f66f451Sopenharmony_cistatic void write_ugid_map(char *map, unsigned eugid) 840f66f451Sopenharmony_ci{ 850f66f451Sopenharmony_ci int fd = xopen(map, O_WRONLY); 860f66f451Sopenharmony_ci 870f66f451Sopenharmony_ci dprintf(fd, "0 %u 1", eugid); 880f66f451Sopenharmony_ci xclose(fd); 890f66f451Sopenharmony_ci} 900f66f451Sopenharmony_ci 910f66f451Sopenharmony_cistatic void handle_r(int euid, int egid) 920f66f451Sopenharmony_ci{ 930f66f451Sopenharmony_ci int fd; 940f66f451Sopenharmony_ci 950f66f451Sopenharmony_ci if ((fd = open("/proc/self/setgroups", O_WRONLY)) >= 0) { 960f66f451Sopenharmony_ci xwrite(fd, "deny", 4); 970f66f451Sopenharmony_ci close(fd); 980f66f451Sopenharmony_ci } 990f66f451Sopenharmony_ci 1000f66f451Sopenharmony_ci write_ugid_map("/proc/self/uid_map", euid); 1010f66f451Sopenharmony_ci write_ugid_map("/proc/self/gid_map", egid); 1020f66f451Sopenharmony_ci} 1030f66f451Sopenharmony_ci 1040f66f451Sopenharmony_cistatic int test_r() 1050f66f451Sopenharmony_ci{ 1060f66f451Sopenharmony_ci return toys.optflags & FLAG_r; 1070f66f451Sopenharmony_ci} 1080f66f451Sopenharmony_ci 1090f66f451Sopenharmony_cistatic int test_f() 1100f66f451Sopenharmony_ci{ 1110f66f451Sopenharmony_ci return toys.optflags & FLAG_f; 1120f66f451Sopenharmony_ci} 1130f66f451Sopenharmony_ci 1140f66f451Sopenharmony_ci// Shift back to the context GLOBALS lives in (I.E. matching the filename). 1150f66f451Sopenharmony_ci#define CLEANUP_unshare 1160f66f451Sopenharmony_ci#define FOR_nsenter 1170f66f451Sopenharmony_ci#include <generated/flags.h> 1180f66f451Sopenharmony_ci 1190f66f451Sopenharmony_civoid unshare_main(void) 1200f66f451Sopenharmony_ci{ 1210f66f451Sopenharmony_ci unsigned flags[]={CLONE_NEWUSER, CLONE_NEWUTS, CLONE_NEWPID, CLONE_NEWNET, 1220f66f451Sopenharmony_ci CLONE_NEWNS, CLONE_NEWIPC}, f = 0; 1230f66f451Sopenharmony_ci int i, fd; 1240f66f451Sopenharmony_ci 1250f66f451Sopenharmony_ci // Create new namespace(s)? 1260f66f451Sopenharmony_ci if (CFG_UNSHARE && *toys.which->name=='u') { 1270f66f451Sopenharmony_ci // For -r, we have to save our original [ug]id before calling unshare() 1280f66f451Sopenharmony_ci int euid = geteuid(), egid = getegid(); 1290f66f451Sopenharmony_ci 1300f66f451Sopenharmony_ci // unshare -U does not imply -r, so we cannot use [+rU] 1310f66f451Sopenharmony_ci if (test_r()) toys.optflags |= FLAG_U; 1320f66f451Sopenharmony_ci 1330f66f451Sopenharmony_ci for (i = 0; i<ARRAY_LEN(flags); i++) 1340f66f451Sopenharmony_ci if (toys.optflags & (1<<i)) f |= flags[i]; 1350f66f451Sopenharmony_ci 1360f66f451Sopenharmony_ci if (unshare(f)) perror_exit(0); 1370f66f451Sopenharmony_ci if (test_r()) handle_r(euid, egid); 1380f66f451Sopenharmony_ci 1390f66f451Sopenharmony_ci if (test_f()) { 1400f66f451Sopenharmony_ci toys.exitval = xrun(toys.optargs); 1410f66f451Sopenharmony_ci 1420f66f451Sopenharmony_ci return; 1430f66f451Sopenharmony_ci } 1440f66f451Sopenharmony_ci // Bind to existing namespace(s)? 1450f66f451Sopenharmony_ci } else if (CFG_NSENTER) { 1460f66f451Sopenharmony_ci char *nsnames = "user\0uts\0pid\0net\0mnt\0ipc"; 1470f66f451Sopenharmony_ci 1480f66f451Sopenharmony_ci for (i = 0; i<ARRAY_LEN(flags); i++) { 1490f66f451Sopenharmony_ci char *filename = TT.Uupnmi[i]; 1500f66f451Sopenharmony_ci 1510f66f451Sopenharmony_ci if (toys.optflags & (1<<i)) { 1520f66f451Sopenharmony_ci if (!filename || !*filename) { 1530f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_t)) error_exit("need -t or =filename"); 1540f66f451Sopenharmony_ci sprintf(toybuf, "/proc/%ld/ns/%s", TT.t, nsnames); 1550f66f451Sopenharmony_ci filename = toybuf; 1560f66f451Sopenharmony_ci } 1570f66f451Sopenharmony_ci 1580f66f451Sopenharmony_ci if (setns(fd = xopenro(filename), flags[i])) perror_exit("setns"); 1590f66f451Sopenharmony_ci close(fd); 1600f66f451Sopenharmony_ci } 1610f66f451Sopenharmony_ci nsnames += strlen(nsnames)+1; 1620f66f451Sopenharmony_ci } 1630f66f451Sopenharmony_ci 1640f66f451Sopenharmony_ci if ((toys.optflags & FLAG_p) && !(toys.optflags & FLAG_F)) { 1650f66f451Sopenharmony_ci toys.exitval = xrun(toys.optargs); 1660f66f451Sopenharmony_ci 1670f66f451Sopenharmony_ci return; 1680f66f451Sopenharmony_ci } 1690f66f451Sopenharmony_ci } 1700f66f451Sopenharmony_ci 1710f66f451Sopenharmony_ci xexec(toys.optargs); 1720f66f451Sopenharmony_ci} 1730f66f451Sopenharmony_ci 1740f66f451Sopenharmony_civoid nsenter_main(void) 1750f66f451Sopenharmony_ci{ 1760f66f451Sopenharmony_ci unshare_main(); 1770f66f451Sopenharmony_ci} 178