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-70-g09d2