[PATCH v7 3/7] unshare: new applet
Denys Vlasenko
vda.linux at googlemail.com
Fri Apr 1 16:48:34 UTC 2016
On Fri, Mar 18, 2016 at 12:37 PM, Bartosz Golaszewski
<bartekgola at gmail.com> wrote:
> Add a fully featured unshare implementation implementing all arguments
> supported in the upstream version.
>
> Signed-off-by: Bartosz Golaszewski <bartekgola at gmail.com>
> ---
> util-linux/unshare.c | 465 +++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 465 insertions(+)
> create mode 100644 util-linux/unshare.c
>
> diff --git a/util-linux/unshare.c b/util-linux/unshare.c
> new file mode 100644
> index 0000000..742d336
> --- /dev/null
> +++ b/util-linux/unshare.c
> @@ -0,0 +1,465 @@
> +/* vi: set sw=4 ts=4: */
> +/*
> + * Mini unshare implementation for busybox.
> + *
> + * Copyright (C) 2016 by Bartosz Golaszewski <bartekgola at gmail.com>
> + *
> + * Licensed under GPLv2 or later, see file LICENSE in this source tree.
> + */
> +
> +//config:config UNSHARE
> +//config: bool "unshare"
> +//config: default y
> +//config: select PLATFORM_LINUX
> +//config: help
> +//config: Run program with some namespaces unshared from parent.
> +//config:
> +//config:config FEATURE_UNSHARE_LONG_OPTS
> +//config: bool "enable long options"
> +//config: default y
> +//config: depends on UNSHARE && LONG_OPTS
> +//config: help
> +//config: Support long options for the unshare applet. This makes
> +//config: the busybox implementation more compatible with upstream.
> +
> +//applet:IF_UNSHARE(APPLET(unshare, BB_DIR_USR_BIN, BB_SUID_DROP))
> +
> +//kbuild:lib-$(CONFIG_UNSHARE) += unshare.o
> +
> +//usage:#define unshare_trivial_usage
> +//usage: "[options] <program> [args...]"
> +//usage:#if ENABLE_FEATURE_UNSHARE_LONG_OPTS
> +//usage:#define unshare_full_usage "\n\n"
> +//usage: "Options:"
> +//usage: "\n -m, --mount[=<file>] unshare mounts namespace"
> +//usage: "\n -u, --uts[=<file>] unshare UTS namespace (hostname etc.)"
> +//usage: "\n -i, --ipc[=<file>] unshare System V IPC namespace"
> +//usage: "\n -n, --network[=<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 launching <program>"
> +//usage: "\n -M, --mount-proc[=<dir>] mount proc filesystem first (implies --mount)"
> +//usage: "\n -r, --map-root-user map current user to root (implies --user)"
> +//usage: "\n -P, --propagation slave|shared|private|unchanged"
> +//usage: "\n modify mount propagation in mount namespace"
> +//usage: "\n -s, --setgroups allow|deny control the setgroups syscall in user namespaces"
> +//usage:#else
> +//usage:#define unshare_full_usage "\n\n"
> +//usage: "Options:"
> +//usage: "\n -m [<file>] unshare mounts namespace"
> +//usage: "\n -u [<file>] unshare UTS namespace (hostname etc.)"
> +//usage: "\n -i [<file>] unshare System V IPC namespace"
> +//usage: "\n -n [<file>] unshare network namespace"
> +//usage: "\n -p [<file>] unshare pid namespace"
> +//usage: "\n -U [<file>] unshare user namespace"
> +//usage: "\n -f fork before launching <program>"
> +//usage: "\n -M [<dir>] mount proc filesystem first (implies -m)"
> +//usage: "\n -r map current user to root (implies -u)"
> +//usage: "\n -P slave|shared|private|unchanged"
> +//usage: "\n modify mount propagation in mount namespace"
> +//usage: "\n -s allow|deny ontrol the setgroups syscall in user namespaces"
> +//usage:#endif
Upstream-incompatible options, even if only "slightly" incompatible,
is asking for trouble.
"unshare -muni sh" was some of my first tests. Whoops. Immediately doesn't work:
it thinks that "uni" is a parameter to -m.
> + /*
> + * Save current process' mount namespace file inode number. We
> + * will later use it in child process to check if it already
> + * changed meaning that this process already called unshare().
> + */
> + inop = get_mnt_ns_inode_by_pid(ppid);
> +
> + pid = xfork();
> + if (pid == 0) {
> + /*
> + * Child - wait until parent calls unshare(). No issue
> + * in busy-waiting - by the time we get here from
> + * fork(), the parent has usually already unshared the
> + * mount namespace. We should spin a few times at most.
> + *
> + * XXX Should probably use a pipe to notify the child
> + * about completing unshare().
> + */
> + do {
> + inoc = get_mnt_ns_inode_by_pid(ppid);
> + } while (inoc == inop);
Yes, waiting on pipe is much simpler than this.
> + status = safe_waitpid(pid, &exit_status, 0);
> + if (status < 0)
> + bb_perror_msg_and_die("waitpid");
> +
> + if (WIFEXITED(exit_status) &&
> + WEXITSTATUS(exit_status) != EXIT_SUCCESS)
> + return WEXITSTATUS(status);
Bug here (wrong variable used in one place).
> + if (*argv) {
> + execvp(*argv, argv);
> + bb_perror_msg_and_die("failed to execute %s", *argv);
> + }
> +
> + run_shell(getenv("SHELL"), 0, NULL, NULL);
> +}
Not compatible. PROG argument is mandatory, no implied shell.
Basically, this bit needs to be replaced by single line,
BB_EXECVP_or_die(argv);
I'll post my version shortly.
More information about the busybox
mailing list