From: ebiederm@xmission.com (Eric W. Biederman)
To: Karel Zak <kzak@redhat.com>
Cc: util-linux@vger.kernel.org
Subject: Re: [PATCH 2/2] unshare: allow persisting mount namespaces
Date: Thu, 09 Apr 2015 12:07:09 -0500 [thread overview]
Message-ID: <87bnix6xj6.fsf@x220.int.ebiederm.org> (raw)
In-Reply-To: <1428578536-31603-2-git-send-email-kzak@redhat.com> (Karel Zak's message of "Thu, 9 Apr 2015 13:22:16 +0200")
Karel Zak <kzak@redhat.com> writes:
> We can create a reference (bind mount) to the new namespace after
> unshare(2), but it does not make sense to do it within unshared
> namespace. (And if I read kernel fs/namespace.c: do_loopback()
> correctly than copy mount bind mounts of /proc/<pid>/ns/mnt between
> namespaces is unsupported.)
The support is limited. mount namespaces are only allowed to be bound
into older mount namespaces.
But yes it is much more interesting to have the namespaces visible in
the parent than in the newly created mount namespace.
Your do { } while(0); loop below concerns me. I think continue and
break are equivalent in that construct.
> This patch bypass this problem by fork() where parent continue as
> usually (call unshare(2), setup another things, etc.), but child
> waits for /proc/[ppid]/ns/mnt inode number change (the ino is
> changed after parent's unshare(2)) and then it bind mounts the new
> namespaces and exit.
>
> Signed-off-by: Karel Zak <kzak@redhat.com>
> ---
> sys-utils/unshare.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++----
> 1 file changed, 65 insertions(+), 4 deletions(-)
>
> diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c
> index 65d3e61..4ed9ad3 100644
> --- a/sys-utils/unshare.c
> +++ b/sys-utils/unshare.c
> @@ -27,6 +27,10 @@
> #include <sys/wait.h>
> #include <sys/mount.h>
>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <unistd.h>
> +
> /* we only need some defines missing in sys/mount.h, no libmount linkage */
> #include <libmount.h>
>
> @@ -185,6 +189,43 @@ static int bind_ns_files(pid_t pid)
> return 0;
> }
>
> +static ino_t get_mnt_ino(pid_t pid)
> +{
> + struct stat st;
> + char path[PATH_MAX];
> +
> + snprintf(path, sizeof(path), "/proc/%u/ns/mnt", (unsigned) pid);
> +
> + if (stat(path, &st) != 0)
> + err(EXIT_FAILURE, _("cannot stat %s"), path);
> + return st.st_ino;
> +}
> +
> +static void bind_ns_files_from_child(pid_t *child)
> +{
> + pid_t ppid = getpid();
> + ino_t ino = get_mnt_ino(ppid);
> +
> + *child = fork();
> +
> + switch(*child) {
> + case -1:
> + err(EXIT_FAILURE, _("fork failed"));
> + case 0: /* child */
> + do {
> + /* wait until parent unshare() */
> + ino_t new_ino = get_mnt_ino(ppid);
> + if (ino != new_ino)
> + break;
> + } while (1);
> + bind_ns_files(ppid);
> + exit(EXIT_SUCCESS);
> + break;
> + default: /* parent */
> + break;
> + }
> +}
> +
> static void usage(int status)
> {
> FILE *out = status == EXIT_SUCCESS ? stdout : stderr;
> @@ -248,6 +289,8 @@ int main(int argc, char *argv[])
> int unshare_flags = 0;
> int c, forkit = 0, maproot = 0;
> const char *procmnt = NULL;
> + pid_t pid = 0;
> + int status;
> unsigned long propagation = UNSHARE_PROPAGATION_DEFAULT;
> uid_t real_euid = geteuid();
> gid_t real_egid = getegid();;
> @@ -316,12 +359,32 @@ int main(int argc, char *argv[])
> }
> }
>
> + if (npersists && (unshare_flags & CLONE_NEWNS))
> + bind_ns_files_from_child(&pid);
> +
> if (-1 == unshare(unshare_flags))
> err(EXIT_FAILURE, _("unshare failed"));
>
> + if (npersists) {
> + if (pid && (unshare_flags & CLONE_NEWNS)) {
> + /* wait for bind_ns_files_from_child() */
> + do {
> + int rc = waitpid(pid, &status, 0);
> + if (rc < 0 && errno == EINTR)
> + continue;
> + else if (rc < 0)
> + err(EXIT_FAILURE, _("waitpid failed"));
> + } while (0);
> +
> + if (WIFEXITED(status) && WEXITSTATUS(status) != EXIT_SUCCESS)
> + return WEXITSTATUS(status);
> + } else
> + /* simple way, just bind */
> + bind_ns_files(getpid());
> + }
> +
> if (forkit) {
> - int status;
> - pid_t pid = fork();
> + pid = fork();
>
> switch(pid) {
> case -1:
> @@ -339,8 +402,6 @@ int main(int argc, char *argv[])
> }
> }
>
> - if (npersists)
> - bind_ns_files(getpid());
>
> if (maproot) {
> if (setgrpcmd == SETGROUPS_ALLOW)
next prev parent reply other threads:[~2015-04-09 17:11 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-04-09 11:22 [PATCH 1/2] unshare: allow persisting namespaces Karel Zak
2015-04-09 11:22 ` [PATCH 2/2] unshare: allow persisting mount namespaces Karel Zak
2015-04-09 17:07 ` Eric W. Biederman [this message]
2015-04-10 8:17 ` Karel Zak
2016-01-30 3:52 ` Yuriy M. Kaminskiy
2016-01-30 13:31 ` Yuriy M. Kaminskiy
2016-02-01 10:41 ` Karel Zak
2016-02-01 14:31 ` Yuriy M. Kaminskiy
2016-02-02 10:14 ` Karel Zak
2016-02-17 13:07 ` Karel Zak
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87bnix6xj6.fsf@x220.int.ebiederm.org \
--to=ebiederm@xmission.com \
--cc=kzak@redhat.com \
--cc=util-linux@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox