From 15b4792c7728a807b517b94d164b0a097d82b1d9 Mon Sep 17 00:00:00 2001 From: "Franco (nextime) Lanza" Date: Thu, 4 Aug 2016 00:09:40 +0200 Subject: Add --private-template --- src/firejail/firejail.h | 9 +++++- src/firejail/fs_home.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ src/firejail/main.c | 14 +++++++++ src/firejail/profile.c | 13 +++++++++ src/firejail/sandbox.c | 3 ++ 5 files changed, 115 insertions(+), 1 deletion(-) 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 { char *bin_private_keep; // keep list for private bin directory char *cwd; // current working directory char *overlay_dir; + char *private_template; // template dir for tmpfs home // networking char *name; // sandbox name @@ -327,6 +328,9 @@ void fs_chroot(const char *rootdir); int fs_check_chroot_dir(const char *rootdir); void fs_private_tmp(void); +// copy all (normal) files and directory recursively +int fs_copydir(const char *path, const struct stat *st, int ftype, struct FTW *sftw); + // profile.c // find and read the profile specified by name from dir directory int profile_find(const char *name, const char *dir); @@ -417,9 +421,12 @@ void fs_dev_disable_sound(); void fs_private(void); // private mode (--private=homedir) void fs_private_homedir(void); +// private template (--private-template=templatedir) +void fs_private_template(void); // check new private home directory (--private= option) - exit if it fails void fs_check_private_dir(void); - +// check new private template home directory (--private-template= option) exit if it fails +void fs_check_private_template(void); // seccomp.c int 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 @@ #include #include #include +#include static void skel(const char *homedir, uid_t u, gid_t g) { char *fname; @@ -334,6 +335,43 @@ void fs_private(void) { } +int fs_copydir(const char *path, const struct stat *st, int ftype, struct FTW *sftw) +{ + + char *homedir = cfg.homedir; + char *dest; + int srcbaselen = 0; + assert(homedir); + uid_t u = getuid(); + gid_t g = getgid(); + srcbaselen = strlen(cfg.private_template); + + if(ftype == FTW_F || ftype == FTW_D) { + if (asprintf(&dest, "%s/%s", homedir, path + srcbaselen) == -1) + errExit("asprintf"); + struct stat s; + // don't copy it if we already have the file + if (stat(dest, &s) == 0) + return 0; + if (stat(path, &s) == 0) { + if (copy_file(path, dest) == 0) { + if (chown(dest, u, g) == -1) + errExit("chown"); + fs_logger("clone %s", path); + } + } + free(dest); + } + return(0); +} + +void fs_private_template(void) { + fs_private(); + if(!nftw(cfg.private_template, fs_copydir, 1, FTW_PHYS)) { + fprintf(stderr, "Error: unable to copy template dir\n"); + exit(1); + } +} // check new private home directory (--private= option) - exit if it fails void fs_check_private_dir(void) { @@ -373,3 +411,42 @@ void fs_check_private_dir(void) { } } +// check new template home directoty (--private-template= option) - exit if it fails +void fs_check_private_template(void) { + EUID_ASSERT(); + invalid_filename(cfg.private_template); + + // Expand the home directory + char *tmp = expand_home(cfg.private_template, cfg.homedir); + cfg.private_template = realpath(tmp, NULL); + free(tmp); + + if (!cfg.private_template + || !is_dir(cfg.private_template) + || is_link(cfg.private_template) + || strstr(cfg.private_template, "..")) { + fprintf(stderr, "Error: invalid private template directory\n"); + exit(1); + } + + // check home directory and chroot home directory have the same owner + struct stat s2; + int rv = stat(cfg.private_template, &s2); + if (rv < 0) { + fprintf(stderr, "Error: cannot find %s directory\n", cfg.private_template); + exit(1); + } + + struct stat s1; + rv = stat(cfg.homedir, &s1); + if (rv < 0) { + fprintf(stderr, "Error: cannot find %s directory, full path name required\n", cfg.homedir); + exit(1); + } + if (s1.st_uid != s2.st_uid) { + printf("Error: --private-template directory should be owned by the current user\n"); + exit(1); + } +} + + 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; static char child_stack[STACK_SIZE]; // space for child's stack Config cfg; // configuration int arg_private = 0; // mount private /home and /tmp directoryu +int arg_private_template = 0; // mount private /home using a template int arg_debug = 0; // print debug messages int arg_debug_check_filename; // print debug messages for filename checking int arg_debug_blacklists; // print debug messages for blacklists @@ -1360,6 +1361,19 @@ int main(int argc, char **argv) { fs_check_private_dir(); arg_private = 1; } + else if (strcmp(argv[i], "--private-template=", 19) == 0) { + cfg.private_template = argv[i] + 14; + if (arg_private) { + fprintf(stderr, "Error: --private and --private-template are mutually exclusive\n"); + exit(1); + } + if (*cfg.private_template == '\0') { + fprintf(stderr, "Error: invalid private-template option\n"); + exit(1); + } + fs_check_private_template(); + arg_private_template = 1; + } else if (strcmp(argv[i], "--private-dev") == 0) { arg_private_dev = 1; } 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) { arg_private = 1; return 0; } + else if (strcmp(ptr, "private-template") == 0) { + arg_private_template = 1; + return 0; + } else if (strcmp(ptr, "private-dev") == 0) { arg_private_dev = 1; return 0; @@ -614,6 +618,15 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { return 0; } + if (strncmp(ptr, "private-template ", 17) == 0) { + if (arg_private) { + fprintf(stderr, "Error: --private and --private-template are mutually exclusive\n"); + exit(1); + } + cfg.private_template = ptr + 17; + fs_check_private_template(); + arg_private_template = 1; + } // private /etc list of files and directories if (strncmp(ptr, "private-etc ", 12) == 0) { 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) { fs_private(); } + if (arg_private_template) + fs_private_template(); + if (arg_private_dev) fs_private_dev(); if (arg_private_etc) { -- cgit v1.2.3-54-g00ecf From bc8314c8c6e8f8e757c8c5ddb49ec5e41368444f Mon Sep 17 00:00:00 2001 From: nextime Date: Thu, 4 Aug 2016 00:51:45 +0200 Subject: Fix minor bugs --- src/firejail/firejail.h | 4 +--- src/firejail/fs_home.c | 5 ++++- src/firejail/main.c | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 02a4966bc..333cd92f4 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -213,6 +213,7 @@ static inline int any_interface_configured(void) { void clear_run_files(pid_t pid); extern int arg_private; // mount private /home +extern int arg_private_template; // private /home template extern int arg_debug; // print debug messages extern int arg_debug_check_filename; // print debug messages for filename checking extern int arg_debug_blacklists; // print debug messages for blacklists @@ -328,9 +329,6 @@ void fs_chroot(const char *rootdir); int fs_check_chroot_dir(const char *rootdir); void fs_private_tmp(void); -// copy all (normal) files and directory recursively -int fs_copydir(const char *path, const struct stat *st, int ftype, struct FTW *sftw); - // profile.c // find and read the profile specified by name from dir directory int profile_find(const char *name, const char *dir); diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c index 76f99cead..3cb410569 100644 --- a/src/firejail/fs_home.c +++ b/src/firejail/fs_home.c @@ -335,6 +335,9 @@ void fs_private(void) { } +int fs_copydir(const char *path, const struct stat *st, int ftype, struct FTW *sftw); + + int fs_copydir(const char *path, const struct stat *st, int ftype, struct FTW *sftw) { @@ -357,7 +360,7 @@ int fs_copydir(const char *path, const struct stat *st, int ftype, struct FTW *s if (copy_file(path, dest) == 0) { if (chown(dest, u, g) == -1) errExit("chown"); - fs_logger("clone %s", path); + fs_logger2("clone", path); } } free(dest); diff --git a/src/firejail/main.c b/src/firejail/main.c index b6b97c98c..a6c96f956 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c @@ -1361,7 +1361,7 @@ int main(int argc, char **argv) { fs_check_private_dir(); arg_private = 1; } - else if (strcmp(argv[i], "--private-template=", 19) == 0) { + else if (strncmp(argv[i], "--private-template=", 19) == 0) { cfg.private_template = argv[i] + 14; if (arg_private) { fprintf(stderr, "Error: --private and --private-template are mutually exclusive\n"); -- cgit v1.2.3-54-g00ecf From 8f512407ddb2abc3e2b7ae71f848916e7e3fc64d Mon Sep 17 00:00:00 2001 From: nextime Date: Thu, 4 Aug 2016 02:15:43 +0200 Subject: Make copydir work as expected --- src/firejail/fs_home.c | 23 ++++++++++++++++++----- src/firejail/main.c | 13 +++++++++++-- src/firejail/usage.c | 3 +++ src/man/firejail.txt | 12 ++++++++++++ 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c index 3cb410569..604bba0e4 100644 --- a/src/firejail/fs_home.c +++ b/src/firejail/fs_home.c @@ -355,11 +355,22 @@ int fs_copydir(const char *path, const struct stat *st, int ftype, struct FTW *s struct stat s; // don't copy it if we already have the file if (stat(dest, &s) == 0) - return 0; + return(0); if (stat(path, &s) == 0) { - if (copy_file(path, dest) == 0) { - if (chown(dest, u, g) == -1) - errExit("chown"); + if(ftype == FTW_F) { + if (copy_file(path, dest) == 0) { + if (arg_debug) + printf("copy from %s to %s\n", path, dest); + if (chown(dest, u, g) == -1) + errExit("chown"); + fs_logger2("clone", path); + } + } + else if(ftype == FTW_D) { + if (mkdir(dest, s.st_mode) == -1) + errExit("mkdir"); + if (arg_debug) + printf("copy from %s to %s\n", path, dest); fs_logger2("clone", path); } } @@ -369,11 +380,13 @@ int fs_copydir(const char *path, const struct stat *st, int ftype, struct FTW *s } void fs_private_template(void) { + fs_private(); - if(!nftw(cfg.private_template, fs_copydir, 1, FTW_PHYS)) { + if(nftw(cfg.private_template, fs_copydir, 1, FTW_PHYS) != 0) { fprintf(stderr, "Error: unable to copy template dir\n"); exit(1); } + } // check new private home directory (--private= option) - exit if it fails diff --git a/src/firejail/main.c b/src/firejail/main.c index a6c96f956..9f6fa5142 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c @@ -1349,9 +1349,18 @@ int main(int argc, char **argv) { else if (strcmp(argv[i], "--writable-var") == 0) { arg_writable_var = 1; } - else if (strcmp(argv[i], "--private") == 0) + else if (strcmp(argv[i], "--private") == 0) { + if (arg_private_template) { + fprintf(stderr, "Error: --private and --private-template are mutually exclusive\n"); + exit(1); + } arg_private = 1; + } else if (strncmp(argv[i], "--private=", 10) == 0) { + if (arg_private_template) { + fprintf(stderr, "Error: --private and --private-template are mutually exclusive\n"); + exit(1); + } // extract private home dirname cfg.home_private = argv[i] + 10; if (*cfg.home_private == '\0') { @@ -1362,7 +1371,7 @@ int main(int argc, char **argv) { arg_private = 1; } else if (strncmp(argv[i], "--private-template=", 19) == 0) { - cfg.private_template = argv[i] + 14; + cfg.private_template = argv[i] + 19; if (arg_private) { fprintf(stderr, "Error: --private and --private-template are mutually exclusive\n"); exit(1); 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) { printf("\tclosed.\n\n"); printf(" --private=directory - use directory as user home.\n\n"); + printf(" --private-template=directory - same as --private but copy the\n"); + printf("\ttemplatedirectory in the tmpfs mounted user home.\n\n"); + printf(" --private-bin=file,file - build a new /bin in a temporary filesystem,\n"); printf("\tand copy the programs in the list.\n\n"); 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 @@ -1044,6 +1044,18 @@ Example: .br $ firejail \-\-private=/home/netblue/firefox-home firefox +.TP +\fB\-\-private-template=templatedir +Mount new /root and /home/user directories in temporary +filesystems, and copy all files in templatedir. All modifications are discarded when the sandbox is +closed. +.br + +.br +Example: +.br +$ firejail \-\-private-template=/home/netblue/.config/mozilla firefox + .TP \fB\-\-private-bin=file,file Build a new /bin in a temporary filesystem, and copy the programs in the list. -- cgit v1.2.3-54-g00ecf From 841c794e12e694695cbf537d1b10f63a5c622556 Mon Sep 17 00:00:00 2001 From: nextime Date: Thu, 4 Aug 2016 09:06:26 +0200 Subject: Fix profile for --private-template --- src/firejail/profile.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 5aeba2f55..1403db704 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c @@ -169,10 +169,6 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { arg_private = 1; return 0; } - else if (strcmp(ptr, "private-template") == 0) { - arg_private_template = 1; - return 0; - } else if (strcmp(ptr, "private-dev") == 0) { arg_private_dev = 1; return 0; @@ -626,6 +622,8 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { cfg.private_template = ptr + 17; fs_check_private_template(); arg_private_template = 1; + + return 0; } // private /etc list of files and directories if (strncmp(ptr, "private-etc ", 12) == 0) { -- cgit v1.2.3-54-g00ecf From 713807e8f93e95763308bd1cc6aa5fd1b75ed13d Mon Sep 17 00:00:00 2001 From: nextime Date: Thu, 4 Aug 2016 09:23:26 +0200 Subject: Fix dir creation owner --- src/firejail/fs_home.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c index 604bba0e4..105092036 100644 --- a/src/firejail/fs_home.c +++ b/src/firejail/fs_home.c @@ -369,6 +369,8 @@ int fs_copydir(const char *path, const struct stat *st, int ftype, struct FTW *s else if(ftype == FTW_D) { if (mkdir(dest, s.st_mode) == -1) errExit("mkdir"); + if (chown(dest, u, g) < 0) + errExit("chown"); if (arg_debug) printf("copy from %s to %s\n", path, dest); fs_logger2("clone", path); -- cgit v1.2.3-54-g00ecf