forked from bloomberg/userchroot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fundamental_devices.c
229 lines (209 loc) · 7.06 KB
/
fundamental_devices.c
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#ifdef _USE_MOUNT_LOFS_INSTEAD_OF_MKNOD
#include <sys/mntent.h>
#include <sys/mount.h>
#endif
#ifdef __linux__
#include <sys/mount.h>
#endif
#include "userchroot.h"
#include "fundamental_devices.h"
static void create_fundamental_device(const char* chroot_path,
const char* device_path) {
int rc;
struct stat realdev;
struct stat chrtdev;
int name_size = strlen(chroot_path) + strlen(device_path) + 1;
char* final_path = malloc(name_size);
if (final_path == NULL) {
fprintf(stderr,"Failed to allocate memory. Aborting.\n");
exit(ERR_EXIT_CODE);
}
rc = snprintf(final_path, name_size, "%s%s", chroot_path, device_path);
if (rc < 0) {
fprintf(stderr,"Failed to produce full path for device. Aborting.\n");
exit(ERR_EXIT_CODE);
}
rc = stat(final_path, &chrtdev);
if (!rc) {
fprintf(stderr,"%s already exists. Aborting.\n", final_path);
exit(ERR_EXIT_CODE);
}
rc = stat(device_path, &realdev);
if (rc) {
fprintf(stderr,"Failed to stat %s. Aborting.\n", device_path);
exit(ERR_EXIT_CODE);
}
// we need to let the devices be created with the appropriate
// modes. However, since the file will be group-owned by
// the user creating the device, we make sure the new mount permissions
// prevent the user from having any permission granted just by the group.
// Clear out existing group permission bits
mode_t device_mode = realdev.st_mode & (~S_IRWXG);
// Set new group permission bits to be identical to other's permission bits
device_mode = device_mode | ((device_mode & S_IRWXO) << 3);
#ifdef _USE_MOUNT_LOFS_INSTEAD_OF_MKNOD
char mount_optbuf[MAX_MNTOPT_STR] = { '\0', };
rc = mkdir(final_path, device_mode);
if (rc) {
fprintf(stderr,"Failed to mkdir %s to mount. Aborting.\n", final_path);
}
rc = mount(device_path, final_path, MS_DATA|MS_OPTIONSTR,
MNTTYPE_LOFS, NULL, 0, mount_optbuf, MAX_MNTOPT_STR);
if (rc) {
fprintf(stderr,"Failed to lofs mount %s.", final_path);
exit(ERR_EXIT_CODE);
}
#else
rc = mknod(final_path, device_mode, realdev.st_rdev);
if (rc) {
fprintf(stderr,"Failed to create the device for %s.", final_path);
exit(ERR_EXIT_CODE);
}
#endif // _USE_MOUNT_LOFS_INSTEAD_OF_MKNOD
free(final_path);
}
static void unlink_fundamental_device(const char* chroot_path,
const char* device_path) {
int rc;
int name_size = strlen(chroot_path) + strlen(device_path) + 1;
char* final_path = malloc(name_size);
if (final_path == NULL) {
fprintf(stderr,"Failed to allocate memory. Aborting.\n");
exit(ERR_EXIT_CODE);
}
rc = snprintf(final_path, name_size, "%s%s", chroot_path, device_path);
if (rc < 0) {
fprintf(stderr,"Failed to produce full path for device. Aborting.\n");
exit(ERR_EXIT_CODE);
}
#ifdef _USE_MOUNT_LOFS_INSTEAD_OF_MKNOD
rc = umount(final_path);
if (rc) {
fprintf(stderr,"Failed to umount %s. Aborting.\n", final_path);
exit(ERR_EXIT_CODE);
}
rc = rmdir(final_path);
if (rc) {
fprintf(stderr,"Failed to rmdir %s. Aborting.\n", final_path);
exit(ERR_EXIT_CODE);
}
rc = rmdir(final_path);
#else
rc = unlink(final_path);
if (rc) {
fprintf(stderr,"Failed to unlink %s. Aborting.\n", final_path);
exit(ERR_EXIT_CODE);
}
#endif // _USE_MOUNT_LOFS_INSTEAD_OF_MKNOD
free(final_path);
}
int create_fundamental_devices(const char* chroot_path) {
mode_t original_mask = umask(0000);
create_fundamental_device(chroot_path,"/dev/null");
create_fundamental_device(chroot_path,"/dev/zero");
create_fundamental_device(chroot_path,"/dev/random");
create_fundamental_device(chroot_path,"/dev/urandom");
// add a mount for /dev/shm for linux only
#ifdef __linux__
char *fullpath = (char *)
malloc(strlen(chroot_path) + strlen("/dev/shm") + 1);
sprintf(fullpath, "%s/dev/shm", chroot_path);
struct stat statbuf;
mode_t perms = (0777 | S_ISVTX);
// clean up from a previous run and set up for this one
umount2(fullpath, MNT_FORCE);
rmdir(fullpath);
mkdir(fullpath, perms);
if (chown(fullpath, 0, 0) < 0)
{
fprintf(stderr, "Could not chown %s to root. Aborting.\n", fullpath);
exit(ERR_EXIT_CODE);
}
if (chmod(fullpath, perms) < 0)
{
fprintf(stderr, "Could not chmod %s to 777+sticky. Aborting.\n",
fullpath);
exit(ERR_EXIT_CODE);
}
if (stat(fullpath, &statbuf) < 0)
{
fprintf(stderr, "Could not stat %s. Aborting.\n", fullpath);
exit(ERR_EXIT_CODE);
}
if (!S_ISDIR(statbuf.st_mode))
{
fprintf(stderr, "%s not a directory. Aborting.\n", fullpath);
exit(ERR_EXIT_CODE);
}
if ((statbuf.st_mode & perms) != perms)
{
fprintf(stderr, "Wrong perms on %s. Aborting.\n", fullpath);
exit(ERR_EXIT_CODE);
}
if (mount("tmpfs", fullpath, "tmpfs", MS_MGC_VAL, "size=128m") < 0)
{
fprintf(stderr, "Could not mount %s. Aborting.\n", fullpath);
exit(ERR_EXIT_CODE);
}
free(fullpath);
#endif
// add mount for /dev/poll on Solaris
#if defined(sun) || defined(__sun)
create_fundamental_device(chroot_path,"/dev/poll");
#endif
umask(original_mask);
return 0;
}
int unlink_fundamental_devices(const char* chroot_path) {
unlink_fundamental_device(chroot_path,"/dev/null");
unlink_fundamental_device(chroot_path,"/dev/zero");
unlink_fundamental_device(chroot_path,"/dev/random");
unlink_fundamental_device(chroot_path,"/dev/urandom");
// unmount /dev/shm for linux only
#ifdef __linux__
char *fullpath = (char *)
malloc(strlen(chroot_path) + strlen("/dev/shm") + 1);
sprintf(fullpath, "%s/dev/shm", chroot_path);
if (umount2(fullpath, MNT_FORCE) < 0)
{
fprintf(stderr, "Could not unmount %s (%s). Aborting.\n",
fullpath, strerror(errno));
exit(ERR_EXIT_CODE);
}
if (rmdir(fullpath) < 0)
{
fprintf(stderr, "Could not rmdir %s (%s). Aborting.\n",
fullpath, strerror(errno));
exit(ERR_EXIT_CODE);
}
free(fullpath);
#endif
// unmount /dev/poll on Solaris
#if defined(sun) || defined(__sun)
unlink_fundamental_device(chroot_path,"/dev/poll");
#endif
return 0;
}
// ----------------------------------------------------------------------------
// Copyright 2015 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------