From 6aad9ad431f749003b4eab7b91cfdd0f218852a2 Mon Sep 17 00:00:00 2001 From: netblue30 Date: Sun, 4 Sep 2016 13:52:16 -0400 Subject: bringing back --private-home --- README | 2 +- README.md | 2 + RELNOTES | 1 + configure | 17 ++ configure.ac | 9 + etc/firejail.config | 3 + src/firejail/Makefile.in | 3 +- src/firejail/checkcfg.c | 32 +++- src/firejail/firejail.h | 4 +- src/firejail/fs_home.c | 408 +++++++++++++++++++++++++++++++++---------- src/firejail/main.c | 51 +++--- src/firejail/profile.c | 12 ++ src/firejail/sandbox.c | 8 + src/firejail/usage.c | 22 +-- src/man/firejail-profile.txt | 6 + src/man/firejail.txt | 13 ++ 16 files changed, 446 insertions(+), 147 deletions(-) diff --git a/README b/README index 8923abaf4..7ba78a05f 100644 --- a/README +++ b/README @@ -87,7 +87,7 @@ greigdp (https://github.com/greigdp) Laurent Declercq (https://github.com/nuxwin) - fixed test for shell interpreter in chroots Franco (nextime) Lanza (https://github.com/nextime) - - added --private-template + - added --private-template/--private-home xee5ch (https://github.com/xee5ch) - skypeforlinux profile Peter Hogg (https://github.com/pigmonkey) diff --git a/README.md b/README.md index ebd39de5b..2f2ab38e7 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,8 @@ FAQ: https://firejail.wordpress.com/support/frequently-asked-questions/ Version 0.9.41~rc1 was released. +## Bringing back --private-home + ## Deprecated --user --user option was deprecated, please use "sudo -u username firejail application" instead. diff --git a/RELNOTES b/RELNOTES index d07bfa896..734a92b4f 100644 --- a/RELNOTES +++ b/RELNOTES @@ -4,6 +4,7 @@ firejail (0.9.42~rc2) baseline; urgency=low * security: tighten --chroot, submitted by Jann Horn * security: terminal sandbox escape, submitted by Stephan Sokolow * security: several TOCTOU fixes submitted by Aleksey Manevich + * modifs: bringing back --private-home option * modifs: deprecated --user option, please use "sudo -u username firejail" * modifs: allow symlinks in home directory for --whitelist option * modifs: Firejail prompt is enabled by env variable FIREJAIL_PROMPT="yes" diff --git a/configure b/configure index 3f9d0fc42..0b05d42e5 100755 --- a/configure +++ b/configure @@ -636,6 +636,7 @@ HAVE_GLOBALCFG HAVE_BIND HAVE_CHROOT HAVE_SECCOMP +HAVE_PRIVATE_HOME HAVE_OVERLAYFS EXTRA_LDFLAGS EGREP @@ -696,6 +697,7 @@ ac_user_opts=' enable_option_checking enable_apparmor enable_overlayfs +enable_private_home enable_seccomp enable_chroot enable_bind @@ -1328,6 +1330,7 @@ Optional Features: --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-apparmor enable apparmor --disable-overlayfs disable overlayfs + --disable-private-home disable private home feature --disable-seccomp disable seccomp --disable-chroot disable chroot --disable-bind disable bind @@ -3525,6 +3528,19 @@ if test "x$enable_overlayfs" != "xno"; then : HAVE_OVERLAYFS="-DHAVE_OVERLAYFS" +fi + +HAVE_PRIVATEHOME="" +# Check whether --enable-private-home was given. +if test "${enable_private_home+set}" = set; then : + enableval=$enable_private_home; +fi + +if test "x$enable_private_home" != "xno"; then : + + HAVE_PRIVATE_HOME="-DHAVE_PRIVATE_HOME" + + fi HAVE_SECCOMP="" @@ -4937,6 +4953,7 @@ echo " network: $HAVE_NETWORK" echo " user namespace: $HAVE_USERNS" echo " X11 sandboxing support: $HAVE_X11" echo " whitelisting: $HAVE_WHITELIST" +echo " private home support: $HAVE_PRIVATE_HOME" echo " file transfer support: $HAVE_FILE_TRANSFER" echo " overlayfs support: $HAVE_OVERLAYFS" echo " fatal warnings: $HAVE_FATAL_WARNINGS" diff --git a/configure.ac b/configure.ac index 67b74e723..ca6066d25 100644 --- a/configure.ac +++ b/configure.ac @@ -38,6 +38,14 @@ AS_IF([test "x$enable_overlayfs" != "xno"], [ AC_SUBST(HAVE_OVERLAYFS) ]) +HAVE_PRIVATEHOME="" +AC_ARG_ENABLE([private-home], + AS_HELP_STRING([--disable-private-home], [disable private home feature])) +AS_IF([test "x$enable_private_home" != "xno"], [ + HAVE_PRIVATE_HOME="-DHAVE_PRIVATE_HOME" + AC_SUBST(HAVE_PRIVATE_HOME) +]) + HAVE_SECCOMP="" AC_ARG_ENABLE([seccomp], AS_HELP_STRING([--disable-seccomp], [disable seccomp])) @@ -163,6 +171,7 @@ echo " network: $HAVE_NETWORK" echo " user namespace: $HAVE_USERNS" echo " X11 sandboxing support: $HAVE_X11" echo " whitelisting: $HAVE_WHITELIST" +echo " private home support: $HAVE_PRIVATE_HOME" echo " file transfer support: $HAVE_FILE_TRANSFER" echo " overlayfs support: $HAVE_OVERLAYFS" echo " fatal warnings: $HAVE_FATAL_WARNINGS" diff --git a/etc/firejail.config b/etc/firejail.config index 6b6ba7fdf..08ff5380d 100644 --- a/etc/firejail.config +++ b/etc/firejail.config @@ -29,6 +29,9 @@ # Enable or disable overlayfs features, default enabled. # overlayfs yes +# Enable or disable private-home feature, default enabled +# private-home yes + # Enable --quiet as default every time the sandbox is started. Default disabled. # quiet-by-default no diff --git a/src/firejail/Makefile.in b/src/firejail/Makefile.in index f56137308..fce460906 100644 --- a/src/firejail/Makefile.in +++ b/src/firejail/Makefile.in @@ -20,13 +20,14 @@ HAVE_WHITELIST=@HAVE_WHITELIST@ HAVE_GLOBALCFG=@HAVE_GLOBALCFG@ HAVE_APPARMOR=@HAVE_APPARMOR@ HAVE_OVERLAYFS=@HAVE_OVERLAYFS@ +HAVE_PRIVATE_HOME=@HAVE_PRIVATE_HOME@ EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@ H_FILE_LIST = $(sort $(wildcard *.[h])) C_FILE_LIST = $(sort $(wildcard *.c)) OBJS = $(C_FILE_LIST:.c=.o) BINOBJS = $(foreach file, $(OBJS), $file) -CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' $(HAVE_X11) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_SECCOMP) $(HAVE_GLOBALCFG) $(HAVE_SECCOMP_H) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_BIND) $(HAVE_FILE_TRANSFER) $(HAVE_WHITELIST) -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security +CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_SECCOMP) $(HAVE_GLOBALCFG) $(HAVE_SECCOMP_H) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_BIND) $(HAVE_FILE_TRANSFER) $(HAVE_WHITELIST) -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/euid_common.h ../include/libnetlink.h ../include/pid.h diff --git a/src/firejail/checkcfg.c b/src/firejail/checkcfg.c index 5bc859f8d..99266c575 100644 --- a/src/firejail/checkcfg.c +++ b/src/firejail/checkcfg.c @@ -241,6 +241,14 @@ int checkcfg(int val) { else goto errout; } + else if (strncmp(ptr, "private-home ", 13) == 0) { + if (strcmp(ptr + 13, "yes") == 0) + cfg_val[CFG_PRIVATE_HOME] = 1; + else if (strcmp(ptr + 13, "no") == 0) + cfg_val[CFG_PRIVATE_HOME] = 0; + else + goto errout; + } else if (strncmp(ptr, "chroot-desktop ", 15) == 0) { if (strcmp(ptr + 15, "yes") == 0) cfg_val[CFG_CHROOT_DESKTOP] = 1; @@ -295,14 +303,6 @@ void print_compiletime_support(void) { #endif ); - printf("\t- overlayfs support is %s\n", -#ifdef HAVE_OVERLAYFS - "enabled" -#else - "disabled" -#endif - ); - printf("\t- file and directory whitelisting support is %s\n", #ifdef HAVE_WHITELIST "enabled" @@ -332,6 +332,22 @@ void print_compiletime_support(void) { printf("\t- networking features are available only to root user\n"); #endif + printf("\t- overlayfs support is %s\n", +#ifdef HAVE_OVERLAYFS + "enabled" +#else + "disabled" +#endif + ); + + printf("\t- private-home support is %s\n", +#ifdef HAVE_PRIVATE_HOME + "enabled" +#else + "disabled" +#endif + ); + printf("\t- seccomp-bpf support is %s\n", #ifdef HAVE_SECCOMP "enabled" diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 7be04f782..9b60d40c2 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -180,6 +180,7 @@ typedef struct config_t { char *profile_ignore[MAX_PROFILE_IGNORE]; char *chrootdir; // chroot directory char *home_private; // private home directory + char *home_private_keep; // keep list for private home directory char *etc_private_keep; // keep list for private etc directory char *bin_private_keep; // keep list for private bin directory char *cwd; // current working directory @@ -640,7 +641,8 @@ void sandboxfs(int op, pid_t pid, const char *patqh); #define CFG_REMOUNT_PROC_SYS 11 #define CFG_OVERLAYFS 12 #define CFG_CHROOT_DESKTOP 13 -#define CFG_MAX 14 // this should always be the last entry +#define CFG_PRIVATE_HOME 14 +#define CFG_MAX 15 // this should always be the last entry extern char *xephyr_screen; extern char *xephyr_extra_params; extern char *netfilter_default; diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c index 85fa244be..a4b2ec046 100644 --- a/src/firejail/fs_home.c +++ b/src/firejail/fs_home.c @@ -313,61 +313,6 @@ 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) -{ -(void) st; -(void) 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(ftype == FTW_F) { - if (copy_file(path, dest, u, g, 0644) == 0) { - if (arg_debug) - printf("copy from %s to %s\n", path, dest); - fs_logger2("clone", path); - } - } - 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); - } - } - free(dest); - } - return(0); -} - -void fs_private_template(void) { - - fs_private(); - 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 void fs_check_private_dir(void) { EUID_ASSERT(); @@ -406,42 +351,323 @@ 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); - } +//*********************************************************************************** +// --private-home +//*********************************************************************************** +#define PRIVATE_COPY_LIMIT (500 * 1024 *1024) +static int size_limit_reached = 0; +static unsigned file_cnt = 0; +static unsigned size_cnt = 0; +static char *check_dir_or_file(const char *name); + +int fs_copydir(const char *path, const struct stat *st, int ftype, struct FTW *sftw) { + if (size_limit_reached) + return 0; + + struct stat s; + char *dest; + if (asprintf(&dest, "%s%s", RUN_HOME_DIR, path + strlen(cfg.homedir)) == -1) + errExit("asprintf"); + + // don't copy it if we already have the file + if (stat(dest, &s) == 0) { + free(dest); + return 0; + } + + // extract mode and ownership + if (stat(path, &s) != 0) { + free(dest); + return 0; + } + + // check uid + if (s.st_uid != firejail_uid || s.st_gid != firejail_gid) { + free(dest); + return 0; + } + + if ((s.st_size + size_cnt) > PRIVATE_COPY_LIMIT) { + size_limit_reached = 1; + free(dest); + return 0; + } + + file_cnt++; + size_cnt += s.st_size; + + if(ftype == FTW_F) + copy_file(path, dest, firejail_uid, firejail_gid, s.st_mode); + else if (ftype == FTW_D) { + if (mkdir(dest, s.st_mode) == -1) + errExit("mkdir"); + if (chmod(dest, s.st_mode) < 0) { + fprintf(stderr, "Error: cannot change mode for %s\n", path); + exit(1); + } + if (chown(dest, firejail_uid, firejail_gid) < 0) { + fprintf(stderr, "Error: cannot change ownership for %s\n", path); + exit(1); + } + +#if 0 +struct stat s2; +if (stat(dest, &s2) == 0) { + printf("%s\t", dest); + printf((S_ISDIR(s.st_mode)) ? "d" : "-"); + printf((s.st_mode & S_IRUSR) ? "r" : "-"); + printf((s.st_mode & S_IWUSR) ? "w" : "-"); + printf((s.st_mode & S_IXUSR) ? "x" : "-"); + printf((s.st_mode & S_IRGRP) ? "r" : "-"); + printf((s.st_mode & S_IWGRP) ? "w" : "-"); + printf((s.st_mode & S_IXGRP) ? "x" : "-"); + printf((s.st_mode & S_IROTH) ? "r" : "-"); + printf((s.st_mode & S_IWOTH) ? "w" : "-"); + printf((s.st_mode & S_IXOTH) ? "x" : "-"); + printf("\n"); +} +#endif + + fs_logger2("clone", path); + } + + free(dest); + return(0); +} + +static void duplicate(char *name) { + char *fname = check_dir_or_file(name); + + if (arg_debug) + printf("Private home: duplicating %s\n", fname); + assert(strncmp(fname, cfg.homedir, strlen(cfg.homedir)) == 0); + + struct stat s; + if (stat(fname, &s) == -1) { + free(fname); + return; + } + + if(nftw(fname, fs_copydir, 1, FTW_PHYS) != 0) { + fprintf(stderr, "Error: unable to copy template dir\n"); + exit(1); + } + fs_logger_print(); // save the current log + + free(fname); +} + + + +static char *check_dir_or_file(const char *name) { + assert(name); + struct stat s; + + // basic checks + invalid_filename(name); + + if (arg_debug) + printf("Private home: checking %s\n", name); + + // expand home directory + char *fname = expand_home(name, cfg.homedir); + if (!fname) { + fprintf(stderr, "Error: file %s not found.\n", name); + exit(1); + } + + // If it doesn't start with '/', it must be relative to homedir + if (fname[0] != '/') { + char* tmp; + if (asprintf(&tmp, "%s/%s", cfg.homedir, fname) == -1) + errExit("asprintf"); + free(fname); + fname = tmp; + } + + // check the file is in user home directory + char *rname = realpath(fname, NULL); + if (!rname) { + fprintf(stderr, "Error: invalid file %s\n", name); + exit(1); + } + if (strncmp(rname, cfg.homedir, strlen(cfg.homedir)) != 0) { + fprintf(stderr, "Error: file %s is not in user home directory\n", name); + exit(1); + } + + // a full home directory is not allowed + if (strcmp(rname, cfg.homedir) == 0) { + fprintf(stderr, "Error: invalid directory %s\n", rname); + exit(1); + } + + // only top files and directories in user home are allowed + char *ptr = rname + strlen(cfg.homedir); + if (*ptr == '\0') { + fprintf(stderr, "Error: invalid file %s\n", name); + exit(1); + } + ptr++; + ptr = strchr(ptr, '/'); + if (ptr) { + if (*ptr != '\0') { + fprintf(stderr, "Error: only top files and directories in user home are allowed\n"); + exit(1); + } + } + + if (stat(fname, &s) == -1) { + fprintf(stderr, "Error: file %s not found.\n", fname); + exit(1); + } + + // check uid + uid_t uid = getuid(); + gid_t gid = getgid(); + if (s.st_uid != uid || s.st_gid != gid) { + fprintf(stderr, "Error: only files or directories created by the current user are allowed.\n"); + exit(1); + } + + // dir or regular file + if (S_ISDIR(s.st_mode) || S_ISREG(s.st_mode)) { + free(fname); + return rname; // regular exit from the function + } + + fprintf(stderr, "Error: invalid file type, %s.\n", fname); + exit(1); +} + + +// check directory list specified by user (--private-home option) - exit if it fails +void fs_check_home_list(void) { + if (strstr(cfg.home_private_keep, "..")) { + fprintf(stderr, "Error: invalid private-home list\n"); + exit(1); + } + + char *dlist = strdup(cfg.home_private_keep); + if (!dlist) + errExit("strdup"); + + char *ptr = strtok(dlist, ","); + char *tmp = check_dir_or_file(ptr); + free(tmp); + + while ((ptr = strtok(NULL, ",")) != NULL) { + tmp = check_dir_or_file(ptr); + free(tmp); + } + + free(dlist); } + +// private mode (--private-home=list): +// mount homedir on top of /home/user, +// tmpfs on top of /root in nonroot mode, +// tmpfs on top of /tmp in root mode, +// set skel files, +// restore .Xauthority +void fs_private_home_list(void) { + char *homedir = cfg.homedir; + char *private_list = cfg.home_private_keep; + assert(homedir); + assert(private_list); + + int xflag = store_xauthority(); + int aflag = store_asoundrc(); + + uid_t u = firejail_uid; + gid_t g = firejail_gid; + struct stat s; + if (stat(homedir, &s) == -1) { + fprintf(stderr, "Error: cannot find user home directory\n"); + exit(1); + } + + // create /tmp/firejail/mnt/home directory + fs_build_mnt_dir(); + int rv = mkdir(RUN_HOME_DIR, 0755); + if (rv == -1) + errExit("mkdir"); + if (chown(RUN_HOME_DIR, u, g) < 0) + errExit("chown"); + if (chmod(RUN_HOME_DIR, 0755) < 0) + errExit("chmod"); + ASSERT_PERMS(RUN_HOME_DIR, u, g, 0755); + + fs_logger_print(); // save the current log + + // copy the list of files in the new home directory + // using a new child process without root privileges + pid_t child = fork(); + if (child < 0) + errExit("fork"); + if (child == 0) { + if (arg_debug) + printf("Copying files in the new home:\n"); + + // drop privileges + if (setgroups(0, NULL) < 0) + errExit("setgroups"); + if (setgid(getgid()) < 0) + errExit("setgid/getgid"); + if (setuid(getuid()) < 0) + errExit("setuid/getuid"); + + // copy the list of files in the new home directory + char *dlist = strdup(cfg.home_private_keep); + if (!dlist) + errExit("strdup"); + + char *ptr = strtok(dlist, ","); + duplicate(ptr); + while ((ptr = strtok(NULL, ",")) != NULL) + duplicate(ptr); + + if (!arg_quiet) { + if (size_limit_reached) + fprintf(stderr, "Warning: private-home copy limit of %u MB reached, not all the files were copied\n", + PRIVATE_COPY_LIMIT / (1024 *1024)); + else + printf("Private home: %u files, total size %u bytes\n", file_cnt, size_cnt); + } + + fs_logger_print(); // save the current log + free(dlist); + exit(0); + } + // wait for the child to finish + waitpid(child, NULL, 0); + + if (arg_debug) + printf("Mount-bind %s on top of %s\n", RUN_HOME_DIR, homedir); + + if (mount(RUN_HOME_DIR, homedir, NULL, MS_BIND|MS_REC, NULL) < 0) + errExit("mount bind"); + + if (u != 0) { + // mask /root + if (arg_debug) + printf("Mounting a new /root directory\n"); + if (mount("tmpfs", "/root", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=700,gid=0") < 0) + errExit("mounting home directory"); + } + else { + // mask /home + if (arg_debug) + printf("Mounting a new /home directory\n"); + if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) + errExit("mounting home directory"); + } + + skel(homedir, u, g); + if (xflag) + copy_xauthority(); + if (aflag) + copy_asoundrc(); +} diff --git a/src/firejail/main.c b/src/firejail/main.c index 501bccff2..94000d917 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c @@ -1560,21 +1560,14 @@ int main(int argc, char **argv) { arg_writable_var = 1; } else if (strcmp(argv[i], "--private") == 0) { -#if 0 - if (arg_private_template) { - fprintf(stderr, "Error: --private and --private-template are mutually exclusive\n"); - exit(1); - } -#endif arg_private = 1; } else if (strncmp(argv[i], "--private=", 10) == 0) { -#if 0 - if (arg_private_template) { - fprintf(stderr, "Error: --private and --private-template are mutually exclusive\n"); - exit(1); - } -#endif + if (cfg.home_private_keep) { + fprintf(stderr, "Error: a private list of files was already defined with --private-home option.\n"); + exit(1); + } + // extract private home dirname cfg.home_private = argv[i] + 10; if (*cfg.home_private == '\0') { @@ -1584,21 +1577,25 @@ int main(int argc, char **argv) { fs_check_private_dir(); arg_private = 1; } -#if 0 - else if (strncmp(argv[i], "--private-template=", 19) == 0) { - cfg.private_template = argv[i] + 19; - 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; - } -#endif +#ifdef HAVE_PRIVATE_HOME + else if (strncmp(argv[i], "--private-home=", 15) == 0) { + if (checkcfg(CFG_PRIVATE_HOME)) { + if (cfg.home_private) { + fprintf(stderr, "Error: a private home directory was already defined with --private option.\n"); + exit(1); + } + + // extract private home dirname + cfg.home_private_keep = argv[i] + 15; + fs_check_home_list(); + arg_private = 1; + } + else { + fprintf(stderr, "Error: --private-home feature is disabled in Firejail configuration file\n"); + exit(1); + } + } +#endif 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 ee5d8c159..a516f3216 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c @@ -169,6 +169,18 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { arg_private = 1; return 0; } + if (strncmp(ptr, "private-home ", 13) == 0) { +#ifdef HAVE_PRIVATE_HOME + if (checkcfg(CFG_PRIVATE_HOME)) { + cfg.home_private_keep = ptr + 13; + fs_check_home_list(); + arg_private = 1; + } + else + fprintf(stderr, "Warning: private-home is disabled in Firejail configuration file\n"); +#endif + return 0; + } else if (strcmp(ptr, "private-dev") == 0) { arg_private_dev = 1; return 0; diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 9423ae7e0..76efe996b 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c @@ -540,6 +540,14 @@ int sandbox(void* sandbox_arg) { else fs_private_homedir(); } + else if (cfg.home_private_keep) { // --private-home= + if (cfg.chrootdir) + fprintf(stderr, "Warning: private-home= feature is disabled in chroot\n"); + else if (arg_overlay) + fprintf(stderr, "Warning: private-home= feature is disabled in overlay\n"); + else + fs_private_home_list(); + } else // --private fs_private(); } diff --git a/src/firejail/usage.c b/src/firejail/usage.c index 363f973e8..52d9bbe7e 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c @@ -221,24 +221,10 @@ $ firejail \-\-overlay-path=~/jails/jail1 firefox printf("\tfilesystems. All modifications are discarded when the sandbox is\n"); printf("\tclosed.\n\n"); printf(" --private=directory - use directory as user home.\n\n"); -#if 0 - printf(" --private-template=directory - same as --private but copy the\n"); - printf("\ttemplatedirectory in the tmpfs mounted user home.\n\n"); - -.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 -#endif - - + printf(" --private-home=file,directory - build a new user home in a temporary\n"); + printf("\t\tfilesystem, and copy the files and directories in the list in\n"); + printf("\t\tthe new home. All modifications are discarded when the sandbox\n"); + printf("\t\tis closed.\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-profile.txt b/src/man/firejail-profile.txt index e3217bbff..51b45cd10 100644 --- a/src/man/firejail-profile.txt +++ b/src/man/firejail-profile.txt @@ -170,6 +170,12 @@ closed. \fBprivate directory Use directory as user home. .TP +\f\private-home file,directory +Build a new user home in a temporary +filesystem, and copy the files and directories in the list in the +new home. All modifications are discarded when the sandbox is +closed. +.TP \fBprivate-bin file,file Build a new /bin in a temporary filesystem, and copy the programs in the list. The same directory is also bind-mounted over /sbin, /usr/bin and /usr/sbin. diff --git a/src/man/firejail.txt b/src/man/firejail.txt index dbb0df233..a5d3623b6 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt @@ -1085,6 +1085,19 @@ Example: .br $ firejail \-\-private=/home/netblue/firefox-home firefox +.TP +\fB\-\-private-home=file,directory +Build a new user home in a temporary +filesystem, and copy the files and directories in the list in the +new home. All modifications are discarded when the sandbox is +closed. +.br + +.br +Example: +.br +$ firejail \-\-private-home=.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