From: yumkam@gmail.com (Yuriy M. Kaminskiy)
To: util-linux@vger.kernel.org
Subject: Re: [PATCH 2/2] unshare: allow persisting mount namespaces
Date: Sat, 30 Jan 2016 16:31:06 +0300 [thread overview]
Message-ID: <m3twlvfb39.fsf@gmail.com> (raw)
In-Reply-To: m31t8zhgfv.fsf@gmail.com
[-- Attachment #1: Type: text/plain, Size: 1461 bytes --]
yumkam@gmail.com (Yuriy M. Kaminskiy)
writes:
> Karel Zak <kzak@redhat.com> writes:
>
> (this was commited as c84f2590dfdb8570beeb731e0105f8fe597443d1)
>
>> +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);
>
> Racing? Suppose, parent died (e.g. unshare(2) failed), (parent) process
> was reaped, new (unrelated) process was created with same pid, as a
> result this function will bind namespaces from wrong process.
... besides, this is a busyloop, if "imposer process" is in same mnt
namespace as original process, it will occupy CPU forever (and this *is*
easy to fix; see attached; note that with attached patch race probability is
reduced, but not totally avoided, there are still window between
read(pipe) and mount() calls [but at least it won't busyloop, and won't
trigger racing on unshare(2) error]).
P.S. that said, for me, on debian's 3.16.7-ckt* kernel, `touch foo && unshare
--mount=foo` still fails with EINVAL (with either unpatched git master
or with this patch), so consider this as "compile-tested only".
> (That said, pretty unlikely, and no idea how to properly fix it).
>
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-unshare-fix-busyloop-and-reduce-racing-probability.patch --]
[-- Type: text/x-diff, Size: 2898 bytes --]
>From 64d1e9d905455b8177d65ad58ca2b403bbe8222c Mon Sep 17 00:00:00 2001
From: "Yuriy M. Kaminskiy" <yumkam@gmail.com>
Date: Sat, 30 Jan 2016 16:18:39 +0300
Subject: [PATCH] unshare: fix busyloop and reduce racing probability
Replace busy-loop with waiting on pipe from parent.
Note: reduces racing probability, but still there are window where
it is possible (if parent unshare process will be [externally] killed
between successful read(fds[0]) and mount() calls).
Signed-off-by: Yuriy M. Kaminskiy <yumkam@gmail.com>
---
sys-utils/unshare.c | 49 ++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 40 insertions(+), 9 deletions(-)
diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c
index 7482a8b..bf4f6d2 100644
--- a/sys-utils/unshare.c
+++ b/sys-utils/unshare.c
@@ -199,27 +199,50 @@ static ino_t get_mnt_ino(pid_t pid)
return st.st_ino;
}
-static void bind_ns_files_from_child(pid_t *child)
+static void bind_ns_files_from_child(pid_t *child, int fds[2])
{
pid_t ppid = getpid();
ino_t ino = get_mnt_ino(ppid);
+ if (pipe(fds) < 0)
+ err(EXIT_FAILURE, _("pipe failed"));
+
*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);
+ close(fds[1]);
+ fds[1] = -1;
+ /* wait for parent */
+ for (;;) {
+ char ch = -1;
+
+ switch(read(fds[0], &ch, 1)) {
+ case -1:
+ if (errno == EINTR)
+ continue;
+ /* fallthrough */
+ default:
+ err(EXIT_FAILURE, _("pipe read error"));
+ case 0: /* parent died? */
+ exit(EXIT_FAILURE);
+ case 1:
+ if (ch != 0)
+ exit(EXIT_FAILURE);
+ /* break loop*/;
+ }
+ break;
+ }
+ if (get_mnt_ino(ppid) == ino)
+ exit(EXIT_FAILURE);
bind_ns_files(ppid);
exit(EXIT_SUCCESS);
break;
default: /* parent */
+ close(fds[0]);
+ fds[0] = -1;
break;
}
}
@@ -288,6 +311,7 @@ int main(int argc, char *argv[])
int c, forkit = 0, maproot = 0;
const char *procmnt = NULL;
pid_t pid = 0;
+ int fds[2];
int status;
unsigned long propagation = UNSHARE_PROPAGATION_DEFAULT;
uid_t real_euid = geteuid();
@@ -358,16 +382,23 @@ int main(int argc, char *argv[])
}
if (npersists && (unshare_flags & CLONE_NEWNS))
- bind_ns_files_from_child(&pid);
+ bind_ns_files_from_child(&pid, fds);
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() */
int rc;
+ char ch = 0;
+
+ /* signal child we are ready */
+ while (write(fds[1], &ch, 1) == -1 && errno == EINTR)
+ ;
+ close(fds[1]);
+ fds[1] = -1;
+ /* wait for bind_ns_files_from_child() */
do {
rc = waitpid(pid, &status, 0);
if (rc < 0) {
--
2.1.4
next prev parent reply other threads:[~2016-01-30 13:31 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
2015-04-10 8:17 ` Karel Zak
2016-01-30 3:52 ` Yuriy M. Kaminskiy
2016-01-30 13:31 ` Yuriy M. Kaminskiy [this message]
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=m3twlvfb39.fsf@gmail.com \
--to=yumkam@gmail.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