aboutsummaryrefslogtreecommitdiffstats
path: root/src/firejail/fs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/firejail/fs.c')
-rw-r--r--src/firejail/fs.c857
1 files changed, 410 insertions, 447 deletions
diff --git a/src/firejail/fs.c b/src/firejail/fs.c
index 7ee76d096..7ff7e3c59 100644
--- a/src/firejail/fs.c
+++ b/src/firejail/fs.c
@@ -27,198 +27,9 @@
27#include <fcntl.h> 27#include <fcntl.h>
28#include <errno.h> 28#include <errno.h>
29 29
30static void create_empty_dir(void) { 30static void fs_rdwr(const char *dir);
31 struct stat s;
32
33 if (stat(RUN_RO_DIR, &s)) {
34 /* coverity[toctou] */
35 int rv = mkdir(RUN_RO_DIR, S_IRUSR | S_IXUSR);
36 if (rv == -1)
37 errExit("mkdir");
38 if (chown(RUN_RO_DIR, 0, 0) < 0)
39 errExit("chown");
40 }
41}
42
43static void create_empty_file(void) {
44 struct stat s;
45
46 if (stat(RUN_RO_FILE, &s)) {
47 /* coverity[toctou] */
48 FILE *fp = fopen(RUN_RO_FILE, "w");
49 if (!fp)
50 errExit("fopen");
51 fclose(fp);
52 if (chown(RUN_RO_FILE, 0, 0) < 0)
53 errExit("chown");
54 if (chmod(RUN_RO_FILE, S_IRUSR) < 0)
55 errExit("chown");
56 }
57}
58
59// build /run/firejail directory
60void fs_build_firejail_dir(void) {
61 struct stat s;
62
63 // CentOS 6 doesn't have /run directory
64 if (stat(RUN_FIREJAIL_BASEDIR, &s)) {
65 if (arg_debug)
66 printf("Creating %s directory\n", RUN_FIREJAIL_BASEDIR);
67 /* coverity[toctou] */
68 int rv = mkdir(RUN_FIREJAIL_BASEDIR, 0755);
69 if (rv == -1)
70 errExit("mkdir");
71 if (chown(RUN_FIREJAIL_BASEDIR, 0, 0) < 0)
72 errExit("chown");
73 if (chmod(RUN_FIREJAIL_BASEDIR, 0755) < 0)
74 errExit("chmod");
75 }
76 else { // check /tmp/firejail directory belongs to root end exit if doesn't!
77 if (s.st_uid != 0 || s.st_gid != 0) {
78 fprintf(stderr, "Error: non-root %s directory, exiting...\n", RUN_FIREJAIL_DIR);
79 exit(1);
80 }
81 }
82
83 if (stat(RUN_FIREJAIL_DIR, &s)) {
84 if (arg_debug)
85 printf("Creating %s directory\n", RUN_FIREJAIL_DIR);
86 /* coverity[toctou] */
87 int rv = mkdir(RUN_FIREJAIL_DIR, 0755);
88 if (rv == -1)
89 errExit("mkdir");
90 if (chown(RUN_FIREJAIL_DIR, 0, 0) < 0)
91 errExit("chown");
92 if (chmod(RUN_FIREJAIL_DIR, 0755) < 0)
93 errExit("chmod");
94 }
95
96 if (stat(RUN_FIREJAIL_NETWORK_DIR, &s)) {
97 if (arg_debug)
98 printf("Creating %s directory\n", RUN_FIREJAIL_NETWORK_DIR);
99
100 if (mkdir(RUN_FIREJAIL_NETWORK_DIR, 0755) == -1)
101 errExit("mkdir");
102 if (chown(RUN_FIREJAIL_NETWORK_DIR, 0, 0) < 0)
103 errExit("chown");
104 if (chmod(RUN_FIREJAIL_NETWORK_DIR, 0755) < 0)
105 errExit("chmod");
106 }
107
108 if (stat(RUN_FIREJAIL_BANDWIDTH_DIR, &s)) {
109 if (arg_debug)
110 printf("Creating %s directory\n", RUN_FIREJAIL_BANDWIDTH_DIR);
111 if (mkdir(RUN_FIREJAIL_BANDWIDTH_DIR, 0755) == -1)
112 errExit("mkdir");
113 if (chown(RUN_FIREJAIL_BANDWIDTH_DIR, 0, 0) < 0)
114 errExit("chown");
115 if (chmod(RUN_FIREJAIL_BANDWIDTH_DIR, 0755) < 0)
116 errExit("chmod");
117 }
118
119 if (stat(RUN_FIREJAIL_NAME_DIR, &s)) {
120 if (arg_debug)
121 printf("Creating %s directory\n", RUN_FIREJAIL_NAME_DIR);
122 if (mkdir(RUN_FIREJAIL_NAME_DIR, 0755) == -1)
123 errExit("mkdir");
124 if (chown(RUN_FIREJAIL_NAME_DIR, 0, 0) < 0)
125 errExit("chown");
126 if (chmod(RUN_FIREJAIL_NAME_DIR, 0755) < 0)
127 errExit("chmod");
128 }
129
130 if (stat(RUN_FIREJAIL_X11_DIR, &s)) {
131 if (arg_debug)
132 printf("Creating %s directory\n", RUN_FIREJAIL_X11_DIR);
133 if (mkdir(RUN_FIREJAIL_X11_DIR, 0755) == -1)
134 errExit("mkdir");
135 if (chown(RUN_FIREJAIL_X11_DIR, 0, 0) < 0)
136 errExit("chown");
137 if (chmod(RUN_FIREJAIL_X11_DIR, 0755) < 0)
138 errExit("chmod");
139 }
140
141 create_empty_dir();
142 create_empty_file();
143}
144 31
145 32
146// build /tmp/firejail/mnt directory
147static int tmpfs_mounted = 0;
148#ifdef HAVE_CHROOT
149static void fs_build_remount_mnt_dir(void) {
150 tmpfs_mounted = 0;
151 fs_build_mnt_dir();
152}
153#endif
154
155void fs_build_mnt_dir(void) {
156 struct stat s;
157 fs_build_firejail_dir();
158
159 // create /run/firejail/mnt directory
160 if (stat(RUN_MNT_DIR, &s)) {
161 if (arg_debug)
162 printf("Creating %s directory\n", RUN_MNT_DIR);
163 /* coverity[toctou] */
164 int rv = mkdir(RUN_MNT_DIR, 0755);
165 if (rv == -1)
166 errExit("mkdir");
167 if (chown(RUN_MNT_DIR, 0, 0) < 0)
168 errExit("chown");
169 if (chmod(RUN_MNT_DIR, 0755) < 0)
170 errExit("chmod");
171 }
172
173 // ... and mount tmpfs on top of it
174 if (!tmpfs_mounted) {
175 // mount tmpfs on top of /run/firejail/mnt
176 if (arg_debug)
177 printf("Mounting tmpfs on %s directory\n", RUN_MNT_DIR);
178 if (mount("tmpfs", RUN_MNT_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
179 errExit("mounting /tmp/firejail/mnt");
180 tmpfs_mounted = 1;
181 fs_logger2("tmpfs", RUN_MNT_DIR);
182 }
183}
184
185// grab a copy of cp command
186void fs_build_cp_command(void) {
187 struct stat s;
188 fs_build_mnt_dir();
189 if (stat(RUN_CP_COMMAND, &s)) {
190 char* fname = realpath("/bin/cp", NULL);
191 if (fname == NULL) {
192 fprintf(stderr, "Error: /bin/cp not found\n");
193 exit(1);
194 }
195 if (stat(fname, &s)) {
196 fprintf(stderr, "Error: /bin/cp not found\n");
197 exit(1);
198 }
199 if (is_link(fname)) {
200 fprintf(stderr, "Error: invalid /bin/cp file\n");
201 exit(1);
202 }
203 int rv = copy_file(fname, RUN_CP_COMMAND);
204 if (rv) {
205 fprintf(stderr, "Error: cannot access /bin/cp\n");
206 exit(1);
207 }
208 /* coverity[toctou] */
209 if (chown(RUN_CP_COMMAND, 0, 0))
210 errExit("chown");
211 if (chmod(RUN_CP_COMMAND, 0755))
212 errExit("chmod");
213
214 free(fname);
215 }
216}
217
218// delete the temporary cp command
219void fs_delete_cp_command(void) {
220 unlink(RUN_CP_COMMAND);
221}
222 33
223//*********************************************** 34//***********************************************
224// process profile file 35// process profile file
@@ -228,6 +39,8 @@ typedef enum {
228 BLACKLIST_NOLOG, 39 BLACKLIST_NOLOG,
229 MOUNT_READONLY, 40 MOUNT_READONLY,
230 MOUNT_TMPFS, 41 MOUNT_TMPFS,
42 MOUNT_NOEXEC,
43 MOUNT_RDWR,
231 OPERATION_MAX 44 OPERATION_MAX
232} OPERATION; 45} OPERATION;
233 46
@@ -242,14 +55,9 @@ static void disable_file(OPERATION op, const char *filename) {
242 assert(op <OPERATION_MAX); 55 assert(op <OPERATION_MAX);
243 last_disable = UNSUCCESSFUL; 56 last_disable = UNSUCCESSFUL;
244 57
245 // rebuild /run/firejail directory in case tmpfs was mounted on top of /run
246 fs_build_firejail_dir();
247
248 // Resolve all symlinks 58 // Resolve all symlinks
249 char* fname = realpath(filename, NULL); 59 char* fname = realpath(filename, NULL);
250 if (fname == NULL && errno != EACCES) { 60 if (fname == NULL && errno != EACCES) {
251 if (arg_debug)
252 printf("Warning (realpath): %s is an invalid file, skipping...\n", filename);
253 return; 61 return;
254 } 62 }
255 if (fname == NULL && errno == EACCES) { 63 if (fname == NULL && errno == EACCES) {
@@ -298,9 +106,10 @@ static void disable_file(OPERATION op, const char *filename) {
298 // some distros put all executables under /usr/bin and make /bin a symbolic link 106 // some distros put all executables under /usr/bin and make /bin a symbolic link
299 if ((strcmp(fname, "/bin") == 0 || strcmp(fname, "/usr/bin") == 0) && 107 if ((strcmp(fname, "/bin") == 0 || strcmp(fname, "/usr/bin") == 0) &&
300 is_link(filename) && 108 is_link(filename) &&
301 S_ISDIR(s.st_mode)) 109 S_ISDIR(s.st_mode)) {
302 fprintf(stderr, "Warning: %s directory link was not blacklisted\n", filename); 110 if (!arg_quiet)
303 111 fprintf(stderr, "Warning: %s directory link was not blacklisted\n", filename);
112 }
304 else { 113 else {
305 if (arg_debug) 114 if (arg_debug)
306 printf("Disable %s\n", fname); 115 printf("Disable %s\n", fname);
@@ -332,6 +141,18 @@ static void disable_file(OPERATION op, const char *filename) {
332 fs_rdonly(fname); 141 fs_rdonly(fname);
333// todo: last_disable = SUCCESSFUL; 142// todo: last_disable = SUCCESSFUL;
334 } 143 }
144 else if (op == MOUNT_RDWR) {
145 if (arg_debug)
146 printf("Mounting read-only %s\n", fname);
147 fs_rdwr(fname);
148// todo: last_disable = SUCCESSFUL;
149 }
150 else if (op == MOUNT_NOEXEC) {
151 if (arg_debug)
152 printf("Mounting noexec %s\n", fname);
153 fs_noexec(fname);
154// todo: last_disable = SUCCESSFUL;
155 }
335 else if (op == MOUNT_TMPFS) { 156 else if (op == MOUNT_TMPFS) {
336 if (S_ISDIR(s.st_mode)) { 157 if (S_ISDIR(s.st_mode)) {
337 if (arg_debug) 158 if (arg_debug)
@@ -361,7 +182,7 @@ static void globbing(OPERATION op, const char *pattern, const char *noblacklist[
361 glob_t globbuf; 182 glob_t globbuf;
362 // Profiles contain blacklists for files that might not exist on a user's machine. 183 // Profiles contain blacklists for files that might not exist on a user's machine.
363 // GLOB_NOCHECK makes that okay. 184 // GLOB_NOCHECK makes that okay.
364 int globerr = glob(pattern, GLOB_NOCHECK | GLOB_NOSORT, NULL, &globbuf); 185 int globerr = glob(pattern, GLOB_NOCHECK | GLOB_NOSORT | GLOB_PERIOD, NULL, &globbuf);
365 if (globerr) { 186 if (globerr) {
366 fprintf(stderr, "Error: failed to glob pattern %s\n", pattern); 187 fprintf(stderr, "Error: failed to glob pattern %s\n", pattern);
367 exit(1); 188 exit(1);
@@ -426,21 +247,13 @@ void fs_blacklist(void) {
426 247
427 // process bind command 248 // process bind command
428 if (strncmp(entry->data, "bind ", 5) == 0) { 249 if (strncmp(entry->data, "bind ", 5) == 0) {
250 struct stat s;
429 char *dname1 = entry->data + 5; 251 char *dname1 = entry->data + 5;
430 char *dname2 = split_comma(dname1); 252 char *dname2 = split_comma(dname1);
431 if (dname2 == NULL) { 253 if (dname2 == NULL ||
432 fprintf(stderr, "Error: second directory missing in bind command\n"); 254 stat(dname1, &s) == -1 ||
433 entry = entry->next; 255 stat(dname2, &s) == -1) {
434 continue; 256 fprintf(stderr, "Error: invalid bind command, directory missing\n");
435 }
436 struct stat s;
437 if (stat(dname1, &s) == -1) {
438 fprintf(stderr, "Error: cannot find %s for bind command\n", dname1);
439 entry = entry->next;
440 continue;
441 }
442 if (stat(dname2, &s) == -1) {
443 fprintf(stderr, "Error: cannot find %s for bind command\n", dname2);
444 entry = entry->next; 257 entry = entry->next;
445 continue; 258 continue;
446 } 259 }
@@ -452,11 +265,8 @@ void fs_blacklist(void) {
452 if (mount(dname1, dname2, NULL, MS_BIND|MS_REC, NULL) < 0) 265 if (mount(dname1, dname2, NULL, MS_BIND|MS_REC, NULL) < 0)
453 errExit("mount bind"); 266 errExit("mount bind");
454 /* coverity[toctou] */ 267 /* coverity[toctou] */
455 if (chown(dname2, s.st_uid, s.st_gid) == -1) 268 if (set_perms(dname2, s.st_uid, s.st_gid,s.st_mode))
456 errExit("mount-bind chown"); 269 errExit("set_perms");
457 /* coverity[toctou] */
458 if (chmod(dname2, s.st_mode) == -1)
459 errExit("mount-bind chmod");
460 270
461 entry = entry->next; 271 entry = entry->next;
462 continue; 272 continue;
@@ -464,12 +274,40 @@ void fs_blacklist(void) {
464 274
465 // Process noblacklist command 275 // Process noblacklist command
466 if (strncmp(entry->data, "noblacklist ", 12) == 0) { 276 if (strncmp(entry->data, "noblacklist ", 12) == 0) {
467 if (noblacklist_c >= noblacklist_m) { 277 char **paths = build_paths();
468 noblacklist_m *= 2; 278
469 noblacklist = realloc(noblacklist, sizeof(*noblacklist) * noblacklist_m); 279 char *enames[sizeof(paths)+1] = {0};
470 if (noblacklist == NULL) 280 int i = 0;
471 errExit("failed increasing memory for noblacklist entries");} 281
472 noblacklist[noblacklist_c++] = expand_home(entry->data + 12, homedir); 282 if (strncmp(entry->data + 12, "${PATH}", 7) == 0) {
283 // expand ${PATH} macro
284 while (paths[i] != NULL) {
285 if (asprintf(&enames[i], "%s%s", paths[i], entry->data + 19) == -1)
286 errExit("asprintf");
287 i++;
288 }
289 } else {
290 // expand ${HOME} macro if found or pass as is
291 enames[0] = expand_home(entry->data + 12, homedir);
292 enames[1] = NULL;
293 }
294
295 i = 0;
296 while (enames[i] != NULL) {
297 if (noblacklist_c >= noblacklist_m) {
298 noblacklist_m *= 2;
299 noblacklist = realloc(noblacklist, sizeof(*noblacklist) * noblacklist_m);
300 if (noblacklist == NULL)
301 errExit("failed increasing memory for noblacklist entries");
302 }
303 noblacklist[noblacklist_c++] = enames[i];
304 i++;
305 }
306
307 while (enames[i] != NULL) {
308 free(enames[i]);
309 }
310
473 entry = entry->next; 311 entry = entry->next;
474 continue; 312 continue;
475 } 313 }
@@ -487,10 +325,32 @@ void fs_blacklist(void) {
487 ptr = entry->data + 10; 325 ptr = entry->data + 10;
488 op = MOUNT_READONLY; 326 op = MOUNT_READONLY;
489 } 327 }
328 else if (strncmp(entry->data, "read-write ", 11) == 0) {
329 ptr = entry->data + 11;
330 op = MOUNT_RDWR;
331 }
332 else if (strncmp(entry->data, "noexec ", 7) == 0) {
333 ptr = entry->data + 7;
334 op = MOUNT_NOEXEC;
335 }
490 else if (strncmp(entry->data, "tmpfs ", 6) == 0) { 336 else if (strncmp(entry->data, "tmpfs ", 6) == 0) {
491 ptr = entry->data + 6; 337 ptr = entry->data + 6;
492 op = MOUNT_TMPFS; 338 op = MOUNT_TMPFS;
493 } 339 }
340 else if (strncmp(entry->data, "mkdir ", 6) == 0) {
341 EUID_USER();
342 fs_mkdir(entry->data + 6);
343 EUID_ROOT();
344 entry = entry->next;
345 continue;
346 }
347 else if (strncmp(entry->data, "mkfile ", 7) == 0) {
348 EUID_USER();
349 fs_mkfile(entry->data + 7);
350 EUID_ROOT();
351 entry = entry->next;
352 continue;
353 }
494 else { 354 else {
495 fprintf(stderr, "Error: invalid profile line %s\n", entry->data); 355 fprintf(stderr, "Error: invalid profile line %s\n", entry->data);
496 entry = entry->next; 356 entry = entry->next;
@@ -542,38 +402,56 @@ void fs_rdonly(const char *dir) {
542 int rv = stat(dir, &s); 402 int rv = stat(dir, &s);
543 if (rv == 0) { 403 if (rv == 0) {
544 // mount --bind /bin /bin 404 // mount --bind /bin /bin
545 if (mount(dir, dir, NULL, MS_BIND|MS_REC, NULL) < 0)
546 errExit("mount read-only");
547 // mount --bind -o remount,ro /bin 405 // mount --bind -o remount,ro /bin
548 if (mount(NULL, dir, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY|MS_REC, NULL) < 0) 406 if (mount(dir, dir, NULL, MS_BIND|MS_REC, NULL) < 0 ||
407 mount(NULL, dir, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY|MS_REC, NULL) < 0)
549 errExit("mount read-only"); 408 errExit("mount read-only");
550 fs_logger2("read-only", dir); 409 fs_logger2("read-only", dir);
551 } 410 }
552} 411}
553void fs_rdonly_noexit(const char *dir) { 412
413static void fs_rdwr(const char *dir) {
414 assert(dir);
415 // check directory exists
416 struct stat s;
417 int rv = stat(dir, &s);
418 if (rv == 0) {
419 // if the file is outside /home directory, allow only root user
420 uid_t u = getuid();
421 if (u != 0 && s.st_uid != u) {
422 if (!arg_quiet)
423 fprintf(stderr, "Warning: you are not allowed to change %s to read-write\n", dir);
424 return;
425 }
426
427 // mount --bind /bin /bin
428 // mount --bind -o remount,rw /bin
429 if (mount(dir, dir, NULL, MS_BIND|MS_REC, NULL) < 0 ||
430 mount(NULL, dir, NULL, MS_BIND|MS_REMOUNT|MS_REC, NULL) < 0)
431 errExit("mount read-write");
432 fs_logger2("read-write", dir);
433 }
434}
435
436void fs_noexec(const char *dir) {
554 assert(dir); 437 assert(dir);
555 // check directory exists 438 // check directory exists
556 struct stat s; 439 struct stat s;
557 int rv = stat(dir, &s); 440 int rv = stat(dir, &s);
558 if (rv == 0) { 441 if (rv == 0) {
559 int merr = 0;
560 // mount --bind /bin /bin 442 // mount --bind /bin /bin
561 if (mount(dir, dir, NULL, MS_BIND|MS_REC, NULL) < 0)
562 merr = 1;
563 // mount --bind -o remount,ro /bin 443 // mount --bind -o remount,ro /bin
564 if (mount(NULL, dir, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY|MS_REC, NULL) < 0) 444 if (mount(dir, dir, NULL, MS_BIND|MS_REC, NULL) < 0 ||
565 merr = 1; 445 mount(NULL, dir, NULL, MS_BIND|MS_REMOUNT|MS_NOEXEC|MS_NODEV|MS_NOSUID|MS_REC, NULL) < 0)
566 if (merr) 446 errExit("mount noexec");
567 fprintf(stderr, "Warning: cannot mount %s read-only\n", dir); 447 fs_logger2("noexec", dir);
568 else
569 fs_logger2("read-only", dir);
570 } 448 }
571} 449}
572 450
451
452
573// mount /proc and /sys directories 453// mount /proc and /sys directories
574void fs_proc_sys_dev_boot(void) { 454void fs_proc_sys_dev_boot(void) {
575 struct stat s;
576
577 if (arg_debug) 455 if (arg_debug)
578 printf("Remounting /proc and /proc/sys filesystems\n"); 456 printf("Remounting /proc and /proc/sys filesystems\n");
579 if (mount("proc", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0) 457 if (mount("proc", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0)
@@ -581,10 +459,8 @@ void fs_proc_sys_dev_boot(void) {
581 fs_logger("remount /proc"); 459 fs_logger("remount /proc");
582 460
583 // remount /proc/sys readonly 461 // remount /proc/sys readonly
584 if (mount("/proc/sys", "/proc/sys", NULL, MS_BIND | MS_REC, NULL) < 0) 462 if (mount("/proc/sys", "/proc/sys", NULL, MS_BIND | MS_REC, NULL) < 0 ||
585 errExit("mounting /proc/sys"); 463 mount(NULL, "/proc/sys", NULL, MS_BIND | MS_REMOUNT | MS_RDONLY | MS_REC, NULL) < 0)
586
587 if (mount(NULL, "/proc/sys", NULL, MS_BIND | MS_REMOUNT | MS_RDONLY | MS_REC, NULL) < 0)
588 errExit("mounting /proc/sys"); 464 errExit("mounting /proc/sys");
589 fs_logger("read-only /proc/sys"); 465 fs_logger("read-only /proc/sys");
590 466
@@ -601,114 +477,71 @@ void fs_proc_sys_dev_boot(void) {
601 fs_logger("remount /sys"); 477 fs_logger("remount /sys");
602 } 478 }
603 479
604 if (stat("/sys/firmware", &s) == 0) { 480 disable_file(BLACKLIST_FILE, "/sys/firmware");
605 disable_file(BLACKLIST_FILE, "/sys/firmware"); 481 disable_file(BLACKLIST_FILE, "/sys/hypervisor");
606 } 482 { // allow user access to /sys/fs if "--noblacklist=/sys/fs" is present on the command line
607 483 EUID_USER();
608 if (stat("/sys/hypervisor", &s) == 0) { 484 profile_add("blacklist /sys/fs");
609 disable_file(BLACKLIST_FILE, "/sys/hypervisor"); 485 EUID_ROOT();
610 }
611
612 if (stat("/sys/fs", &s) == 0) {
613 disable_file(BLACKLIST_FILE, "/sys/fs");
614 }
615
616 if (stat("/sys/module", &s) == 0) {
617 disable_file(BLACKLIST_FILE, "/sys/module");
618 } 486 }
619 487 disable_file(BLACKLIST_FILE, "/sys/module");
620 if (stat("/sys/power", &s) == 0) { 488 disable_file(BLACKLIST_FILE, "/sys/power");
621 disable_file(BLACKLIST_FILE, "/sys/power"); 489 disable_file(BLACKLIST_FILE, "/sys/kernel/debug");
622 } 490 disable_file(BLACKLIST_FILE, "/sys/kernel/vmcoreinfo");
623 491 disable_file(BLACKLIST_FILE, "/sys/kernel/uevent_helper");
624// if (mount("sysfs", "/sys", "sysfs", MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REC, NULL) < 0) 492
625// errExit("mounting /sys"); 493 // various /proc/sys files
626 494 disable_file(BLACKLIST_FILE, "/proc/sys/security");
627 // Disable SysRq 495 disable_file(BLACKLIST_FILE, "/proc/sys/efi/vars");
628 // a linux box can be shut down easily using the following commands (as root): 496 disable_file(BLACKLIST_FILE, "/proc/sys/fs/binfmt_misc");
629 // # echo 1 > /proc/sys/kernel/sysrq 497 disable_file(BLACKLIST_FILE, "/proc/sys/kernel/core_pattern");
630 // #echo b > /proc/sysrq-trigger 498 disable_file(BLACKLIST_FILE, "/proc/sys/kernel/modprobe");
631 // for more information see https://www.kernel.org/doc/Documentation/sysrq.txt 499 disable_file(BLACKLIST_FILE, "/proc/sysrq-trigger");
632 if (arg_debug) 500 disable_file(BLACKLIST_FILE, "/proc/sys/kernel/hotplug");
633 printf("Disable /proc/sysrq-trigger\n"); 501 disable_file(BLACKLIST_FILE, "/proc/sys/vm/panic_on_oom");
634 fs_rdonly_noexit("/proc/sysrq-trigger"); 502
635 503 // various /proc files
636 // disable hotplug and uevent_helper 504 disable_file(BLACKLIST_FILE, "/proc/irq");
637 if (arg_debug) 505 disable_file(BLACKLIST_FILE, "/proc/bus");
638 printf("Disable /proc/sys/kernel/hotplug\n"); 506 disable_file(BLACKLIST_FILE, "/proc/config.gz");
639 fs_rdonly_noexit("/proc/sys/kernel/hotplug"); 507 disable_file(BLACKLIST_FILE, "/proc/sched_debug");
640 if (arg_debug) 508 disable_file(BLACKLIST_FILE, "/proc/timer_list");
641 printf("Disable /sys/kernel/uevent_helper\n"); 509 disable_file(BLACKLIST_FILE, "/proc/timer_stats");
642 fs_rdonly_noexit("/sys/kernel/uevent_helper");
643
644 // read-only /proc/irq and /proc/bus
645 if (arg_debug)
646 printf("Disable /proc/irq\n");
647 fs_rdonly_noexit("/proc/irq");
648 if (arg_debug)
649 printf("Disable /proc/bus\n");
650 fs_rdonly_noexit("/proc/bus");
651
652 // disable /proc/kcore
653 disable_file(BLACKLIST_FILE, "/proc/kcore"); 510 disable_file(BLACKLIST_FILE, "/proc/kcore");
654
655 // disable /proc/kallsyms
656 disable_file(BLACKLIST_FILE, "/proc/kallsyms"); 511 disable_file(BLACKLIST_FILE, "/proc/kallsyms");
512 disable_file(BLACKLIST_FILE, "/proc/mem");
513 disable_file(BLACKLIST_FILE, "/proc/kmem");
657 514
658 // disable /boot 515 // remove kernel symbol information
659 if (stat("/boot", &s) == 0) { 516 if (!arg_allow_debuggers) {
660 if (arg_debug) 517 disable_file(BLACKLIST_FILE, "/usr/src/linux");
661 printf("Disable /boot directory\n"); 518 disable_file(BLACKLIST_FILE, "/lib/modules");
519 disable_file(BLACKLIST_FILE, "/usr/lib/debug");
662 disable_file(BLACKLIST_FILE, "/boot"); 520 disable_file(BLACKLIST_FILE, "/boot");
663 } 521 }
664 522
665 // disable /selinux 523 // disable /selinux
666 if (stat("/selinux", &s) == 0) { 524 disable_file(BLACKLIST_FILE, "/selinux");
667 if (arg_debug)
668 printf("Disable /selinux directory\n");
669 disable_file(BLACKLIST_FILE, "/selinux");
670 }
671 525
672 // disable /dev/port 526 // disable /dev/port
673 if (stat("/dev/port", &s) == 0) { 527 disable_file(BLACKLIST_FILE, "/dev/port");
674 disable_file(BLACKLIST_FILE, "/dev/port");
675 }
676 528
677 if (getuid() != 0) { 529 if (getuid() != 0) {
678 // disable /dev/kmsg 530 // disable /dev/kmsg and /proc/kmsg
679 if (stat("/dev/kmsg", &s) == 0) { 531 disable_file(BLACKLIST_FILE, "/dev/kmsg");
680 disable_file(BLACKLIST_FILE, "/dev/kmsg"); 532 disable_file(BLACKLIST_FILE, "/proc/kmsg");
681 }
682
683 // disable /proc/kmsg
684 if (stat("/proc/kmsg", &s) == 0) {
685 disable_file(BLACKLIST_FILE, "/proc/kmsg");
686 }
687 } 533 }
688} 534}
689 535
690// disable firejail configuration in /etc/firejail and in ~/.config/firejail 536// disable firejail configuration in /etc/firejail and in ~/.config/firejail
691static void disable_firejail_config(void) { 537static void disable_config(void) {
692 struct stat s; 538 struct stat s;
693 if (stat("/etc/firejail", &s) == 0)
694 disable_file(BLACKLIST_FILE, "/etc/firejail");
695 539
696 char *fname; 540 char *fname;
697 if (asprintf(&fname, "%s/.config/firejail", cfg.homedir) == -1) 541 if (asprintf(&fname, "%s/.config/firejail", cfg.homedir) == -1)
698 errExit("asprintf"); 542 errExit("asprintf");
699 if (stat(fname, &s) == 0) 543 if (stat(fname, &s) == 0)
700 disable_file(BLACKLIST_FILE, fname); 544 disable_file(BLACKLIST_FILE, fname);
701
702 if (stat("/usr/local/etc/firejail", &s) == 0)
703 disable_file(BLACKLIST_FILE, "/usr/local/etc/firejail");
704
705 if (strcmp(PREFIX, "/usr/local")) {
706 if (asprintf(&fname, "%s/etc/firejail", PREFIX) == -1)
707 errExit("asprintf");
708 if (stat(fname, &s) == 0)
709 disable_file(BLACKLIST_FILE, fname);
710 }
711
712 free(fname); 545 free(fname);
713 546
714 // disable run time information 547 // disable run time information
@@ -725,8 +558,23 @@ static void disable_firejail_config(void) {
725 558
726// build a basic read-only filesystem 559// build a basic read-only filesystem
727void fs_basic_fs(void) { 560void fs_basic_fs(void) {
561 uid_t uid = getuid();
562
728 if (arg_debug) 563 if (arg_debug)
729 printf("Mounting read-only /bin, /sbin, /lib, /lib32, /lib64, /usr, /etc, /var\n"); 564 printf("Mounting read-only /bin, /sbin, /lib, /lib32, /lib64, /usr");
565 if (!arg_writable_etc) {
566 fs_rdonly("/etc");
567 if (uid)
568 fs_noexec("/etc");
569 if (arg_debug) printf(", /etc");
570 }
571 if (!arg_writable_var) {
572 fs_rdonly("/var");
573 if (uid)
574 fs_noexec("/var");
575 if (arg_debug) printf(", /var");
576 }
577 if (arg_debug) printf("\n");
730 fs_rdonly("/bin"); 578 fs_rdonly("/bin");
731 fs_rdonly("/sbin"); 579 fs_rdonly("/sbin");
732 fs_rdonly("/lib"); 580 fs_rdonly("/lib");
@@ -734,12 +582,10 @@ void fs_basic_fs(void) {
734 fs_rdonly("/lib32"); 582 fs_rdonly("/lib32");
735 fs_rdonly("/libx32"); 583 fs_rdonly("/libx32");
736 fs_rdonly("/usr"); 584 fs_rdonly("/usr");
737 fs_rdonly("/etc");
738 fs_rdonly("/var");
739 585
740 // update /var directory in order to support multiple sandboxes running on the same root directory 586 // update /var directory in order to support multiple sandboxes running on the same root directory
741 if (!arg_private_dev) 587// if (!arg_private_dev)
742 fs_dev_shm(); 588// fs_dev_shm();
743 fs_var_lock(); 589 fs_var_lock();
744 fs_var_tmp(); 590 fs_var_tmp();
745 fs_var_log(); 591 fs_var_log();
@@ -750,10 +596,51 @@ void fs_basic_fs(void) {
750 // don't leak user information 596 // don't leak user information
751 restrict_users(); 597 restrict_users();
752 598
753 disable_firejail_config(); 599 // when starting as root, firejail config is not disabled;
600 // this mode could be used to install and test new software by chaining
601 // firejail sandboxes (firejail --force)
602 if (uid)
603 disable_config();
754} 604}
755 605
756 606
607
608#ifdef HAVE_OVERLAYFS
609char *fs_check_overlay_dir(const char *subdirname, int allow_reuse) {
610 struct stat s;
611 char *dirname;
612
613 // create ~/.firejail directory
614 if (asprintf(&dirname, "%s/.firejail", cfg.homedir) == -1)
615 errExit("asprintf");
616 if (stat(dirname, &s) == -1) {
617 mkdir_attr(dirname, 0700, 0, 0);
618 }
619 else if (is_link(dirname)) {
620 fprintf(stderr, "Error: invalid ~/.firejail directory\n");
621 exit(1);
622 }
623 free(dirname);
624
625 // check overlay directory
626 if (asprintf(&dirname, "%s/.firejail/%s", cfg.homedir, subdirname) == -1)
627 errExit("asprintf");
628 if (is_link(dirname)) {
629 fprintf(stderr, "Error: overlay directory is a symbolic link\n");
630 exit(1);
631 }
632 if (allow_reuse == 0) {
633 if (stat(dirname, &s) == 0) {
634 fprintf(stderr, "Error: overlay directory already exists: %s\n", dirname);
635 exit(1);
636 }
637 }
638
639 return dirname;
640}
641
642
643
757// mount overlayfs on top of / directory 644// mount overlayfs on top of / directory
758// mounting an overlay and chrooting into it: 645// mounting an overlay and chrooting into it:
759// 646//
@@ -806,48 +693,53 @@ void fs_overlayfs(void) {
806 if (major == 3 && minor < 18) 693 if (major == 3 && minor < 18)
807 oldkernel = 1; 694 oldkernel = 1;
808 695
809 // build overlay directories
810 fs_build_mnt_dir();
811
812 char *oroot; 696 char *oroot;
813 if(asprintf(&oroot, "%s/oroot", RUN_MNT_DIR) == -1) 697 if(asprintf(&oroot, "%s/oroot", RUN_MNT_DIR) == -1)
814 errExit("asprintf"); 698 errExit("asprintf");
815 if (mkdir(oroot, 0755)) 699 mkdir_attr(oroot, 0755, 0, 0);
816 errExit("mkdir");
817 if (chown(oroot, 0, 0) < 0)
818 errExit("chown");
819 if (chmod(oroot, 0755) < 0)
820 errExit("chmod");
821 700
701 struct stat s;
822 char *basedir = RUN_MNT_DIR; 702 char *basedir = RUN_MNT_DIR;
823 if (arg_overlay_keep) { 703 if (arg_overlay_keep) {
824 // set base for working and diff directories 704 // set base for working and diff directories
825 basedir = cfg.overlay_dir; 705 basedir = cfg.overlay_dir;
826 if (mkdir(basedir, 0755) != 0) { 706
827 fprintf(stderr, "Error: cannot create overlay directory\n"); 707 // does the overlay exist?
828 exit(1); 708 if (stat(basedir, &s) == 0) {
709 if (arg_overlay_reuse == 0) {
710 fprintf(stderr, "Error: overlay directory exists, but reuse is not allowed\n");
711 exit(1);
712 }
713 }
714 else {
715 if (mkdir(basedir, 0755) != 0) {
716 fprintf(stderr, "Error: cannot create overlay directory\n");
717 exit(1);
718 }
829 } 719 }
830 } 720 }
831 721
832 char *odiff; 722 char *odiff;
833 if(asprintf(&odiff, "%s/odiff", basedir) == -1) 723 if(asprintf(&odiff, "%s/odiff", basedir) == -1)
834 errExit("asprintf"); 724 errExit("asprintf");
835 if (mkdir(odiff, 0755)) 725
836 errExit("mkdir"); 726 // no need to check arg_overlay_reuse
837 if (chown(odiff, 0, 0) < 0) 727 if (stat(odiff, &s) != 0) {
838 errExit("chown"); 728 mkdir_attr(odiff, 0755, 0, 0);
839 if (chmod(odiff, 0755) < 0) 729 }
840 errExit("chmod"); 730 else if (set_perms(odiff, 0, 0, 0755))
731 errExit("set_perms");
841 732
842 char *owork; 733 char *owork;
843 if(asprintf(&owork, "%s/owork", basedir) == -1) 734 if(asprintf(&owork, "%s/owork", basedir) == -1)
844 errExit("asprintf"); 735 errExit("asprintf");
845 if (mkdir(owork, 0755)) 736
846 errExit("mkdir"); 737 // no need to check arg_overlay_reuse
847 if (chown(owork, 0, 0) < 0) 738 if (stat(owork, &s) != 0) {
739 mkdir_attr(owork, 0755, 0, 0);
740 }
741 else if (set_perms(owork, 0, 0, 0755))
848 errExit("chown"); 742 errExit("chown");
849 if (chmod(owork, 0755) < 0)
850 errExit("chmod");
851 743
852 // mount overlayfs 744 // mount overlayfs
853 if (arg_debug) 745 if (arg_debug)
@@ -899,21 +791,23 @@ void fs_overlayfs(void) {
899 791
900 if(asprintf(&hdiff, "%s/hdiff", basedir) == -1) 792 if(asprintf(&hdiff, "%s/hdiff", basedir) == -1)
901 errExit("asprintf"); 793 errExit("asprintf");
902 if (mkdir(hdiff, S_IRWXU | S_IRWXG | S_IRWXO)) 794
903 errExit("mkdir"); 795 // no need to check arg_overlay_reuse
904 if (chown(hdiff, 0, 0) < 0) 796 if (stat(hdiff, &s) != 0) {
905 errExit("chown"); 797 mkdir_attr(hdiff, S_IRWXU | S_IRWXG | S_IRWXO, 0, 0);
906 if (chmod(hdiff, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) 798 }
907 errExit("chmod"); 799 else if (set_perms(hdiff, 0, 0, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH))
800 errExit("set_perms");
908 801
909 if(asprintf(&hwork, "%s/hwork", basedir) == -1) 802 if(asprintf(&hwork, "%s/hwork", basedir) == -1)
910 errExit("asprintf"); 803 errExit("asprintf");
911 if (mkdir(hwork, S_IRWXU | S_IRWXG | S_IRWXO)) 804
912 errExit("mkdir"); 805 // no need to check arg_overlay_reuse
913 if (chown(hwork, 0, 0) < 0) 806 if (stat(hwork, &s) != 0) {
914 errExit("chown"); 807 mkdir_attr(hwork, S_IRWXU | S_IRWXG | S_IRWXO, 0, 0);
915 if (chmod(hwork, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) 808 }
916 errExit("chmod"); 809 else if (set_perms(hwork, 0, 0, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH))
810 errExit("set_perms");
917 811
918 // no homedir in overlay so now mount another overlay for /home 812 // no homedir in overlay so now mount another overlay for /home
919 if (asprintf(&option, "lowerdir=/home,upperdir=%s,workdir=%s", hdiff, hwork) == -1) 813 if (asprintf(&option, "lowerdir=/home,upperdir=%s,workdir=%s", hdiff, hwork) == -1)
@@ -950,13 +844,30 @@ void fs_overlayfs(void) {
950 errExit("mounting /run"); 844 errExit("mounting /run");
951 fs_logger("whitelist /run"); 845 fs_logger("whitelist /run");
952 846
847 // mount-bind /tmp/.X11-unix directory
848 if (stat("/tmp/.X11-unix", &s) == 0) {
849 if (arg_debug)
850 printf("Mounting /tmp/.X11-unix\n");
851 char *x11;
852 if (asprintf(&x11, "%s/tmp/.X11-unix", oroot) == -1)
853 errExit("asprintf");
854 if (mount("/tmp/.X11-unix", x11, NULL, MS_BIND|MS_REC, NULL) < 0)
855 fprintf(stderr, "Warning: cannot mount /tmp/.X11-unix in overlay\n");
856 else
857 fs_logger("whitelist /tmp/.X11-unix");
858 free(x11);
859 }
860
953 // chroot in the new filesystem 861 // chroot in the new filesystem
862#ifdef HAVE_GCOV
863 __gcov_flush();
864#endif
954 if (chroot(oroot) == -1) 865 if (chroot(oroot) == -1)
955 errExit("chroot"); 866 errExit("chroot");
956 867
957 // update /var directory in order to support multiple sandboxes running on the same root directory 868 // update /var directory in order to support multiple sandboxes running on the same root directory
958 if (!arg_private_dev) 869// if (!arg_private_dev)
959 fs_dev_shm(); 870// fs_dev_shm();
960 fs_var_lock(); 871 fs_var_lock();
961 fs_var_tmp(); 872 fs_var_tmp();
962 fs_var_log(); 873 fs_var_log();
@@ -967,20 +878,18 @@ void fs_overlayfs(void) {
967 // don't leak user information 878 // don't leak user information
968 restrict_users(); 879 restrict_users();
969 880
970 // when starting as root in overlay mode, firejail config is not disabled; 881 // when starting as root, firejail config is not disabled;
971 // this mode could be used to install and test new software by chaining 882 // this mode could be used to install and test new software by chaining
972 // firejail sandboxes (firejail --force) 883 // firejail sandboxes (firejail --force)
973 if (getuid() != 0) 884 if (getuid() != 0)
974 disable_firejail_config(); 885 disable_config();
975 else
976 fprintf(stderr, "Warning: masking /etc/firejail disabled when starting the sandbox as root using --overlay option\n");
977 886
978 // cleanup and exit 887 // cleanup and exit
979 free(option); 888 free(option);
980 free(oroot); 889 free(oroot);
981 free(odiff); 890 free(odiff);
982} 891}
983 892#endif
984 893
985 894
986#ifdef HAVE_CHROOT 895#ifdef HAVE_CHROOT
@@ -991,6 +900,16 @@ int fs_check_chroot_dir(const char *rootdir) {
991 struct stat s; 900 struct stat s;
992 char *name; 901 char *name;
993 902
903 // rootdir has to be owned by root
904 if (stat(rootdir, &s) != 0) {
905 fprintf(stderr, "Error: cannot find chroot directory\n");
906 return 1;
907 }
908 if (s.st_uid != 0) {
909 fprintf(stderr, "Error: chroot directory should be owned by root\n");
910 return 1;
911 }
912
994 // check /dev 913 // check /dev
995 if (asprintf(&name, "%s/dev", rootdir) == -1) 914 if (asprintf(&name, "%s/dev", rootdir) == -1)
996 errExit("asprintf"); 915 errExit("asprintf");
@@ -1018,7 +937,7 @@ int fs_check_chroot_dir(const char *rootdir) {
1018 } 937 }
1019 free(name); 938 free(name);
1020 939
1021 // check /proc 940 // check /tmp
1022 if (asprintf(&name, "%s/tmp", rootdir) == -1) 941 if (asprintf(&name, "%s/tmp", rootdir) == -1)
1023 errExit("asprintf"); 942 errExit("asprintf");
1024 if (stat(name, &s) == -1) { 943 if (stat(name, &s) == -1) {
@@ -1026,16 +945,29 @@ int fs_check_chroot_dir(const char *rootdir) {
1026 return 1; 945 return 1;
1027 } 946 }
1028 free(name); 947 free(name);
1029 948
1030 // check /bin/bash 949 // check /bin/bash
1031 if (asprintf(&name, "%s/bin/bash", rootdir) == -1) 950// if (asprintf(&name, "%s/bin/bash", rootdir) == -1)
1032 errExit("asprintf"); 951// errExit("asprintf");
1033 if (stat(name, &s) == -1) { 952// if (stat(name, &s) == -1) {
1034 fprintf(stderr, "Error: cannot find /bin/bash in chroot directory\n"); 953// fprintf(stderr, "Error: cannot find /bin/bash in chroot directory\n");
1035 return 1; 954// return 1;
955// }
956// free(name);
957
958 // check x11 socket directory
959 if (getenv("FIREJAIL_X11")) {
960 mask_x11_abstract_socket = 1;
961 char *name;
962 if (asprintf(&name, "%s/tmp/.X11-unix", rootdir) == -1)
963 errExit("asprintf");
964 if (stat(name, &s) == -1) {
965 fprintf(stderr, "Error: cannot find /tmp/.X11-unix in chroot directory\n");
966 return 1;
967 }
968 free(name);
1036 } 969 }
1037 free(name); 970
1038
1039 return 0; 971 return 0;
1040} 972}
1041 973
@@ -1043,77 +975,108 @@ int fs_check_chroot_dir(const char *rootdir) {
1043void fs_chroot(const char *rootdir) { 975void fs_chroot(const char *rootdir) {
1044 assert(rootdir); 976 assert(rootdir);
1045 977
1046 //*********************************** 978 if (checkcfg(CFG_CHROOT_DESKTOP)) {
1047 // mount-bind a /dev in rootdir 979 // mount-bind a /dev in rootdir
1048 //*********************************** 980 char *newdev;
1049 // mount /dev 981 if (asprintf(&newdev, "%s/dev", rootdir) == -1)
1050 char *newdev; 982 errExit("asprintf");
1051 if (asprintf(&newdev, "%s/dev", rootdir) == -1) 983 if (arg_debug)
1052 errExit("asprintf"); 984 printf("Mounting /dev on %s\n", newdev);
1053 if (arg_debug) 985 if (mount("/dev", newdev, NULL, MS_BIND|MS_REC, NULL) < 0)
1054 printf("Mounting /dev on %s\n", newdev); 986 errExit("mounting /dev");
1055 if (mount("/dev", newdev, NULL, MS_BIND|MS_REC, NULL) < 0) 987 free(newdev);
1056 errExit("mounting /dev"); 988
1057 989 // x11
1058 // some older distros don't have a /run directory 990 if (getenv("FIREJAIL_X11")) {
1059 // create one by default 991 mask_x11_abstract_socket = 1;
1060 // no exit on error, let the user deal with any problems 992 char *newx11;
1061 char *rundir; 993 if (asprintf(&newx11, "%s/tmp/.X11-unix", rootdir) == -1)
1062 if (asprintf(&rundir, "%s/run", rootdir) == -1) 994 errExit("asprintf");
1063 errExit("asprintf"); 995 if (arg_debug)
1064 if (!is_dir(rundir)) { 996 printf("Mounting /tmp/.X11-unix on %s\n", newx11);
1065 int rv = mkdir(rundir, 0755); 997 if (mount("/tmp/.X11-unix", newx11, NULL, MS_BIND|MS_REC, NULL) < 0)
1066 (void) rv; 998 errExit("mounting /tmp/.X11-unix");
1067 rv = chown(rundir, 0, 0); 999 free(newx11);
1068 (void) rv; 1000 }
1001
1002 // create /run/firejail directory in chroot
1003 char *rundir;
1004 if (asprintf(&rundir, "%s/run", rootdir) == -1)
1005 errExit("asprintf");
1006 create_empty_dir_as_root(rundir, 0755);
1007 free(rundir);
1008 if (asprintf(&rundir, "%s/run/firejail", rootdir) == -1)
1009 errExit("asprintf");
1010 create_empty_dir_as_root(rundir, 0755);
1011 free(rundir);
1012
1013 // create /run/firejail/mnt directory in chroot and mount a tmpfs
1014 if (asprintf(&rundir, "%s/run/firejail/mnt", rootdir) == -1)
1015 errExit("asprintf");
1016 create_empty_dir_as_root(rundir, 0755);
1017 if (mount("tmpfs", rundir, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
1018 errExit("mounting /run/firejail/mnt");
1019 fs_logger2("tmpfs", RUN_MNT_DIR);
1020 free(rundir);
1021
1022 // retrieve seccomp.protocol
1023 struct stat s;
1024 if (stat(RUN_SECCOMP_PROTOCOL, &s) == 0) {
1025 if (asprintf(&rundir, "%s%s", rootdir, RUN_SECCOMP_PROTOCOL) == -1)
1026 errExit("asprintf");
1027 copy_file(RUN_SECCOMP_PROTOCOL, rundir, getuid(), getgid(), 0644);
1028 free(rundir);
1029 }
1030
1031 // copy /etc/resolv.conf in chroot directory
1032 // if resolv.conf in chroot is a symbolic link, this will fail
1033 // no exit on error, let the user deal with the problem
1034 char *fname;
1035 if (asprintf(&fname, "%s/etc/resolv.conf", rootdir) == -1)
1036 errExit("asprintf");
1037 if (arg_debug)
1038 printf("Updating /etc/resolv.conf in %s\n", fname);
1039 if (is_link(fname)) {
1040 fprintf(stderr, "Error: invalid %s file\n", fname);
1041 exit(1);
1042 }
1043 if (copy_file("/etc/resolv.conf", fname, 0, 0, 0644) == -1)
1044 fprintf(stderr, "Warning: /etc/resolv.conf not initialized\n");
1069 } 1045 }
1070 1046
1071 // copy /etc/resolv.conf in chroot directory
1072 // if resolv.conf in chroot is a symbolic link, this will fail
1073 // no exit on error, let the user deal with the problem
1074 char *fname;
1075 if (asprintf(&fname, "%s/etc/resolv.conf", rootdir) == -1)
1076 errExit("asprintf");
1077 if (arg_debug)
1078 printf("Updating /etc/resolv.conf in %s\n", fname);
1079 if (is_link(fname)) {
1080 fprintf(stderr, "Error: invalid %s file\n", fname);
1081 exit(1);
1082 }
1083 if (copy_file("/etc/resolv.conf", fname) == -1)
1084 fprintf(stderr, "Warning: /etc/resolv.conf not initialized\n");
1085
1086 // chroot into the new directory 1047 // chroot into the new directory
1048#ifdef HAVE_GCOV
1049 __gcov_flush();
1050#endif
1087 if (arg_debug) 1051 if (arg_debug)
1088 printf("Chrooting into %s\n", rootdir); 1052 printf("Chrooting into %s\n", rootdir);
1089 if (chroot(rootdir) < 0) 1053 if (chroot(rootdir) < 0)
1090 errExit("chroot"); 1054 errExit("chroot");
1091 // mount a new tmpfs in /run/firejail/mnt - the old one was lost in chroot
1092 fs_build_remount_mnt_dir();
1093
1094 // update /var directory in order to support multiple sandboxes running on the same root directory
1095 if (!arg_private_dev)
1096 fs_dev_shm();
1097 fs_var_lock();
1098 fs_var_tmp();
1099 fs_var_log();
1100 fs_var_lib();
1101 fs_var_cache();
1102 fs_var_utmp();
1103 1055
1104 // don't leak user information 1056 // create all other /run/firejail files and directories
1105 restrict_users(); 1057 preproc_build_firejail_dir();
1106 1058
1107 disable_firejail_config(); 1059 if (checkcfg(CFG_CHROOT_DESKTOP)) {
1060 // update /var directory in order to support multiple sandboxes running on the same root directory
1061// if (!arg_private_dev)
1062// fs_dev_shm();
1063 fs_var_lock();
1064 fs_var_tmp();
1065 fs_var_log();
1066 fs_var_lib();
1067 fs_var_cache();
1068 fs_var_utmp();
1069
1070 // don't leak user information
1071 restrict_users();
1072
1073 // when starting as root, firejail config is not disabled;
1074 // this mode could be used to install and test new software by chaining
1075 // firejail sandboxes (firejail --force)
1076 if (getuid() != 0)
1077 disable_config();
1078 }
1108} 1079}
1109#endif 1080#endif
1110 1081
1111void fs_private_tmp(void) {
1112 // mount tmpfs on top of /run/firejail/mnt
1113 if (arg_debug)
1114 printf("Mounting tmpfs on /tmp directory\n");
1115 if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=1777,gid=0") < 0)
1116 errExit("mounting /tmp/firejail/mnt");
1117 fs_logger2("tmpfs", "/tmp");
1118}
1119 1082