diff options
| author | Michael Kerrisk <mtk.manpages@gmail.com> | 2019-07-28 09:11:29 +0200 |
|---|---|---|
| committer | Michael Kerrisk <mtk.manpages@gmail.com> | 2019-09-23 13:11:19 +0200 |
| commit | 2f2e1a22968523829da906abd0f0660901897380 (patch) | |
| tree | 73012567e0aef92c8659023290c4293f9611974b | |
| parent | 0c2329cdbee7c707888d32ebccee53978417db21 (diff) | |
| download | man-pages-2f2e1a22968523829da906abd0f0660901897380.tar.gz | |
pivot_root.2: Add an example program
Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
| -rw-r--r-- | man2/pivot_root.2 | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/man2/pivot_root.2 b/man2/pivot_root.2 index 9506dc7d1e..a11a31a031 100644 --- a/man2/pivot_root.2 +++ b/man2/pivot_root.2 @@ -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), |
