[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