pivot_root.2: pivot_root(".", ".") really is a thing

LXC uses this [1]. I tested, to double-check, and it works.

The fchdir() dance done by LXC is not needed though:

fchdir(old_root); umount(".", MNT_DETACH); fchdir(new_root);

As far as I can see, just the umount() is sufficient, since,
after pivot_root(), oldi_root is at the top of the stack
of mounts at "/" and thus (so long as CWD is at "/")
the umount will remove the mount at the top of the stack.
Eric Biederman confirmed my understanding by mail, and
Philipp Wendler verified my results by experiment.

[1] See the following commit in LXC:

    commit 2d489f9e87fa0cccd8a1762680a43eeff2fe1b6e
    Author: Serge Hallyn <serge.hallyn@ubuntu.com>
    Date:   Sat Sep 20 03:15:44 2014 +0000

        pivot_root: switch to a new mechanism (v2)

Helped-by: Eric W. Biederman <ebiederm@xmission.com>
Helped-by: Philipp Wendler <ml@philippwendler.de>
Helped-by: Aleksa Sarai <asarai@suse.de>
Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
This commit is contained in:
Michael Kerrisk 2019-07-31 23:51:39 +02:00
parent 682e1329f9
commit 57bab66a92
1 changed files with 38 additions and 1 deletions

View File

@ -80,7 +80,8 @@ can't be
.IR """/"""
(but can be a bind mounted directory on the current root filesystem).
.IP \-
\fIput_old\fP must be underneath \fInew_root\fP, that is, adding a nonzero
\fIput_old\fP must be at or underneath \fInew_root\fP;
that is, adding a nonnegative
number of \fI/..\fP to the string pointed to by \fIput_old\fP must yield
the same directory as \fInew_root\fP.
.IP \-
@ -209,6 +210,42 @@ root directory busy with their root and current working directory,
even if they never access
the filesystem in any way.
.PP
.I new_root
and
.I put_old
may be the same directory.
In particular, the following sequence allows a pivot-root operation
without needing to create and remove a temporary directory:
.PP
.in +4n
.EX
chdir(new_root);
pivot_root(".", ".");
umount2(".", MNT_DETACH);
.EE
.in
.PP
This sequence succeeds because the
.BR pivot_root ()
call stacks the old root mount point
.RI ( old_root )
on top of the new root mount point at
.IR / .
At that point, the calling process's root directory and current
working directory refer to the new root mount point
.RI ( new_root ).
During the subsequent
.BR umount ()
call, resolution of
.IR """."""
starts with
.I new_root
and then moves up the list of mounts stacked at
.IR / ,
with the result that
.IR old_root
is unmounted.
.PP
The rootfs (initial ramfs) cannot be
.BR pivot_root ()ed.
The recommended method of changing the root filesystem in this case is