]> git.ipfire.org Git - thirdparty/man-pages.git/blobdiff - man2/pivot_root.2
des_crypt.3: Minor wording fix in VERSIONS
[thirdparty/man-pages.git] / man2 / pivot_root.2
index 6853e9bd9a9e6e8acd0ac1cbc12836e90385c6f2..1995361616b0153117a7dc31c46f67a084caae09 100644 (file)
@@ -1,16 +1,32 @@
-.\" Copyright (C) 2000 by Werner Almesberger
-.\" and Copyright (C) 2019 Michael Kerrisk <mtk.manpages@gmail.com>
+.\" Copyright (C) 2019 Michael Kerrisk <mtk.manpages@gmail.com>
+.\" A very few fragments remain from an earlier page written by
+.\" Werner Almesberger in 2000
 .\"
-.\" %%%LICENSE_START(GPL_NOVERSION_ONELINE)
-.\" May be distributed under GPL
-.\" %%%LICENSE_END
+.\" %%%LICENSE_START(VERBATIM)
+.\" Permission is granted to make and distribute verbatim copies of this
+.\" manual provided the copyright notice and this permission notice are
+.\" preserved on all copies.
+.\"
+.\" Permission is granted to copy and distribute modified versions of this
+.\" manual under the conditions for verbatim copying, provided that the
+.\" entire resulting derived work is distributed under the terms of a
+.\" permission notice identical to this one.
 .\"
-.\" Written 2000-02-23 by Werner Almesberger
-.\" Modified 2004-06-17 Michael Kerrisk <mtk.manpages@gmail.com>
+.\" Since the Linux kernel and libraries are constantly changing, this
+.\" manual page may be incorrect or out-of-date.  The author(s) assume no
+.\" responsibility for errors or omissions, or for damages resulting from
+.\" the use of the information contained herein.  The author(s) may not
+.\" have taken the same level of care in the production of this manual,
+.\" which is licensed free of charge, as they might when working
+.\" professionally.
+.\"
+.\" Formatted or processed versions of this manual, if unaccompanied by
+.\" the source, must acknowledge the copyright and authors of this work.
+.\" %%%LICENSE_END
 .\"
-.TH PIVOT_ROOT 2 2019-08-02 "Linux" "Linux Programmer's Manual"
+.TH PIVOT_ROOT 2 2019-11-19 "Linux" "Linux Programmer's Manual"
 .SH NAME
-pivot_root \- change the root filesystem
+pivot_root \- change the root mount
 .SH SYNOPSIS
 .BI "int pivot_root(const char *" new_root ", const char *" put_old );
 .PP
@@ -18,48 +34,25 @@ pivot_root \- change the root filesystem
 There is no glibc wrapper for this system call; see NOTES.
 .SH DESCRIPTION
 .BR pivot_root ()
-changes the root filesystem in the mount namespace of the calling process.
-More precisely, it moves the root filesystem to the
-directory \fIput_old\fP and makes \fInew_root\fP the new root filesystem.
+changes the root mount in the mount namespace of the calling process.
+More precisely, it moves the root mount to the
+directory \fIput_old\fP and makes \fInew_root\fP the new root mount.
 The calling process must have the
 .B CAP_SYS_ADMIN
 capability in the user namespace that owns the caller's mount namespace.
 .PP
 .BR pivot_root ()
-may or may not change the current root and the current
-working directory of any processes or threads that
-use the old root directory and which are in
-the same mount namespace as the caller of
-.BR pivot_root ().
-The caller of
-.BR pivot_root ()
-must ensure that processes with root or current working directory
-at the old root operate correctly in either case.
-An easy way to ensure this is to change their
-root and current working directory to \fInew_root\fP before invoking
-.BR pivot_root ().
-.PP
-The paragraph above is intentionally vague because the implementation of
-.BR pivot_root ()
-may change in the future
-(or so it was thought when this system call was first added).
-However,
-the behavior on this point has remained consistent since
-.BR pivot_root ()
-was first implemented:
-.BR pivot_root ()
 changes the root directory and the current working directory
 of each process or thread in the same mount namespace to
 .I new_root
 if they point to the old root directory.
-See also NOTES.
-.PP
-Note that this also applies to the calling process:
+(See also NOTES.)
+On the other hand,
 .BR pivot_root ()
-may or may not affect its current working directory.
-It is therefore recommended to call
-\fBchdir("/")\fP immediately after
-.BR pivot_root ().
+does not change the caller's current working directory
+(unless it is on the old root directory),
+and thus it should be followed by a
+\fBchdir("/")\fP call.
 .PP
 The following restrictions apply:
 .IP \- 3
@@ -68,45 +61,36 @@ and
 .IR put_old
 must be directories.
 .IP \-
-\fInew_root\fP and \fIput_old\fP must not be on the same filesystem as
-the current root.
-In particular,
-.IR new_root
-can't be
-.IR """/"""
-(but can be a bind mounted directory on the current root filesystem).
+.I new_root
+and
+.I put_old
+must not be on the same mount as the current root.
 .IP \-
-\fIput_old\fP must be underneath \fInew_root\fP, that is, adding a nonzero
-number of \fI/..\fP to the string pointed to by \fIput_old\fP must yield
-the same directory as \fInew_root\fP.
+\fIput_old\fP must be at or underneath \fInew_root\fP;
+that is, adding some nonnegative
+number of "\fI/..\fP" prefixes to the pathname pointed to by
+.I put_old
+must yield the same directory as \fInew_root\fP.
 .IP \-
 .I new_root
-must be a mount point.
-(If it is not otherwise a mount point, it suffices to bind mount
-.I new_root
-on top of itself.)
+must be a path to a mount point, but can't be
+.IR """/""" .
+A path that is not already a mount point can be converted into one by
+bind mounting the path onto itself.
 .IP \-
-The propagation type of
-.I new_root
-and its parent mount must not be
+The propagation type of the parent mount of
+.IR new_root
+and the parent mount of the current root directory must not be
 .BR MS_SHARED ;
 similarly, if
 .I put_old
 is an existing mount point, its propagation type must not be
 .BR MS_SHARED .
-.\" FIXME
-.\" mtk: I am very suspicious of the following paragraph. My testing suggests
-.\" that pivot_root() fails with the error EINVAL in the case where
-.\" the current root (after chroot()) is not a mount point. And tehre are
-.\" these lines in pivot_root():
-.\"        error = -EINVAL;
-.\"        if (root.mnt->mnt_root != root.dentry)
-.\"                goto out4; /* not a mountpoint */
-.PP
-If the current root is not a mount point (e.g., after an earlier
-.BR chroot (2)),
-then the mount point of the filesystem containing the current root directory
-(i.e., not the directory itself) is mounted on \fIput_old\fP.
+These restrictions ensure that
+.BR pivot_root ()
+never propagates any changes to another mount namespace.
+.IP \-
+The current root directory must be a mount point.
 .SH RETURN VALUE
 On success, zero is returned.
 On error, \-1 is returned, and
@@ -124,7 +108,7 @@ Additionally, it may fail with the following errors:
 .\" itself. Of course, this is an odd situation, since a later check
 .\" in the kernel code will in any case yield EINVAL if 'new_root' is
 .\" not a mount point. However, when the system call was first added,
-.\" 'new_root' was not required to be a mount point. So, this this
+.\" 'new_root' was not required to be a mount point. So, this
 .\" error is nowadays probably just the result of crufty accumulation.
 .\" This error can also occur if we bind mount "/" on top of itself
 .\" and try to specify "/" as the 'new' (again, an odd situation). So,
@@ -135,7 +119,7 @@ Additionally, it may fail with the following errors:
 .I new_root
 or
 .I put_old
-is on the current root filesystem.
+is on the current root mount.
 (This error covers the pathological case where
 .I new_root
 is
@@ -146,10 +130,15 @@ is
 is not a mount point.
 .TP
 .B EINVAL
-\fIput_old\fP is not underneath \fInew_root\fP.
+\fIput_old\fP is not at or underneath \fInew_root\fP.
 .TP
 .B EINVAL
-The current root is on the rootfs (initial ramfs) filesystem; see NOTES.
+The current root directory is not a mount point
+(because of an earlier
+.BR chroot (2)).
+.TP
+.B EINVAL
+The current root is on the rootfs (initial ramfs) mount; see NOTES.
 .TP
 .B EINVAL
 Either the mount point at
@@ -189,15 +178,17 @@ placing the old root mount at a location under
 .I new_root
 from where it can subsequently be unmounted.
 (The fact that it moves all processes that have a root directory
-or current working directory on the old root filesystem to the
-new root filesystem frees the old root filesystem of users,
-allowing it to be unmounted more easily.)
-A typical use of
+or current working directory on the old root directory to the
+new root frees the old root directory of users,
+allowing the old root mount to be unmounted more easily.)
+.PP
+One use of
 .BR pivot_root ()
 is during system startup, when the
-system mounts a temporary root filesystem (e.g., an \fBinitrd\fP), then
-mounts the real root filesystem, and eventually turns the latter into
-the current root of all relevant processes or threads.
+system mounts a temporary root filesystem (e.g., an
+.BR initrd (4)),
+then mounts the real root filesystem, and eventually turns the latter into
+the root directory of all relevant processes and threads.
 A modern use is to set up a root filesystem during
 the creation of a container.
 .PP
@@ -206,13 +197,9 @@ The fact that
 modifies process root and current working directories in the
 manner noted in DESCRIPTION
 is necessary in order to prevent kernel threads from keeping the old
-root directory busy with their root and current working directory,
+root mount busy with their root and current working directories,
 even if they never access
 the filesystem in any way.
-Perhaps one day there may be a mechanism for
-kernel threads to explicitly relinquish any access to the filesystem,
-such that this fairly intrusive mechanism can be removed from
-.BR pivot_root ().
 .PP
 The rootfs (initial ramfs) cannot be
 .BR pivot_root ()ed.
@@ -225,7 +212,69 @@ and exec the new
 .BR init (1).
 Helper programs for this process exist; see
 .BR switch_root (8).
+.\"
+.SS pivot_root(\(dq.\(dq, \(dq.\(dq)
+.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
+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 old root mount point is unmounted.
+.\"
+.SS Historical notes
+For many years, this manual page carried the following text:
+.RS
+.PP
+.BR pivot_root ()
+may or may not change the current root and the current
+working directory of any processes or threads which use the old
+root directory.
+The caller of
+.BR pivot_root ()
+must ensure that processes with root or current working directory
+at the old root operate correctly in either case.
+An easy way to ensure this is to change their
+root and current working directory to \fInew_root\fP before invoking
+.BR pivot_root ().
+.RE
+.PP
+This text, written before the system call implementation was
+even finalized in the kernel, was probably intended to warn users
+at that time that the implementation might change before final release.
+However, the behavior stated in DESCRIPTION
+has remained consistent since this system call
+was first implemented and will not change now.
 .SH EXAMPLE
+.\" FIXME
+.\" Would it be better, because simpler, to use unshare(2)
+.\" rather than clone(2) in the example below?
 .PP
 The program below demonstrates the use of
 .BR pivot_root ()
@@ -276,6 +325,7 @@ hello world
 #include <sys/mount.h>
 #include <sys/stat.h>
 #include <limits.h>
+#include <sys/mman.h>
 
 #define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \e
                         } while (0)
@@ -320,7 +370,7 @@ child(void *arg)
     if (pivot_root(new_root, path) == \-1)
         errExit("pivot_root");
 
-    /* Switch the current working working directory to "/" */
+    /* Switch the current working directory to "/" */
 
     if (chdir("/") == \-1)
         errExit("chdir");
@@ -343,9 +393,10 @@ main(int argc, char *argv[])
 {
     /* Create a child process in a new mount namespace */
 
-    char *stack = malloc(STACK_SIZE);
-    if (stack == NULL)
-        errExit("malloc");
+    char *stack = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE,
+                       MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, \-1, 0);
+    if (stack == MAP_FAILED)
+        errExit("mmap");
 
     if (clone(child, stack + STACK_SIZE,
                 CLONE_NEWNS | SIGCHLD, &argv[1]) == \-1)