*
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/
-
//config:config UNSHARE
-//config: bool "unshare"
+//config: bool "unshare (9.2 kb)"
//config: default y
-//config: depends on LONG_OPTS && !NOMMU
+//config: depends on !NOMMU
//config: select PLATFORM_LINUX
+//config: select LONG_OPTS
//config: help
-//config: Run program with some namespaces unshared from parent.
+//config: Run program with some namespaces unshared from parent.
-// depends on LONG_OPTS: it is awkward to exclude code which handles --propagation
+// needs LONG_OPTS: it is awkward to exclude code which handles --propagation
// and --setgroups based on LONG_OPTS, so instead applet requires LONG_OPTS.
// depends on !NOMMU: we need fork()
//usage:#define unshare_trivial_usage
//usage: "[OPTIONS] [PROG [ARGS]]"
//usage:#define unshare_full_usage "\n"
-//usage: "\n -m, --mount[=FILE] Unshare mount namespace"
-//usage: "\n -u, --uts[=FILE] Unshare UTS namespace (hostname etc.)"
-//usage: "\n -i, --ipc[=FILE] Unshare System V IPC namespace"
-//usage: "\n -n, --net[=FILE] Unshare network namespace"
-//usage: "\n -p, --pid[=FILE] Unshare PID namespace"
-//usage: "\n -U, --user[=FILE} Unshare user namespace"
-//usage: "\n -f, --fork Fork before execing PROG"
-//usage: "\n -r, --map-root-user Map current user to root (implies -u)"
+//usage: "\n -m,--mount[=FILE] Unshare mount namespace"
+//usage: "\n -u,--uts[=FILE] Unshare UTS namespace (hostname etc.)"
+//usage: "\n -i,--ipc[=FILE] Unshare System V IPC namespace"
+//usage: "\n -n,--net[=FILE] Unshare network namespace"
+//usage: "\n -p,--pid[=FILE] Unshare PID namespace"
+//usage: "\n -U,--user[=FILE] Unshare user namespace"
+//usage: "\n -f,--fork Fork before execing PROG"
+//usage: "\n -r,--map-root-user Map current user to root (implies -U)"
//usage: "\n --mount-proc[=DIR] Mount /proc filesystem first (implies -m)"
//usage: "\n --propagation slave|shared|private|unchanged"
//usage: "\n Modify mount propagation in mount namespace"
//usage: "\n --setgroups allow|deny Control the setgroups syscall in user namespaces"
#include <sched.h>
+#ifndef CLONE_NEWUTS
+# define CLONE_NEWUTS 0x04000000
+#endif
+#ifndef CLONE_NEWIPC
+# define CLONE_NEWIPC 0x08000000
+#endif
+#ifndef CLONE_NEWUSER
+# define CLONE_NEWUSER 0x10000000
+#endif
+#ifndef CLONE_NEWPID
+# define CLONE_NEWPID 0x20000000
+#endif
+#ifndef CLONE_NEWNET
+# define CLONE_NEWNET 0x40000000
+#endif
+
#include <sys/mount.h>
+#ifndef MS_REC
+# define MS_REC (1 << 14)
+#endif
+#ifndef MS_PRIVATE
+# define MS_PRIVATE (1 << 18)
+#endif
+#ifndef MS_SLAVE
+# define MS_SLAVE (1 << 19)
+#endif
+#ifndef MS_SHARED
+# define MS_SHARED (1 << 20)
+#endif
+
#include "libbb.h"
static void mount_or_die(const char *source, const char *target,
- const char *fstype, unsigned long mountflags)
+ const char *fstype, unsigned long mountflags)
{
if (mount(source, target, fstype, mountflags, NULL)) {
bb_perror_msg_and_die("can't mount %s on %s (flags:0x%lx)",
}
}
-/*
- * Longest possible path to a procfs file used in unshare. Must be able to
- * contain the '/proc/' string, the '/ns/user' string which is the longest
- * namespace name and a 32-bit integer representing the process ID.
- */
#define PATH_PROC_SETGROUPS "/proc/self/setgroups"
#define PATH_PROC_UIDMAP "/proc/self/uid_map"
#define PATH_PROC_GIDMAP "/proc/self/gid_map"
OPT_mount = 1 << 0,
OPT_uts = 1 << 1,
OPT_ipc = 1 << 2,
- OPT_network = 1 << 3,
+ OPT_net = 1 << 3,
OPT_pid = 1 << 4,
OPT_user = 1 << 5, /* OPT_user, NS_USR_POS, and ns_list[] index must match! */
OPT_fork = 1 << 6,
* we are forced to use "fake" letters for them.
* '+': stop at first non-option.
*/
-static const char opt_str[] = "+muinpU""fr""\xfd::""\xfe:""\xff:";
+#define OPT_STR "+muinpU""fr""\xfd::""\xfe:""\xff:"
static const char unshare_longopts[] ALIGN1 =
"mount\0" Optional_argument "\xf0"
"uts\0" Optional_argument "\xf1"
"ipc\0" Optional_argument "\xf2"
- "network\0" Optional_argument "\xf3"
+ "net\0" Optional_argument "\xf3"
"pid\0" Optional_argument "\xf4"
"user\0" Optional_argument "\xf5"
"fork\0" No_argument "f"
prop_str = PRIVATE_STR;
setgrp_str = NULL;
- opt_complementary =
+ opts = getopt32long(argv, "^" OPT_STR "\0"
"\xf0""m" /* long opts (via their "fake chars") imply short opts */
":\xf1""u"
":\xf2""i"
":\xf3""n"
":\xf4""p"
":\xf5""U"
- ":ru" /* --map-root-user or -r implies -u */
+ ":rU" /* --map-root-user or -r implies -U */
":\xfd""m" /* --mount-proc implies -m */
- ;
- applet_long_options = unshare_longopts;
- opts = getopt32(argv, opt_str,
- &proc_mnt_target, &prop_str, &setgrp_str,
- &ns_ctx_list[NS_MNT_POS].path,
- &ns_ctx_list[NS_UTS_POS].path,
- &ns_ctx_list[NS_IPC_POS].path,
- &ns_ctx_list[NS_NET_POS].path,
- &ns_ctx_list[NS_PID_POS].path,
- &ns_ctx_list[NS_USR_POS].path
+ , unshare_longopts,
+ &proc_mnt_target, &prop_str, &setgrp_str,
+ &ns_ctx_list[NS_MNT_POS].path,
+ &ns_ctx_list[NS_UTS_POS].path,
+ &ns_ctx_list[NS_IPC_POS].path,
+ &ns_ctx_list[NS_NET_POS].path,
+ &ns_ctx_list[NS_PID_POS].path,
+ &ns_ctx_list[NS_USR_POS].path
);
argv += optind;
//bb_error_msg("opts:0x%x", opts);
if (fdp.wr >= 0) {
close(fdp.wr); /* Release child */
- /*close(fdp.rd);*/
+ close(fdp.rd); /* should close fd, to not confuse exec'ed PROG */
}
if (need_mount) {
* that'll become PID 1 in this new namespace.
*/
if (opts & OPT_fork) {
- pid_t pid = xfork();
- if (pid > 0) {
- /* Parent */
- int exit_status = wait_for_exitstatus(pid);
- if (WIFSIGNALED(exit_status))
- kill_myself_with_sig(WTERMSIG(exit_status));
- return WEXITSTATUS(exit_status);
- }
+ xvfork_parent_waits_and_exits();
/* Child continues */
}
if (opts & OPT_map_root) {
- char uidmap_buf[sizeof("%u 0 1") + sizeof(int)*3];
+ char uidmap_buf[sizeof("0 %u 1") + sizeof(int)*3];
/*
* Since Linux 3.19 unprivileged writing of /proc/self/gid_map
* in that user namespace.
*/
xopen_xwrite_close(PATH_PROC_SETGROUPS, "deny");
- sprintf(uidmap_buf, "%u 0 1", (unsigned)reuid);
+ sprintf(uidmap_buf, "0 %u 1", (unsigned)reuid);
xopen_xwrite_close(PATH_PROC_UIDMAP, uidmap_buf);
- sprintf(uidmap_buf, "%u 0 1", (unsigned)regid);
+ sprintf(uidmap_buf, "0 %u 1", (unsigned)regid);
xopen_xwrite_close(PATH_PROC_GIDMAP, uidmap_buf);
} else
if (setgrp_str) {
mount_or_die("proc", proc_mnt_target, "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV);
}
- if (argv[0]) {
- BB_EXECVP_or_die(argv);
- }
- /* unshare from util-linux 2.27.1, despite not documenting it,
- * runs a login shell (argv0="-sh") if no PROG is given
- */
- run_shell(getenv("SHELL"), /*login:*/ 1, NULL, NULL);
+ exec_prog_or_SHELL(argv);
}