-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathchange_root.c
More file actions
71 lines (59 loc) · 1.81 KB
/
change_root.c
File metadata and controls
71 lines (59 loc) · 1.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#define _GNU_SOURCE
#include "change_root.h"
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <linux/limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <unistd.h>
/**
* `change_root` uses the pivot_root syscall to change the root of the file
* system to the given path.
* In addition, it mounts the new `/dev` and `/proc`, and configures `PATH`.
*/
void change_root(const char* path) {
/* before calling `pivot_root`, unmount `/proc` */
if (umount2("/proc", MNT_DETACH) < 0) {
err(1, "unmount proc");
}
/* now, use `pivot_root` */
char old_path[PATH_MAX];
char old_root[PATH_MAX];
char new_root[PATH_MAX];
realpath(path, new_root);
sprintf(old_path, "%s/.old_root", new_root);
realpath(old_path, old_root);
if (mount(new_root, new_root, "bind", MS_BIND | MS_REC, "") < 0) {
err(1, "Failed to bind mount new root");
}
if (mkdir(old_root, 0700) < 0 && errno != EEXIST) {
err(1, "Failed to create a directory to store old root");
}
if (syscall(SYS_pivot_root, new_root, old_root) < 0) {
err(1, "Failed to pivot_root");
}
chdir("/");
if (umount2("/.old_root", MNT_DETACH) < 0) {
err(1, "Failed to unmount old root");
}
if (rmdir("/.old_root") < 0) {
err(1, "Failed to remove old root");
}
/* few more things to make the container work properly */
// mount new /dev
if (mount("devtmpfs", "/dev", "devtmpfs", MS_NOSUID | MS_RELATIME, NULL) <
0) {
err(1, "mount devtmpfs");
}
// mount new /proc
if (mount("proc", "/proc", "proc",
MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME, NULL) < 0) {
err(1, "mount proc");
}
// set `PATH` so container can execute commands
setenv("PATH", "/bin:/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin", 1);
}