-
Notifications
You must be signed in to change notification settings - Fork 56
Expand file tree
/
Copy pathchroot.c
More file actions
150 lines (128 loc) · 4.91 KB
/
chroot.c
File metadata and controls
150 lines (128 loc) · 4.91 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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#define _GNU_SOURCE
#include <slurm/spank.h>
#include <slurm/slurm_errno.h>
#include <stdlib.h>
#include <stdint.h>
#include <sched.h>
#include <stdio.h>
#include <sys/mount.h>
#include <sys/syscall.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
// pivot_root is not available directly in glibc, so we use syscall
#ifndef SYS_pivot_root
#error "SYS_pivot_root unavailable on this system"
#endif
SPANK_PLUGIN("chroot", 1);
// The following Slurm job step IDs are copied from the Slurm source code:
//
// Max job step ID of normal step
#define SLURM_MAX_NORMAL_STEP_ID (0xfffffff0)
// Job step ID of pending step
#define SLURM_PENDING_STEP (0xfffffffd)
// Job step ID of external process container
#define SLURM_EXTERN_CONT (0xfffffffc)
// Job step ID of batch scripts
#define SLURM_BATCH_SCRIPT (0xfffffffb)
// Job step ID for the interactive step (if used)
#define SLURM_INTERACTIVE_STEP (0xfffffffa)
int change_root(const char *jail_path) {
slurm_debug("chroot: change_root: Initialize host_in_jail_path = jail_path + /mnt/host");
char host_in_jail_path[256];
host_in_jail_path[0] = '\0'; // Initialize to an empty string
if (strlen(jail_path) + strlen("/mnt/host") + 1 > sizeof(host_in_jail_path)) {
fprintf(stderr, "host_in_jail_path buffer is not large enough to hold the concatenated string\n");
return 10;
}
strcat(host_in_jail_path, jail_path);
strcat(host_in_jail_path, "/mnt/host");
slurm_debug("chroot: change_root: Create new mount namespace for the current process");
if (unshare(CLONE_NEWNS) != 0) {
fprintf(stderr, "unshare --mount: %s\n", strerror(errno));
return 20;
}
slurm_debug("chroot: change_root: Remount old root / as slave");
if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) != 0) {
fprintf(stderr, "mount --make-rslave /: %s\n", strerror(errno));
return 30;
}
slurm_debug("chroot: change_root: Pivot jail and host roots");
if (syscall(SYS_pivot_root, jail_path, host_in_jail_path) != 0) {
fprintf(stderr, "pivot_root ${jail_path} ${jail_path}/mnt/host: %s\n", strerror(errno));
return 40;
}
slurm_debug("chroot: change_root: Unmount old root /mnt/host from jail");
if (umount2("/mnt/host", MNT_DETACH) != 0) {
fprintf(stderr, "umount -R /mnt/host: %s\n", strerror(errno));
return 50;
}
slurm_debug("chroot: change_root: Change directory into new root /");
if (chdir("/") != 0) {
fprintf(stderr, "chdir /: %s\n", strerror(errno));
return 60;
}
return 0;
}
int remount_proc() {
slurm_debug("chroot: remount_proc: Remount /proc as slave");
if (mount(NULL, "/proc", NULL, MS_SLAVE | MS_REC, NULL) != 0) {
fprintf(stderr, "mount --make-rslave /proc: %s\n", strerror(errno));
return 10;
}
slurm_debug("chroot: remount_proc: Unmount /proc");
if (umount2("/proc", MNT_DETACH) != 0) {
fprintf(stderr, "umount -R /proc: %s\n", strerror(errno));
return 20;
}
slurm_debug("chroot: remount_proc: Mount /proc again");
if (mount("proc", "/proc", "proc", 0, NULL) != 0) {
fprintf(stderr, "mount -t /proc proc/: %s\n", strerror(errno));
return 30;
}
return 0;
}
int slurm_spank_init_post_opt(spank_t spank, int argc, char **argv) {
spank_context_t spank_ctx = spank_context();
if (spank_ctx != S_CTX_REMOTE) {
slurm_debug("chroot: init_post_opt: Called not in remote context, exit");
return ESPANK_SUCCESS;
}
if (argc != 1) {
fprintf(stderr, "expected 1 plugin argument: <path_to_jail>, but got %d arguments\n", argc);
return 100;
}
char *jail_path = argv[0];
uint32_t job_stepid = 0;
spank_get_item(spank, S_JOB_STEPID, &job_stepid);
// Possible job step ids:
// - SLURM_MAX_NORMAL_STEP_ID (any normal job step ID has ID less or equal to that)
// - SLURM_PENDING_STEP
// - SLURM_EXTERN_CONT
// - SLURM_BATCH_SCRIPT
// - SLURM_INTERACTIVE_STEP
if (job_stepid <= SLURM_MAX_NORMAL_STEP_ID) {
slurm_debug("chroot: init_post_opt: Called in normal job step");
} else if (job_stepid == SLURM_BATCH_SCRIPT) {
slurm_debug("chroot: init_post_opt: Called in batch job step");
} else if (job_stepid == SLURM_INTERACTIVE_STEP) {
slurm_debug("chroot: init_post_opt: Called in interactive job step");
} else {
slurm_debug("chroot: init_post_opt: Called not in batch or normal job step, exit");
return ESPANK_SUCCESS;
}
slurm_debug("chroot: init_post_opt: Enter jail environment");
int res = -1;
slurm_debug("chroot: init_post_opt: Change the process root into %s", jail_path);
res = change_root(jail_path);
if (res != 0) {
return 200 + res;
}
slurm_debug("chroot: init_post_opt: Remount /proc in jail");
res = remount_proc();
if (res != 0) {
return 300 + res;
}
return ESPANK_SUCCESS;
}