// build a basic read-only filesystem void fs_basic_fs(void) { if (arg_debug) printf("Mounting read-only /bin, /sbin, /lib, /lib32, /lib64, /usr, /etc, /var\n"); fs_rdonly("/bin"); fs_rdonly("/sbin"); fs_rdonly("/lib"); fs_rdonly("/lib64"); fs_rdonly("/lib32"); fs_rdonly("/usr"); fs_rdonly("/etc"); fs_rdonly("/var"); // update /var directory in order to support multiple sandboxes running on the same root directory if (!arg_private_dev) fs_dev_shm(); fs_var_lock(); fs_var_tmp(); fs_var_log(); fs_var_lib(); fs_var_cache(); fs_var_utmp(); // don't leak user information restrict_users(); disable_firejail_config(); }
// chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf void fs_chroot(const char *rootdir) { assert(rootdir); //*********************************** // mount-bind a /dev in rootdir //*********************************** // mount /dev char *newdev; if (asprintf(&newdev, "%s/dev", rootdir) == -1) errExit("asprintf"); if (arg_debug) printf("Mounting /dev on %s\n", newdev); if (mount("/dev", newdev, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mounting /dev"); // some older distros don't have a /run directory // create one by default // no exit on error, let the user deal with any problems char *rundir; if (asprintf(&rundir, "%s/run", rootdir) == -1) errExit("asprintf"); if (!is_dir(rundir)) { int rv = mkdir(rundir, S_IRWXU | S_IRWXG | S_IRWXO); (void) rv; rv = chown(rundir, 0, 0); (void) rv; } // copy /etc/resolv.conf in chroot directory // if resolv.conf in chroot is a symbolic link, this will fail // no exit on error, let the user deal with the problem char *fname; if (asprintf(&fname, "%s/etc/resolv.conf", rootdir) == -1) errExit("asprintf"); if (arg_debug) printf("Updating /etc/resolv.conf in %s\n", fname); if (copy_file("/etc/resolv.conf", fname) == -1) fprintf(stderr, "Warning: /etc/resolv.conf not initialized\n"); // chroot into the new directory if (arg_debug) printf("Chrooting into %s\n", rootdir); if (chroot(rootdir) < 0) errExit("chroot"); // update /var directory in order to support multiple sandboxes running on the same root directory if (!arg_private_dev) fs_dev_shm(); fs_var_lock(); fs_var_tmp(); fs_var_log(); fs_var_lib(); fs_var_cache(); fs_var_utmp(); // only in user mode if (getuid()) sanitize_home(); }
// build a basic read-only filesystem void fs_basic_fs(void) { if (arg_debug) printf("Mounting read-only /bin, /sbin, /lib, /lib64, /usr, /etc, /var\n"); fs_rdonly("/bin"); fs_rdonly("/sbin"); fs_rdonly("/lib"); fs_rdonly("/lib64"); fs_rdonly("/usr"); fs_rdonly("/etc"); fs_rdonly("/var"); // update /var directory in order to support multiple sandboxes running on the same root directory if (!arg_private_dev) fs_dev_shm(); fs_var_lock(); fs_var_tmp(); fs_var_log(); fs_var_lib(); fs_var_cache(); fs_var_utmp(); // only in user mode if (getuid()) sanitize_home(); }
// build a basic read-only filesystem void fs_basic_fs(void) { if (arg_debug) printf("Mounting read-only /bin, /sbin, /lib, /lib32, /lib64, /usr, /etc, /var\n"); fs_rdonly("/bin"); fs_rdonly("/sbin"); fs_rdonly("/lib"); fs_rdonly("/lib64"); fs_rdonly("/lib32"); fs_rdonly("/libx32"); fs_rdonly("/usr"); fs_rdonly("/etc"); fs_rdonly("/var"); // update /var directory in order to support multiple sandboxes running on the same root directory if (!arg_private_dev) fs_dev_shm(); fs_var_lock(); fs_var_tmp(); fs_var_log(); fs_var_lib(); fs_var_cache(); fs_var_utmp(); // don't leak user information restrict_users(); // when starting as root, firejail config is not disabled; // this mode could be used to install and test new software by chaining // firejail sandboxes (firejail --force) if (getuid() != 0) disable_firejail_config(); else fprintf(stderr, "Warning: masking /etc/firejail disabled when starting the sandbox as root\n"); }
// chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf void fs_chroot(const char *rootdir) { assert(rootdir); //*********************************** // mount-bind a /dev in rootdir //*********************************** // mount /dev char *newdev; if (asprintf(&newdev, "%s/dev", rootdir) == -1) errExit("asprintf"); if (arg_debug) printf("Mounting /dev on %s\n", newdev); if (mount("/dev", newdev, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mounting /dev"); // some older distros don't have a /run directory // create one by default // no exit on error, let the user deal with any problems char *rundir; if (asprintf(&rundir, "%s/run", rootdir) == -1) errExit("asprintf"); if (!is_dir(rundir)) { int rv = mkdir(rundir, 0755); (void) rv; rv = chown(rundir, 0, 0); (void) rv; } // copy /etc/resolv.conf in chroot directory // if resolv.conf in chroot is a symbolic link, this will fail // no exit on error, let the user deal with the problem char *fname; if (asprintf(&fname, "%s/etc/resolv.conf", rootdir) == -1) errExit("asprintf"); if (arg_debug) printf("Updating /etc/resolv.conf in %s\n", fname); if (is_link(fname)) { fprintf(stderr, "Error: invalid %s file\n", fname); exit(1); } if (copy_file("/etc/resolv.conf", fname) == -1) fprintf(stderr, "Warning: /etc/resolv.conf not initialized\n"); // chroot into the new directory if (arg_debug) printf("Chrooting into %s\n", rootdir); if (chroot(rootdir) < 0) errExit("chroot"); // mount a new tmpfs in /run/firejail/mnt - the old one was lost in chroot fs_build_remount_mnt_dir(); // update /var directory in order to support multiple sandboxes running on the same root directory if (!arg_private_dev) fs_dev_shm(); fs_var_lock(); fs_var_tmp(); fs_var_log(); fs_var_lib(); fs_var_cache(); fs_var_utmp(); // don't leak user information restrict_users(); disable_firejail_config(); }
void fs_overlayfs(void) { // check kernel version struct utsname u; int rv = uname(&u); if (rv != 0) errExit("uname"); int major; int minor; if (2 != sscanf(u.release, "%d.%d", &major, &minor)) { fprintf(stderr, "Error: cannot extract Linux kernel version: %s\n", u.version); exit(1); } if (arg_debug) printf("Linux kernel version %d.%d\n", major, minor); int oldkernel = 0; if (major < 3) { fprintf(stderr, "Error: minimum kernel version required 3.x\n"); exit(1); } if (major == 3 && minor < 18) oldkernel = 1; // build overlay directories fs_build_mnt_dir(); char *oroot; if(asprintf(&oroot, "%s/oroot", RUN_MNT_DIR) == -1) errExit("asprintf"); if (mkdir(oroot, 0755)) errExit("mkdir"); if (chown(oroot, 0, 0) < 0) errExit("chown"); if (chmod(oroot, 0755) < 0) errExit("chmod"); 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); } } char *odiff; if(asprintf(&odiff, "%s/odiff", basedir) == -1) errExit("asprintf"); if (mkdir(odiff, 0755)) errExit("mkdir"); if (chown(odiff, 0, 0) < 0) errExit("chown"); if (chmod(odiff, 0755) < 0) errExit("chmod"); char *owork; if(asprintf(&owork, "%s/owork", basedir) == -1) errExit("asprintf"); if (mkdir(owork, 0755)) errExit("mkdir"); if (chown(owork, 0, 0) < 0) errExit("chown"); if (chmod(owork, 0755) < 0) errExit("chmod"); // mount overlayfs if (arg_debug) printf("Mounting OverlayFS\n"); char *option; if (oldkernel) { // old Ubuntu/OpenSUSE kernels if (arg_overlay_keep) { fprintf(stderr, "Error: option --overlay= not available for kernels older than 3.18\n"); exit(1); } if (asprintf(&option, "lowerdir=/,upperdir=%s", odiff) == -1) errExit("asprintf"); if (mount("overlayfs", oroot, "overlayfs", MS_MGC_VAL, option) < 0) errExit("mounting overlayfs"); } else { // kernel 3.18 or newer if (asprintf(&option, "lowerdir=/,upperdir=%s,workdir=%s", odiff, owork) == -1) errExit("asprintf"); //printf("option #%s#\n", option); if (mount("overlay", oroot, "overlay", MS_MGC_VAL, option) < 0) errExit("mounting overlayfs"); } printf("OverlayFS configured in %s directory\n", basedir); // mount-bind dev directory if (arg_debug) printf("Mounting /dev\n"); char *dev; if (asprintf(&dev, "%s/dev", oroot) == -1) errExit("asprintf"); if (mount("/dev", dev, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mounting /dev"); // chroot in the new filesystem if (chroot(oroot) == -1) errExit("chroot"); // update /var directory in order to support multiple sandboxes running on the same root directory if (!arg_private_dev) fs_dev_shm(); fs_var_lock(); fs_var_tmp(); fs_var_log(); fs_var_lib(); fs_var_cache(); fs_var_utmp(); // don't leak user information restrict_users(); disable_firejail_config(); // cleanup and exit free(option); free(oroot); free(odiff); }
void fs_overlayfs(void) { // check kernel version struct utsname u; int rv = uname(&u); if (rv != 0) errExit("uname"); int major; int minor; if (2 != sscanf(u.release, "%d.%d", &major, &minor)) { fprintf(stderr, "Error: cannot extract Linux kernel version: %s\n", u.version); exit(1); } if (arg_debug) printf("Linux kernel version %d.%d\n", major, minor); int oldkernel = 0; if (major < 3) { fprintf(stderr, "Error: minimum kernel version required 3.x\n"); exit(1); } if (major == 3 && minor < 18) oldkernel = 1; // build overlay directories fs_build_mnt_dir(); char *oroot; if(asprintf(&oroot, "%s/oroot", MNT_DIR) == -1) errExit("asprintf"); if (mkdir(oroot, S_IRWXU | S_IRWXG | S_IRWXO)) errExit("mkdir"); if (chown(oroot, 0, 0) < 0) errExit("chown"); if (chmod(oroot, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) errExit("chmod"); char *odiff; if(asprintf(&odiff, "%s/odiff", MNT_DIR) == -1) errExit("asprintf"); if (mkdir(odiff, S_IRWXU | S_IRWXG | S_IRWXO)) errExit("mkdir"); if (chown(odiff, 0, 0) < 0) errExit("chown"); if (chmod(odiff, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) errExit("chmod"); char *owork; if(asprintf(&owork, "%s/owork", MNT_DIR) == -1) errExit("asprintf"); if (mkdir(owork, S_IRWXU | S_IRWXG | S_IRWXO)) errExit("mkdir"); if (chown(owork, 0, 0) < 0) errExit("chown"); if (chmod(owork, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) errExit("chmod"); // mount overlayfs if (arg_debug) printf("Mounting OverlayFS\n"); char *option; if (oldkernel) { // old Ubuntu/OpenSUSE kernels if (asprintf(&option, "lowerdir=/,upperdir=%s", odiff) == -1) errExit("asprintf"); if (mount("overlayfs", oroot, "overlayfs", MS_MGC_VAL, option) < 0) errExit("mounting overlayfs"); } else { // kernel 3.18 or newer if (asprintf(&option, "lowerdir=/,upperdir=%s,workdir=%s", odiff, owork) == -1) errExit("asprintf"); if (mount("overlay", oroot, "overlay", MS_MGC_VAL, option) < 0) errExit("mounting overlayfs"); } // mount-bind dev directory if (arg_debug) printf("Mounting /dev\n"); char *dev; if (asprintf(&dev, "%s/dev", oroot) == -1) errExit("asprintf"); if (mount("/dev", dev, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mounting /dev"); // chroot in the new filesystem if (chroot(oroot) == -1) errExit("chroot"); // update /var directory in order to support multiple sandboxes running on the same root directory if (!arg_private_dev) fs_dev_shm(); fs_var_lock(); fs_var_tmp(); fs_var_log(); fs_var_lib(); fs_var_cache(); fs_var_utmp(); // only in user mode if (getuid()) sanitize_home(); // cleanup and exit free(option); free(oroot); free(odiff); }
void fs_overlayfs(void) { // check kernel version struct utsname u; int rv = uname(&u); if (rv != 0) errExit("uname"); int major; int minor; if (2 != sscanf(u.release, "%d.%d", &major, &minor)) { fprintf(stderr, "Error: cannot extract Linux kernel version: %s\n", u.version); exit(1); } if (arg_debug) printf("Linux kernel version %d.%d\n", major, minor); int oldkernel = 0; if (major < 3) { fprintf(stderr, "Error: minimum kernel version required 3.x\n"); exit(1); } if (major == 3 && minor < 18) oldkernel = 1; // build overlay directories fs_build_mnt_dir(); char *oroot; if(asprintf(&oroot, "%s/oroot", RUN_MNT_DIR) == -1) errExit("asprintf"); if (mkdir(oroot, 0755)) errExit("mkdir"); if (chown(oroot, 0, 0) < 0) errExit("chown"); if (chmod(oroot, 0755) < 0) errExit("chmod"); 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); } } char *odiff; if(asprintf(&odiff, "%s/odiff", basedir) == -1) errExit("asprintf"); if (mkdir(odiff, 0755)) errExit("mkdir"); if (chown(odiff, 0, 0) < 0) errExit("chown"); if (chmod(odiff, 0755) < 0) errExit("chmod"); char *owork; if(asprintf(&owork, "%s/owork", basedir) == -1) errExit("asprintf"); if (mkdir(owork, 0755)) errExit("mkdir"); if (chown(owork, 0, 0) < 0) errExit("chown"); if (chmod(owork, 0755) < 0) errExit("chmod"); // mount overlayfs if (arg_debug) printf("Mounting OverlayFS\n"); char *option; if (oldkernel) { // old Ubuntu/OpenSUSE kernels if (arg_overlay_keep) { fprintf(stderr, "Error: option --overlay= not available for kernels older than 3.18\n"); exit(1); } if (asprintf(&option, "lowerdir=/,upperdir=%s", odiff) == -1) errExit("asprintf"); if (mount("overlayfs", oroot, "overlayfs", MS_MGC_VAL, option) < 0) errExit("mounting overlayfs"); } else { // kernel 3.18 or newer if (asprintf(&option, "lowerdir=/,upperdir=%s,workdir=%s", odiff, owork) == -1) errExit("asprintf"); if (mount("overlay", oroot, "overlay", MS_MGC_VAL, option) < 0) errExit("mounting overlayfs"); //*************************** // issue #263 start code // My setup has a separate mount point for /home. When the overlay is mounted, // the overlay does not contain the original /home contents. // I added code to create a second overlay for /home if the overlay home dir is empty and this seems to work // @dshmgh, Jan 2016 { char *overlayhome; struct stat s; char *hroot; char *hdiff; char *hwork; // dons add debug if (arg_debug) printf ("DEBUG: chroot dirs are oroot %s odiff %s owork %s\n",oroot,odiff,owork); // BEFORE NEXT, WE NEED TO TEST IF /home has any contents or do we need to mount it? // must create var for oroot/cfg.homedir if (asprintf(&overlayhome,"%s%s",oroot,cfg.homedir) == -1) errExit("asprintf"); if (arg_debug) printf ("DEBUG: overlayhome var holds ##%s##\n",overlayhome); // if no homedir in overlay -- create another overlay for /home if (stat(overlayhome, &s) == -1) { if(asprintf(&hroot, "%s/oroot/home", RUN_MNT_DIR) == -1) errExit("asprintf"); if(asprintf(&hdiff, "%s/hdiff", basedir) == -1) errExit("asprintf"); 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) errExit("chmod"); if(asprintf(&hwork, "%s/hwork", basedir) == -1) errExit("asprintf"); 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) errExit("chmod"); // no homedir in overlay so now mount another overlay for /home if (asprintf(&option, "lowerdir=/home,upperdir=%s,workdir=%s", hdiff, hwork) == -1) errExit("asprintf"); if (mount("overlay", hroot, "overlay", MS_MGC_VAL, option) < 0) errExit("mounting overlayfs for mounted home directory"); printf("OverlayFS for /home configured in %s directory\n", basedir); } // stat(overlayhome) free(overlayhome); } // issue #263 end code //*************************** } printf("OverlayFS configured in %s directory\n", basedir); // mount-bind dev directory if (arg_debug) printf("Mounting /dev\n"); char *dev; if (asprintf(&dev, "%s/dev", oroot) == -1) errExit("asprintf"); if (mount("/dev", dev, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mounting /dev"); fs_logger("whitelist /dev"); // mount-bind run directory if (arg_debug) printf("Mounting /run\n"); char *run; if (asprintf(&run, "%s/run", oroot) == -1) errExit("asprintf"); if (mount("/run", run, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mounting /run"); fs_logger("whitelist /run"); // chroot in the new filesystem if (chroot(oroot) == -1) errExit("chroot"); // update /var directory in order to support multiple sandboxes running on the same root directory if (!arg_private_dev) fs_dev_shm(); fs_var_lock(); fs_var_tmp(); fs_var_log(); fs_var_lib(); fs_var_cache(); fs_var_utmp(); // don't leak user information restrict_users(); // when starting as root, firejail config is not disabled; // this mode could be used to install and test new software by chaining // firejail sandboxes (firejail --force) if (getuid() != 0) disable_firejail_config(); else fprintf(stderr, "Warning: masking /etc/firejail disabled when starting the sandbox as root\n"); // cleanup and exit free(option); free(oroot); free(odiff); }