pivot_root.2: Add an example program

Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
This commit is contained in:
Michael Kerrisk 2019-07-28 09:11:29 +02:00
parent 0c2329cdbe
commit 2f2e1a2296
1 changed files with 134 additions and 0 deletions

View File

@ -195,6 +195,140 @@ Some of the more obscure uses of
.BR pivot_root ()
may quickly lead to
insanity.
.SH EXAMPLE
.PP
The program below demonstrates the use of
.BR pivot_root ()
inside a mount namespace that is created using
.BR clone (2).
After pivoting to the root directory named in the program's
first command-line argument, the child created by
.BR clone (2)
then executes the program named in the remaining command-line arguments.
.PP
We demonstrate the program by creating a directory that will serve as
the new root filesystem and placing a copy of the (statically linked)
.BR busybox (1)
executable in that directory.
.PP
.in +4n
.EX
$ \fBmkdir /tmp/rootfs\fP
$ \fBls \-id /tmp/rootfs\fP # Show inode number of new root directory
319459 /tmp/rootfs
$ \fBcp $(which busybox) /tmp/rootfs\fP
$ \fBPS1='bbsh$ ' sudo ./pivot_root_demo /tmp/rootfs /busybox sh\fP
bbsh$ \fBPATH=/\fP
bbsh$ \fBbusybox ln busybox ln\fP
bbsh$ \fBln busybox echo\fP
bbsh$ \fBln busybox ls\fP
bbsh$ \fBls\fP
busybox echo ln ls
bbsh$ \fBls \-id /\fP # Compare with inode number above
319459 /
bbsh$ \fBecho \(aqhello world\(aq\fP
hello world
.EE
.in
.SS Program source
\&
.PP
.EX
/* pivot_root_demo.c */
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/syscall.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <limits.h>
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \e
} while (0)
static int
pivot_root(const char *new_root, const char *put_old)
{
return syscall(SYS_pivot_root, new_root, put_old);
}
#define STACK_SIZE (1024 * 1024)
static int /* Startup function for cloned child */
child(void *arg)
{
char **args = arg;
char *new_root = args[0];
const char *put_old = "/oldrootfs";
char path[PATH_MAX];
/* Ensure that \(aqnew_root\(aq and its parent mount don\(aqt have
shared propagation (which would cause pivot_root() to
return an error), and prevent propagation of mount
events to the initial mount namespace */
if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL) == 1)
errExit("mount\-MS_PRIVATE");
/* Ensure that \(aqnew_root\(aq is a mount point */
if (mount(new_root, new_root, NULL, MS_BIND, NULL) == \-1)
errExit("mount\-MS_BIND");
/* Create directory to which old root will be pivoted */
snprintf(path, sizeof(path), "%s/%s", new_root, put_old);
if (mkdir(path, 0777) == \-1)
errExit("mkdir");
/* And pivot the root filesystem */
if (pivot_root(new_root, path) == \-1)
errExit("pivot_root");
/* Switch the current working working directory to "/" */
if (chdir("/") == \-1)
errExit("chdir");
/* Unmount old root and remove mount point */
if (umount2(put_old, MNT_DETACH) == \-1)
perror("umount2");
if (rmdir(put_old) == \-1)
perror("rmdir");
/* Execute the command specified in argv[1]... */
execv(args[1], &args[1]);
errExit("execv");
}
int
main(int argc, char *argv[])
{
/* Create a child process in a new mount namespace */
char *stack = malloc(STACK_SIZE);
if (stack == NULL)
errExit("malloc");
if (clone(child, stack + STACK_SIZE,
CLONE_NEWNS | SIGCHLD, &argv[1]) == \-1)
errExit("clone");
/* Parent falls through to here; wait for child */
if (wait(NULL) == \-1)
errExit("wait");
exit(EXIT_SUCCESS);
}
.EE
.SH SEE ALSO
.BR chdir (2),
.BR chroot (2),