aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Franco (nextime) Lanza <nextime@nexlab.it>2016-08-04 00:09:40 +0200
committerLibravatar Franco (nextime) Lanza <nextime@nexlab.it>2016-08-04 00:09:40 +0200
commit15b4792c7728a807b517b94d164b0a097d82b1d9 (patch)
treed512da6a8c12c43247f0e5a0f1ed808d8cb81425
parentapparmor (diff)
downloadfirejail-15b4792c7728a807b517b94d164b0a097d82b1d9.tar.gz
firejail-15b4792c7728a807b517b94d164b0a097d82b1d9.tar.zst
firejail-15b4792c7728a807b517b94d164b0a097d82b1d9.zip
Add --private-template
-rw-r--r--src/firejail/firejail.h9
-rw-r--r--src/firejail/fs_home.c77
-rw-r--r--src/firejail/main.c14
-rw-r--r--src/firejail/profile.c13
-rw-r--r--src/firejail/sandbox.c3
5 files changed, 115 insertions, 1 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 821a8e003..02a4966bc 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -136,6 +136,7 @@ typedef struct config_t {
136 char *bin_private_keep; // keep list for private bin directory 136 char *bin_private_keep; // keep list for private bin directory
137 char *cwd; // current working directory 137 char *cwd; // current working directory
138 char *overlay_dir; 138 char *overlay_dir;
139 char *private_template; // template dir for tmpfs home
139 140
140 // networking 141 // networking
141 char *name; // sandbox name 142 char *name; // sandbox name
@@ -327,6 +328,9 @@ void fs_chroot(const char *rootdir);
327int fs_check_chroot_dir(const char *rootdir); 328int fs_check_chroot_dir(const char *rootdir);
328void fs_private_tmp(void); 329void fs_private_tmp(void);
329 330
331// copy all (normal) files and directory recursively
332int fs_copydir(const char *path, const struct stat *st, int ftype, struct FTW *sftw);
333
330// profile.c 334// profile.c
331// find and read the profile specified by name from dir directory 335// find and read the profile specified by name from dir directory
332int profile_find(const char *name, const char *dir); 336int profile_find(const char *name, const char *dir);
@@ -417,9 +421,12 @@ void fs_dev_disable_sound();
417void fs_private(void); 421void fs_private(void);
418// private mode (--private=homedir) 422// private mode (--private=homedir)
419void fs_private_homedir(void); 423void fs_private_homedir(void);
424// private template (--private-template=templatedir)
425void fs_private_template(void);
420// check new private home directory (--private= option) - exit if it fails 426// check new private home directory (--private= option) - exit if it fails
421void fs_check_private_dir(void); 427void fs_check_private_dir(void);
422 428// check new private template home directory (--private-template= option) exit if it fails
429void fs_check_private_template(void);
423 430
424// seccomp.c 431// seccomp.c
425int seccomp_filter_drop(int enforce_seccomp); 432int seccomp_filter_drop(int enforce_seccomp);
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c
index 41092de2b..76f99cead 100644
--- a/src/firejail/fs_home.c
+++ b/src/firejail/fs_home.c
@@ -28,6 +28,7 @@
28#include <sys/wait.h> 28#include <sys/wait.h>
29#include <unistd.h> 29#include <unistd.h>
30#include <grp.h> 30#include <grp.h>
31#include <ftw.h>
31 32
32static void skel(const char *homedir, uid_t u, gid_t g) { 33static void skel(const char *homedir, uid_t u, gid_t g) {
33 char *fname; 34 char *fname;
@@ -334,6 +335,43 @@ void fs_private(void) {
334 335
335} 336}
336 337
338int fs_copydir(const char *path, const struct stat *st, int ftype, struct FTW *sftw)
339{
340
341 char *homedir = cfg.homedir;
342 char *dest;
343 int srcbaselen = 0;
344 assert(homedir);
345 uid_t u = getuid();
346 gid_t g = getgid();
347 srcbaselen = strlen(cfg.private_template);
348
349 if(ftype == FTW_F || ftype == FTW_D) {
350 if (asprintf(&dest, "%s/%s", homedir, path + srcbaselen) == -1)
351 errExit("asprintf");
352 struct stat s;
353 // don't copy it if we already have the file
354 if (stat(dest, &s) == 0)
355 return 0;
356 if (stat(path, &s) == 0) {
357 if (copy_file(path, dest) == 0) {
358 if (chown(dest, u, g) == -1)
359 errExit("chown");
360 fs_logger("clone %s", path);
361 }
362 }
363 free(dest);
364 }
365 return(0);
366}
367
368void fs_private_template(void) {
369 fs_private();
370 if(!nftw(cfg.private_template, fs_copydir, 1, FTW_PHYS)) {
371 fprintf(stderr, "Error: unable to copy template dir\n");
372 exit(1);
373 }
374}
337 375
338// check new private home directory (--private= option) - exit if it fails 376// check new private home directory (--private= option) - exit if it fails
339void fs_check_private_dir(void) { 377void fs_check_private_dir(void) {
@@ -373,3 +411,42 @@ void fs_check_private_dir(void) {
373 } 411 }
374} 412}
375 413
414// check new template home directoty (--private-template= option) - exit if it fails
415void fs_check_private_template(void) {
416 EUID_ASSERT();
417 invalid_filename(cfg.private_template);
418
419 // Expand the home directory
420 char *tmp = expand_home(cfg.private_template, cfg.homedir);
421 cfg.private_template = realpath(tmp, NULL);
422 free(tmp);
423
424 if (!cfg.private_template
425 || !is_dir(cfg.private_template)
426 || is_link(cfg.private_template)
427 || strstr(cfg.private_template, "..")) {
428 fprintf(stderr, "Error: invalid private template directory\n");
429 exit(1);
430 }
431
432 // check home directory and chroot home directory have the same owner
433 struct stat s2;
434 int rv = stat(cfg.private_template, &s2);
435 if (rv < 0) {
436 fprintf(stderr, "Error: cannot find %s directory\n", cfg.private_template);
437 exit(1);
438 }
439
440 struct stat s1;
441 rv = stat(cfg.homedir, &s1);
442 if (rv < 0) {
443 fprintf(stderr, "Error: cannot find %s directory, full path name required\n", cfg.homedir);
444 exit(1);
445 }
446 if (s1.st_uid != s2.st_uid) {
447 printf("Error: --private-template directory should be owned by the current user\n");
448 exit(1);
449 }
450}
451
452
diff --git a/src/firejail/main.c b/src/firejail/main.c
index b6fd745a2..b6b97c98c 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -51,6 +51,7 @@ uid_t firejail_uid = 0;
51static char child_stack[STACK_SIZE]; // space for child's stack 51static char child_stack[STACK_SIZE]; // space for child's stack
52Config cfg; // configuration 52Config cfg; // configuration
53int arg_private = 0; // mount private /home and /tmp directoryu 53int arg_private = 0; // mount private /home and /tmp directoryu
54int arg_private_template = 0; // mount private /home using a template
54int arg_debug = 0; // print debug messages 55int arg_debug = 0; // print debug messages
55int arg_debug_check_filename; // print debug messages for filename checking 56int arg_debug_check_filename; // print debug messages for filename checking
56int arg_debug_blacklists; // print debug messages for blacklists 57int arg_debug_blacklists; // print debug messages for blacklists
@@ -1360,6 +1361,19 @@ int main(int argc, char **argv) {
1360 fs_check_private_dir(); 1361 fs_check_private_dir();
1361 arg_private = 1; 1362 arg_private = 1;
1362 } 1363 }
1364 else if (strcmp(argv[i], "--private-template=", 19) == 0) {
1365 cfg.private_template = argv[i] + 14;
1366 if (arg_private) {
1367 fprintf(stderr, "Error: --private and --private-template are mutually exclusive\n");
1368 exit(1);
1369 }
1370 if (*cfg.private_template == '\0') {
1371 fprintf(stderr, "Error: invalid private-template option\n");
1372 exit(1);
1373 }
1374 fs_check_private_template();
1375 arg_private_template = 1;
1376 }
1363 else if (strcmp(argv[i], "--private-dev") == 0) { 1377 else if (strcmp(argv[i], "--private-dev") == 0) {
1364 arg_private_dev = 1; 1378 arg_private_dev = 1;
1365 } 1379 }
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index 15cc1e55a..5aeba2f55 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -169,6 +169,10 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
169 arg_private = 1; 169 arg_private = 1;
170 return 0; 170 return 0;
171 } 171 }
172 else if (strcmp(ptr, "private-template") == 0) {
173 arg_private_template = 1;
174 return 0;
175 }
172 else if (strcmp(ptr, "private-dev") == 0) { 176 else if (strcmp(ptr, "private-dev") == 0) {
173 arg_private_dev = 1; 177 arg_private_dev = 1;
174 return 0; 178 return 0;
@@ -614,6 +618,15 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
614 return 0; 618 return 0;
615 } 619 }
616 620
621 if (strncmp(ptr, "private-template ", 17) == 0) {
622 if (arg_private) {
623 fprintf(stderr, "Error: --private and --private-template are mutually exclusive\n");
624 exit(1);
625 }
626 cfg.private_template = ptr + 17;
627 fs_check_private_template();
628 arg_private_template = 1;
629 }
617 // private /etc list of files and directories 630 // private /etc list of files and directories
618 if (strncmp(ptr, "private-etc ", 12) == 0) { 631 if (strncmp(ptr, "private-etc ", 12) == 0) {
619 if (arg_writable_etc) { 632 if (arg_writable_etc) {
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index 9bf2a0a39..d9866385e 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -524,6 +524,9 @@ int sandbox(void* sandbox_arg) {
524 fs_private(); 524 fs_private();
525 } 525 }
526 526
527 if (arg_private_template)
528 fs_private_template();
529
527 if (arg_private_dev) 530 if (arg_private_dev)
528 fs_private_dev(); 531 fs_private_dev();
529 if (arg_private_etc) { 532 if (arg_private_etc) {