From 32e6cb2b6425b48c9cc2d456f81460ec6b3fc5b3 Mon Sep 17 00:00:00 2001 From: Adis Hamzić Date: Fri, 12 Aug 2016 18:06:47 +0200 Subject: added more overlay options --- src/firejail/firejail.h | 3 +- src/firejail/fs.c | 54 ++++++++++++++++++++------ src/firejail/main.c | 100 +++++++++++++++++++++++++++++++++++++----------- src/firejail/usage.c | 18 +++++++-- src/man/firejail.txt | 44 +++++++++++++++++++-- 5 files changed, 176 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 16b9d468f..ee70f19f1 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -221,7 +221,8 @@ extern int arg_debug_whitelists; // print debug messages for whitelists extern int arg_nonetwork; // --net=none extern int arg_command; // -c extern int arg_overlay; // overlay option -extern int arg_overlay_keep; // place overlay diff directory in ~/.firejail +extern int arg_overlay_keep; // place overlay diff in a known directory +extern int arg_overlay_reuse; // allow the reuse of overlays extern int arg_zsh; // use zsh as default shell extern int arg_csh; // use csh as default shell diff --git a/src/firejail/fs.c b/src/firejail/fs.c index 86126672e..c152abe0d 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c @@ -879,21 +879,37 @@ void fs_overlayfs(void) { if (chmod(oroot, 0755) < 0) errExit("chmod"); + struct stat s; char *basedir = RUN_MNT_DIR; if (arg_overlay_keep) { // set base for working and diff directories basedir = cfg.overlay_dir; - if (mkdir(basedir, 0755) != 0) { - fprintf(stderr, "Error: cannot create overlay directory\n"); - exit(1); + + // does the overlay exist? + if (stat(basedir, &s) == 0) { + if (arg_overlay_reuse == 0) { + fprintf(stderr, "Error: overlay directory exists, but reuse is not allowed\n"); + exit(1); + } + } + else { + if (mkdir(basedir, 0755) != 0) { + fprintf(stderr, "Error: cannot create overlay directory\n"); + exit(1); + } } } char *odiff; if(asprintf(&odiff, "%s/odiff", basedir) == -1) errExit("asprintf"); - if (mkdir(odiff, 0755)) - errExit("mkdir"); + + // no need to check arg_overlay_reuse + if (stat(odiff, &s) != 0) { + if (mkdir(odiff, 0755)) + errExit("mkdir"); + } + if (chown(odiff, 0, 0) < 0) errExit("chown"); if (chmod(odiff, 0755) < 0) @@ -902,8 +918,13 @@ void fs_overlayfs(void) { char *owork; if(asprintf(&owork, "%s/owork", basedir) == -1) errExit("asprintf"); - if (mkdir(owork, 0755)) - errExit("mkdir"); + + // no need to check arg_overlay_reuse + if (stat(owork, &s) != 0) { + if (mkdir(owork, 0755)) + errExit("mkdir"); + } + if (chown(owork, 0, 0) < 0) errExit("chown"); if (chmod(owork, 0755) < 0) @@ -959,8 +980,13 @@ void fs_overlayfs(void) { if(asprintf(&hdiff, "%s/hdiff", basedir) == -1) errExit("asprintf"); - if (mkdir(hdiff, S_IRWXU | S_IRWXG | S_IRWXO)) - errExit("mkdir"); + + // no need to check arg_overlay_reuse + if (stat(hdiff, &s) != 0) { + if (mkdir(hdiff, S_IRWXU | S_IRWXG | S_IRWXO)) + errExit("mkdir"); + } + if (chown(hdiff, 0, 0) < 0) errExit("chown"); if (chmod(hdiff, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) @@ -968,8 +994,13 @@ void fs_overlayfs(void) { if(asprintf(&hwork, "%s/hwork", basedir) == -1) errExit("asprintf"); - if (mkdir(hwork, S_IRWXU | S_IRWXG | S_IRWXO)) - errExit("mkdir"); + + // no need to check arg_overlay_reuse + if (stat(hwork, &s) != 0) { + if (mkdir(hwork, S_IRWXU | S_IRWXG | S_IRWXO)) + errExit("mkdir"); + } + if (chown(hwork, 0, 0) < 0) errExit("chown"); if (chmod(hwork, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) @@ -1011,7 +1042,6 @@ void fs_overlayfs(void) { fs_logger("whitelist /run"); // mount-bind /tmp/.X11-unix directory - struct stat s; if (stat("/tmp/.X11-unix", &s) == 0) { if (arg_debug) printf("Mounting /tmp/.X11-unix\n"); diff --git a/src/firejail/main.c b/src/firejail/main.c index acae7c3dd..120809456 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c @@ -59,7 +59,8 @@ int arg_debug_whitelists; // print debug messages for whitelists int arg_nonetwork = 0; // --net=none int arg_command = 0; // -c int arg_overlay = 0; // overlay option -int arg_overlay_keep = 0; // place overlay diff directory in ~/.firejail +int arg_overlay_keep = 0; // place overlay diff in a known directory +int arg_overlay_reuse = 0; // allow the reuse of overlays int arg_zsh = 0; // use zsh as default shell int arg_csh = 0; // use csh as default shell @@ -691,6 +692,41 @@ static void delete_x11_file(pid_t pid) { free(fname); } +static char *create_and_check_overlay_dir(const char *subdirname, int allow_reuse) { + // create ~/.firejail directory + struct stat s; + char *dirname; + if (asprintf(&dirname, "%s/.firejail", cfg.homedir) == -1) + errExit("asprintf"); + if (stat(dirname, &s) == -1) { + /* coverity[toctou] */ + if (mkdir(dirname, 0700)) + errExit("mkdir"); + if (chown(dirname, getuid(), getgid()) < 0) + errExit("chown"); + if (chmod(dirname, 0700) < 0) + errExit("chmod"); + } + else if (is_link(dirname)) { + fprintf(stderr, "Error: invalid ~/.firejail directory\n"); + exit(1); + } + + free(dirname); + + // check overlay directory + if (asprintf(&dirname, "%s/.firejail/%s", cfg.homedir, subdirname) == -1) + errExit("asprintf"); + if (allow_reuse == 0) { + if (stat(dirname, &s) == 0) { + fprintf(stderr, "Error: overlay directory already exists: %s\n", dirname); + exit(1); + } + } + + return dirname; +} + static void detect_quiet(int argc, char **argv) { int i; @@ -1193,34 +1229,54 @@ int main(int argc, char **argv) { arg_overlay = 1; arg_overlay_keep = 1; - // create ~/.firejail directory - char *dirname; - if (asprintf(&dirname, "%s/.firejail", cfg.homedir) == -1) + char *subdirname; + if (asprintf(&subdirname, "%d", getpid()) == -1) errExit("asprintf"); - if (stat(dirname, &s) == -1) { - /* coverity[toctou] */ - if (mkdir(dirname, 0700)) - errExit("mkdir"); - if (chown(dirname, getuid(), getgid()) < 0) - errExit("chown"); - if (chmod(dirname, 0700) < 0) - errExit("chmod"); - } - else if (is_link(dirname)) { - fprintf(stderr, "Error: invalid ~/.firejail directory\n"); + cfg.overlay_dir = create_and_check_overlay_dir(subdirname, arg_overlay_reuse); + + free(subdirname); + } + else if (strncmp(argv[i], "--overlay-named=", 16) == 0) { + if (cfg.chrootdir) { + fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); + exit(1); + } + struct stat s; + if (stat("/proc/sys/kernel/grsecurity", &s) == 0) { + fprintf(stderr, "Error: --overlay option is not available on Grsecurity systems\n"); exit(1); } + arg_overlay = 1; + arg_overlay_keep = 1; + arg_overlay_reuse = 1; - free(dirname); + char *subdirname = argv[i] + 16; + if (subdirname == '\0') { + fprintf(stderr, "Error: invalid overlay option\n"); + exit(1); + } + cfg.overlay_dir = create_and_check_overlay_dir(subdirname, arg_overlay_reuse); + } + else if (strncmp(argv[i], "--overlay-path=", 15) == 0) { + if (cfg.chrootdir) { + fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); + exit(1); + } + struct stat s; + if (stat("/proc/sys/kernel/grsecurity", &s) == 0) { + fprintf(stderr, "Error: --overlay option is not available on Grsecurity systems\n"); + exit(1); + } + arg_overlay = 1; + arg_overlay_keep = 1; + arg_overlay_reuse = 1; - // check overlay directory - if (asprintf(&dirname, "%s/.firejail/%d", cfg.homedir, getpid()) == -1) - errExit("asprintf"); - if (stat(dirname, &s) == 0) { - fprintf(stderr, "Error: overlay directory already exists: %s\n", dirname); + char *dirname = argv[i] + 15; + if (dirname == '\0') { + fprintf(stderr, "Error: invalid overlay option\n"); exit(1); } - cfg.overlay_dir = dirname; + cfg.overlay_dir = expand_home(dirname, cfg.homedir); } else if (strcmp(argv[i], "--overlay-tmpfs") == 0) { if (cfg.chrootdir) { diff --git a/src/firejail/usage.c b/src/firejail/usage.c index 03558cca7..ed6d22e69 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c @@ -176,16 +176,26 @@ void usage(void) { printf(" --overlay - mount a filesystem overlay on top of the current filesystem.\n"); printf("\tThe upper filesystem layer is persistent, and stored in\n"); - printf("\t$HOME/.firejail directory. (OverlayFS support is required in\n"); - printf("\tLinux kernel for this option to work). \n\n"); + printf("\t$HOME/.firejail/ directory. (OverlayFS support is required in\n"); + printf("\tLinux kernel for this option to work). \n\n"); + + printf(" --overlay-named=name - mount a filesystem overlay on top of the current\n"); + printf("\tfilesystem. The upper filesystem layer is persistent, and stored in\n"); + printf("\t$HOME/.firejail/ directory. (OverlayFS support is required in\n"); + printf("\tLinux kernel for this option to work). \n\n"); + + printf(" --overlay-path=path - mount a filesystem overlay on top of the current\n"); + printf("\tfilesystem. The upper filesystem layer is persistent, and stored in\n"); + printf("\tthe specified path. (OverlayFS support is required in Linux kernel for\n"); + printf("\tthis option to work). \n\n"); - printf(" --overlay-clean - clean all overlays stored in $HOME/.firejail directory.\n\n"); - printf(" --overlay-tmpfs - mount a filesystem overlay on top of the current\n"); printf("\tfilesystem. The upper layer is stored in a tmpfs filesystem,\n"); printf("\tand it is discarded when the sandbox is closed. (OverlayFS\n"); printf("\tsupport is required in Linux kernel for this option to work).\n\n"); + printf(" --overlay-clean - clean all overlays stored in $HOME/.firejail directory.\n\n"); + printf(" --private - mount new /root and /home/user directories in temporary\n"); printf("\tfilesystems. All modifications are discarded when the sandbox is\n"); printf("\tclosed.\n\n"); diff --git a/src/man/firejail.txt b/src/man/firejail.txt index fb8cb630b..3cc9a8401 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt @@ -994,7 +994,7 @@ $ ls -l sandboxlog* \fB\-\-overlay Mount a filesystem overlay on top of the current filesystem. Unlike the regular filesystem container, the system directories are mounted read-write. All filesystem modifications go into the overlay. -The overlay is stored in $HOME/.firejail directory. This option is not available on Grsecurity systems. +The overlay is stored in $HOME/.firejail/ directory. This option is not available on Grsecurity systems. .br .br @@ -1008,14 +1008,40 @@ Example: $ firejail \-\-overlay firefox .TP -\fB\-\-overlay-clean -Clean all overlays stored in $HOME/.firejail directory. +\fB\-\-overlay-named=name +Mount a filesystem overlay on top of the current filesystem. Unlike the regular filesystem container, +the system directories are mounted read-write. All filesystem modifications go into the overlay. +The overlay is stored in $HOME/.firejail/ directory. The created overlay can be reused between multiple +sessions. This option is not available on Grsecurity systems. +.br + +.br +OverlayFS support is required in Linux kernel for this option to work. +OverlayFS was officially introduced in Linux kernel version 3.18 .br .br Example: .br -$ firejail \-\-overlay-clean +$ firejail \-\-overlay-named=jail1 firefox + +.TP +\fB\-\-overlay-path=path +Mount a filesystem overlay on top of the current filesystem. Unlike the regular filesystem container, +the system directories are mounted read-write. All filesystem modifications go into the overlay. +The overlay is stored in the specified path. The created overlay can be reused between multiple sessions. +This option is not available on Grsecurity systems. +.br + +.br +OverlayFS support is required in Linux kernel for this option to work. +OverlayFS was officially introduced in Linux kernel version 3.18 +.br + +.br +Example: +.br +$ firejail \-\-overlay-path=~/jails/jail1 firefox .TP \fB\-\-overlay-tmpfs @@ -1033,6 +1059,16 @@ Example: .br $ firejail \-\-overlay-tmpfs firefox +.TP +\fB\-\-overlay-clean +Clean all overlays stored in $HOME/.firejail directory. +.br + +.br +Example: +.br +$ firejail \-\-overlay-clean + .TP \fB\-\-private Mount new /root and /home/user directories in temporary -- cgit v1.2.3-70-g09d2