aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2016-08-04 09:20:19 -0400
committerLibravatar GitHub <noreply@github.com>2016-08-04 09:20:19 -0400
commitbf84057200bb6dab84af11f777e3a45cb6e66239 (patch)
tree102e6c6a952f03d98f6132cc26f2d98f87d27b37
parentapparmor fixes for Arch Linux (diff)
parentFix dir creation owner (diff)
downloadfirejail-bf84057200bb6dab84af11f777e3a45cb6e66239.tar.gz
firejail-bf84057200bb6dab84af11f777e3a45cb6e66239.tar.zst
firejail-bf84057200bb6dab84af11f777e3a45cb6e66239.zip
Merge pull request #681 from nextime/master
add --private-template=directory option
-rw-r--r--src/firejail/firejail.h7
-rw-r--r--src/firejail/fs_home.c95
-rw-r--r--src/firejail/main.c25
-rw-r--r--src/firejail/profile.c11
-rw-r--r--src/firejail/sandbox.c3
-rw-r--r--src/firejail/usage.c3
-rw-r--r--src/man/firejail.txt12
7 files changed, 154 insertions, 2 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 821a8e003..333cd92f4 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
@@ -212,6 +213,7 @@ static inline int any_interface_configured(void) {
212void clear_run_files(pid_t pid); 213void clear_run_files(pid_t pid);
213 214
214extern int arg_private; // mount private /home 215extern int arg_private; // mount private /home
216extern int arg_private_template; // private /home template
215extern int arg_debug; // print debug messages 217extern int arg_debug; // print debug messages
216extern int arg_debug_check_filename; // print debug messages for filename checking 218extern int arg_debug_check_filename; // print debug messages for filename checking
217extern int arg_debug_blacklists; // print debug messages for blacklists 219extern int arg_debug_blacklists; // print debug messages for blacklists
@@ -417,9 +419,12 @@ void fs_dev_disable_sound();
417void fs_private(void); 419void fs_private(void);
418// private mode (--private=homedir) 420// private mode (--private=homedir)
419void fs_private_homedir(void); 421void fs_private_homedir(void);
422// private template (--private-template=templatedir)
423void fs_private_template(void);
420// check new private home directory (--private= option) - exit if it fails 424// check new private home directory (--private= option) - exit if it fails
421void fs_check_private_dir(void); 425void fs_check_private_dir(void);
422 426// check new private template home directory (--private-template= option) exit if it fails
427void fs_check_private_template(void);
423 428
424// seccomp.c 429// seccomp.c
425int seccomp_filter_drop(int enforce_seccomp); 430int seccomp_filter_drop(int enforce_seccomp);
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c
index 41092de2b..105092036 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,61 @@ 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
341int fs_copydir(const char *path, const struct stat *st, int ftype, struct FTW *sftw)
342{
343
344 char *homedir = cfg.homedir;
345 char *dest;
346 int srcbaselen = 0;
347 assert(homedir);
348 uid_t u = getuid();
349 gid_t g = getgid();
350 srcbaselen = strlen(cfg.private_template);
351
352 if(ftype == FTW_F || ftype == FTW_D) {
353 if (asprintf(&dest, "%s/%s", homedir, path + srcbaselen) == -1)
354 errExit("asprintf");
355 struct stat s;
356 // don't copy it if we already have the file
357 if (stat(dest, &s) == 0)
358 return(0);
359 if (stat(path, &s) == 0) {
360 if(ftype == FTW_F) {
361 if (copy_file(path, dest) == 0) {
362 if (arg_debug)
363 printf("copy from %s to %s\n", path, dest);
364 if (chown(dest, u, g) == -1)
365 errExit("chown");
366 fs_logger2("clone", path);
367 }
368 }
369 else if(ftype == FTW_D) {
370 if (mkdir(dest, s.st_mode) == -1)
371 errExit("mkdir");
372 if (chown(dest, u, g) < 0)
373 errExit("chown");
374 if (arg_debug)
375 printf("copy from %s to %s\n", path, dest);
376 fs_logger2("clone", path);
377 }
378 }
379 free(dest);
380 }
381 return(0);
382}
383
384void fs_private_template(void) {
385
386 fs_private();
387 if(nftw(cfg.private_template, fs_copydir, 1, FTW_PHYS) != 0) {
388 fprintf(stderr, "Error: unable to copy template dir\n");
389 exit(1);
390 }
391
392}
337 393
338// check new private home directory (--private= option) - exit if it fails 394// check new private home directory (--private= option) - exit if it fails
339void fs_check_private_dir(void) { 395void fs_check_private_dir(void) {
@@ -373,3 +429,42 @@ void fs_check_private_dir(void) {
373 } 429 }
374} 430}
375 431
432// check new template home directoty (--private-template= option) - exit if it fails
433void fs_check_private_template(void) {
434 EUID_ASSERT();
435 invalid_filename(cfg.private_template);
436
437 // Expand the home directory
438 char *tmp = expand_home(cfg.private_template, cfg.homedir);
439 cfg.private_template = realpath(tmp, NULL);
440 free(tmp);
441
442 if (!cfg.private_template
443 || !is_dir(cfg.private_template)
444 || is_link(cfg.private_template)
445 || strstr(cfg.private_template, "..")) {
446 fprintf(stderr, "Error: invalid private template directory\n");
447 exit(1);
448 }
449
450 // check home directory and chroot home directory have the same owner
451 struct stat s2;
452 int rv = stat(cfg.private_template, &s2);
453 if (rv < 0) {
454 fprintf(stderr, "Error: cannot find %s directory\n", cfg.private_template);
455 exit(1);
456 }
457
458 struct stat s1;
459 rv = stat(cfg.homedir, &s1);
460 if (rv < 0) {
461 fprintf(stderr, "Error: cannot find %s directory, full path name required\n", cfg.homedir);
462 exit(1);
463 }
464 if (s1.st_uid != s2.st_uid) {
465 printf("Error: --private-template directory should be owned by the current user\n");
466 exit(1);
467 }
468}
469
470
diff --git a/src/firejail/main.c b/src/firejail/main.c
index b6fd745a2..9f6fa5142 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
@@ -1348,9 +1349,18 @@ int main(int argc, char **argv) {
1348 else if (strcmp(argv[i], "--writable-var") == 0) { 1349 else if (strcmp(argv[i], "--writable-var") == 0) {
1349 arg_writable_var = 1; 1350 arg_writable_var = 1;
1350 } 1351 }
1351 else if (strcmp(argv[i], "--private") == 0) 1352 else if (strcmp(argv[i], "--private") == 0) {
1353 if (arg_private_template) {
1354 fprintf(stderr, "Error: --private and --private-template are mutually exclusive\n");
1355 exit(1);
1356 }
1352 arg_private = 1; 1357 arg_private = 1;
1358 }
1353 else if (strncmp(argv[i], "--private=", 10) == 0) { 1359 else if (strncmp(argv[i], "--private=", 10) == 0) {
1360 if (arg_private_template) {
1361 fprintf(stderr, "Error: --private and --private-template are mutually exclusive\n");
1362 exit(1);
1363 }
1354 // extract private home dirname 1364 // extract private home dirname
1355 cfg.home_private = argv[i] + 10; 1365 cfg.home_private = argv[i] + 10;
1356 if (*cfg.home_private == '\0') { 1366 if (*cfg.home_private == '\0') {
@@ -1360,6 +1370,19 @@ int main(int argc, char **argv) {
1360 fs_check_private_dir(); 1370 fs_check_private_dir();
1361 arg_private = 1; 1371 arg_private = 1;
1362 } 1372 }
1373 else if (strncmp(argv[i], "--private-template=", 19) == 0) {
1374 cfg.private_template = argv[i] + 19;
1375 if (arg_private) {
1376 fprintf(stderr, "Error: --private and --private-template are mutually exclusive\n");
1377 exit(1);
1378 }
1379 if (*cfg.private_template == '\0') {
1380 fprintf(stderr, "Error: invalid private-template option\n");
1381 exit(1);
1382 }
1383 fs_check_private_template();
1384 arg_private_template = 1;
1385 }
1363 else if (strcmp(argv[i], "--private-dev") == 0) { 1386 else if (strcmp(argv[i], "--private-dev") == 0) {
1364 arg_private_dev = 1; 1387 arg_private_dev = 1;
1365 } 1388 }
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index 15cc1e55a..1403db704 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -614,6 +614,17 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
614 return 0; 614 return 0;
615 } 615 }
616 616
617 if (strncmp(ptr, "private-template ", 17) == 0) {
618 if (arg_private) {
619 fprintf(stderr, "Error: --private and --private-template are mutually exclusive\n");
620 exit(1);
621 }
622 cfg.private_template = ptr + 17;
623 fs_check_private_template();
624 arg_private_template = 1;
625
626 return 0;
627 }
617 // private /etc list of files and directories 628 // private /etc list of files and directories
618 if (strncmp(ptr, "private-etc ", 12) == 0) { 629 if (strncmp(ptr, "private-etc ", 12) == 0) {
619 if (arg_writable_etc) { 630 if (arg_writable_etc) {
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index dc107f00a..f37605e20 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) {
diff --git a/src/firejail/usage.c b/src/firejail/usage.c
index 958a16da7..baba93791 100644
--- a/src/firejail/usage.c
+++ b/src/firejail/usage.c
@@ -189,6 +189,9 @@ void usage(void) {
189 printf("\tclosed.\n\n"); 189 printf("\tclosed.\n\n");
190 printf(" --private=directory - use directory as user home.\n\n"); 190 printf(" --private=directory - use directory as user home.\n\n");
191 191
192 printf(" --private-template=directory - same as --private but copy the\n");
193 printf("\ttemplatedirectory in the tmpfs mounted user home.\n\n");
194
192 printf(" --private-bin=file,file - build a new /bin in a temporary filesystem,\n"); 195 printf(" --private-bin=file,file - build a new /bin in a temporary filesystem,\n");
193 printf("\tand copy the programs in the list.\n\n"); 196 printf("\tand copy the programs in the list.\n\n");
194 197
diff --git a/src/man/firejail.txt b/src/man/firejail.txt
index 9e6916534..c6b73f428 100644
--- a/src/man/firejail.txt
+++ b/src/man/firejail.txt
@@ -1045,6 +1045,18 @@ Example:
1045$ firejail \-\-private=/home/netblue/firefox-home firefox 1045$ firejail \-\-private=/home/netblue/firefox-home firefox
1046 1046
1047.TP 1047.TP
1048\fB\-\-private-template=templatedir
1049Mount new /root and /home/user directories in temporary
1050filesystems, and copy all files in templatedir. All modifications are discarded when the sandbox is
1051closed.
1052.br
1053
1054.br
1055Example:
1056.br
1057$ firejail \-\-private-template=/home/netblue/.config/mozilla firefox
1058
1059.TP
1048\fB\-\-private-bin=file,file 1060\fB\-\-private-bin=file,file
1049Build a new /bin in a temporary filesystem, and copy the programs in the list. 1061Build a new /bin in a temporary filesystem, and copy the programs in the list.
1050If no listed file is found, /bin directory will be empty. 1062If no listed file is found, /bin directory will be empty.