// 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(); }
void restrict_users(void) { // only in user mode if (getuid()) { if (strncmp(cfg.homedir, "/home/", 6) == 0) { // user has the home directory under /home sanitize_home(); } else { // user has the home diercotry outside /home // mount tmpfs on top of /home in order to hide it if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mount tmpfs"); fs_logger("tmpfs /home"); } sanitize_passwd(); sanitize_group(); } }
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); }