void fs_var_cache(void) { struct stat s; if (stat("/var/cache/apache2", &s) == 0) { if (arg_debug) printf("Mounting tmpfs on /var/cache/apache2\n"); if (mount("tmpfs", "/var/cache/apache2", "tmpfs", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting /var/cache/apache2"); fs_logger("tmpfs /var/cache/apache2"); } if (stat("/var/cache/lighttpd", &s) == 0) { if (arg_debug) printf("Mounting tmpfs on /var/cache/lighttpd\n"); if (mount("tmpfs", "/var/cache/lighttpd", "tmpfs", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting /var/cache/lighttpd"); fs_logger("tmpfs /var/cache/lighttpd"); struct passwd *p = getpwnam("www-data"); uid_t uid = 0; gid_t gid = 0; if (p) { uid = p->pw_uid; gid = p->pw_gid; } mkdir_attr("/var/cache/lighttpd/compress", 0755, uid, gid); fs_logger("mkdir /var/cache/lighttpd/compress"); mkdir_attr("/var/cache/lighttpd/uploads", 0755, uid, gid); fs_logger("/var/cache/lighttpd/uploads"); } }
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 (lstat(fname, &s) == -1) { free(fname); return; } else if (S_ISDIR(s.st_mode)) { // create the directory in RUN_HOME_DIR char *name; char *ptr = strrchr(fname, '/'); ptr++; if (asprintf(&name, "%s/%s", RUN_HOME_DIR, ptr) == -1) errExit("asprintf"); mkdir_attr(name, 0755, getuid(), getgid()); sbox_run(SBOX_USER| SBOX_CAPS_NONE | SBOX_SECCOMP, 3, PATH_FCOPY, fname, name); free(name); } else sbox_run(SBOX_USER| SBOX_CAPS_NONE | SBOX_SECCOMP, 3, PATH_FCOPY, fname, RUN_HOME_DIR); fs_logger2("clone", fname); fs_logger_print(); // save the current log free(fname); }
void fs_var_lock(void) { if (is_dir("/var/lock")) { if (arg_debug) printf("Mounting tmpfs on /var/lock\n"); if (mount("tmpfs", "/var/lock", "tmpfs", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=1777,gid=0") < 0) errExit("mounting /lock"); fs_logger("tmpfs /var/lock"); } else { char *lnk = realpath("/var/lock", NULL); if (lnk) { if (!is_dir(lnk)) { // create directory mkdir_attr(lnk, S_IRWXU|S_IRWXG|S_IRWXO, 0, 0); } if (arg_debug) printf("Mounting tmpfs on %s on behalf of /var/lock\n", lnk); if (mount("tmpfs", lnk, "tmpfs", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=1777,gid=0") < 0) errExit("mounting /var/lock"); free(lnk); fs_logger("tmpfs /var/lock"); } else { fwarning("/var/lock not mounted\n"); dbg_test_dir("/var/lock"); } } }
// 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 uid = getuid(); gid_t gid = getgid(); // create /run/firejail/mnt/home directory mkdir_attr(RUN_HOME_DIR, 0755, uid, gid); fs_logger_print(); // save the current log if (arg_debug) printf("Copying files in the new home:\n"); // 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); fs_logger_print(); // save the current log free(dlist); 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 (uid != 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, uid, gid); if (xflag) copy_xauthority(); if (aflag) copy_asoundrc(); }
static void build_dirs(void) { // create directories under /var/log DirData *ptr = dirlist; while (ptr) { mkdir_attr(ptr->name, ptr->st_mode, ptr->st_uid, ptr->st_gid); fs_logger2("mkdir", ptr->name); ptr = ptr->next; } }
static void mount_dev_shm(void) { mkdir_attr("/dev/shm", 01777, 0, 0); int rv = mount(RUN_DEV_DIR "/shm", "/dev/shm", "none", MS_BIND, "mode=01777,gid=0"); if (rv == -1) { fwarning("cannot mount the old /dev/shm in private-dev\n"); dbg_test_dir(RUN_DEV_DIR "/shm"); empty_dev_shm(); return; } }
static void deventry_mount(void) { int i = 0; while (dev[i].dev_fname != NULL) { struct stat s; if (stat(dev[i].run_fname, &s) == 0) { // check device type and subsystem configuration if ((dev[i].type == DEV_SOUND && arg_nosound == 0) || (dev[i].type == DEV_3D && arg_no3d == 0) || (dev[i].type == DEV_VIDEO && arg_novideo == 0) || (dev[i].type == DEV_TV && arg_notv == 0) || (dev[i].type == DEV_DVD && arg_nodvd == 0) || (dev[i].type == DEV_U2F && arg_nou2f == 0)) { int dir = is_dir(dev[i].run_fname); if (arg_debug) printf("mounting %s %s\n", dev[i].run_fname, (dir)? "directory": "file"); if (dir) { mkdir_attr(dev[i].dev_fname, 0755, 0, 0); } else { struct stat s; if (stat(dev[i].run_fname, &s) == -1) { if (arg_debug) fwarning("cannot stat %s file\n", dev[i].run_fname); i++; continue; } FILE *fp = fopen(dev[i].dev_fname, "w"); if (fp) { fprintf(fp, "\n"); SET_PERMS_STREAM(fp, s.st_uid, s.st_gid, s.st_mode); fclose(fp); } } if (mount(dev[i].run_fname, dev[i].dev_fname, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mounting dev file"); fs_logger2("whitelist", dev[i].dev_fname); } } i++; } }
void appimage_set(const char *appimage) { assert(appimage); assert(devloop == NULL); // don't call this twice! EUID_ASSERT(); #ifdef LOOP_CTL_GET_FREE // test for older kernels; this definition is found in /usr/include/linux/loop.h // check appimage file invalid_filename(appimage); if (access(appimage, R_OK) == -1) { fprintf(stderr, "Error: cannot access AppImage file\n"); exit(1); } // get appimage type and ELF size // a value of 0 means we are dealing with a type1 appimage long unsigned int size = appimage2_size(appimage); if (arg_debug) printf("AppImage ELF size %lu\n", size); // open appimage file /* coverity[toctou] */ int ffd = open(appimage, O_RDONLY|O_CLOEXEC); if (ffd == -1) { fprintf(stderr, "Error: cannot open AppImage file\n"); exit(1); } // find or allocate a free loop device to use EUID_ROOT(); int cfd = open("/dev/loop-control", O_RDWR); if (cfd == -1) { fprintf(stderr, "Error: /dev/loop-control interface is not supported by your kernel\n"); exit(1); } int devnr = ioctl(cfd, LOOP_CTL_GET_FREE); if (devnr == -1) { fprintf(stderr, "Error: cannot allocate a new loopback device\n"); exit(1); } close(cfd); if (asprintf(&devloop, "/dev/loop%d", devnr) == -1) errExit("asprintf"); int lfd = open(devloop, O_RDONLY); if (lfd == -1) { fprintf(stderr, "Error: cannot open %s\n", devloop); exit(1); } if (ioctl(lfd, LOOP_SET_FD, ffd) == -1) { fprintf(stderr, "Error: cannot configure the loopback device\n"); exit(1); } if (size) { struct loop_info64 info; memset(&info, 0, sizeof(struct loop_info64)); info.lo_offset = size; if (ioctl(lfd, LOOP_SET_STATUS64, &info) == -1) errExit("configure appimage offset"); } close(lfd); close(ffd); EUID_USER(); // creates appimage mount point perms 0700 if (asprintf(&mntdir, "%s/.appimage-%u", RUN_FIREJAIL_APPIMAGE_DIR, getpid()) == -1) errExit("asprintf"); EUID_ROOT(); mkdir_attr(mntdir, 0700, getuid(), getgid()); EUID_USER(); // mount char *mode; if (asprintf(&mode, "mode=700,uid=%d,gid=%d", getuid(), getgid()) == -1) errExit("asprintf"); EUID_ROOT(); if (size == 0) { if (mount(devloop, mntdir, "iso9660",MS_MGC_VAL|MS_RDONLY, mode) < 0) errExit("mounting appimage"); } else { if (mount(devloop, mntdir, "squashfs",MS_MGC_VAL|MS_RDONLY, mode) < 0) errExit("mounting appimage"); } if (arg_debug) printf("appimage mounted on %s\n", mntdir); EUID_USER(); // set environment if (setenv("APPIMAGE", appimage, 1) < 0) errExit("setenv"); if (mntdir && setenv("APPDIR", mntdir, 1) < 0) errExit("setenv"); // build new command line if (asprintf(&cfg.command_line, "%s/AppRun", mntdir) == -1) errExit("asprintf"); free(mode); #ifdef HAVE_GCOV __gcov_flush(); #endif #else fprintf(stderr, "Error: /dev/loop-control interface is not supported by your kernel\n"); exit(1); #endif }
static int fs_copydir(const char *infname, const struct stat *st, int ftype, struct FTW *sftw) { (void) st; (void) sftw; assert(infname); assert(*infname != '\0'); assert(outpath); assert(*outpath != '\0'); assert(inpath); // check size limit if (size_limit_reached) return 0; char *outfname; if (asprintf(&outfname, "%s%s", outpath, infname + strlen(inpath)) == -1) errExit("asprintf"); //printf("outpaht %s\n", outpath); //printf("inpath %s\n", inpath); //printf("infname %s\n", infname); //printf("outfname %s\n\n", outfname); // don't copy it if we already have the file struct stat s; if (stat(outfname, &s) == 0) { if (first) first = 0; else fprintf(stderr, "Warning fcopy: skipping %s, file already present\n", infname); free(outfname); return 0; } // extract mode and ownership if (stat(infname, &s) != 0) { fprintf(stderr, "Warning fcopy: skipping %s, cannot find inode\n", infname); free(outfname); return 0; } uid_t uid = s.st_uid; gid_t gid = s.st_gid; mode_t mode = s.st_mode; // recalculate size if ((s.st_size + size_cnt) > COPY_LIMIT) { fprintf(stderr, "Error fcopy: size limit of %dMB reached\n", (COPY_LIMIT / 1024) / 1024); size_limit_reached = 1; free(outfname); return 0; } file_cnt++; size_cnt += s.st_size; if(ftype == FTW_F) { copy_file(infname, outfname, mode, uid, gid); } else if (ftype == FTW_D) { mkdir_attr(outfname, mode, uid, gid); } else if (ftype == FTW_SL) { copy_link(infname, outfname, mode, uid, gid); } return(0); }
void fs_private_dev(void){ // install a new /dev directory if (arg_debug) printf("Mounting tmpfs on /dev\n"); // create DRI_DIR // keep a copy of dev directory mkdir_attr(RUN_DEV_DIR, 0755, 0, 0); if (mount("/dev", RUN_DEV_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mounting /dev"); // create DEVLOG_FILE int have_devlog = 0; struct stat s; if (stat("/dev/log", &s) == 0) { have_devlog = 1; FILE *fp = fopen(RUN_DEVLOG_FILE, "w"); if (!fp) have_devlog = 0; else { fprintf(fp, "\n"); fclose(fp); if (mount("/dev/log", RUN_DEVLOG_FILE, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mounting /dev/log"); } } // mount tmpfs on top of /dev if (mount("tmpfs", "/dev", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting /dev"); fs_logger("tmpfs /dev"); // optional devices: sound, video cards etc... deventry_mount(); // bring back /dev/log if (have_devlog) { FILE *fp = fopen("/dev/log", "w"); if (fp) { fprintf(fp, "\n"); fclose(fp); if (mount(RUN_DEVLOG_FILE, "/dev/log", NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mounting /dev/log"); fs_logger("clone /dev/log"); } } // bring forward the current /dev/shm directory if necessary if (arg_debug) printf("Process /dev/shm directory\n"); process_dev_shm(); if (mount(RUN_RO_DIR, RUN_DEV_DIR, "none", MS_BIND, "mode=400,gid=0") < 0) errExit("disable run dev directory"); // create default devices create_char_dev("/dev/zero", 0666, 1, 5); // mknod -m 666 /dev/zero c 1 5 fs_logger("mknod /dev/zero"); create_char_dev("/dev/null", 0666, 1, 3); // mknod -m 666 /dev/null c 1 3 fs_logger("mknod /dev/null"); create_char_dev("/dev/full", 0666, 1, 7); // mknod -m 666 /dev/full c 1 7 fs_logger("mknod /dev/full"); create_char_dev("/dev/random", 0666, 1, 8); // Mknod -m 666 /dev/random c 1 8 fs_logger("mknod /dev/random"); create_char_dev("/dev/urandom", 0666, 1, 9); // mknod -m 666 /dev/urandom c 1 9 fs_logger("mknod /dev/urandom"); create_char_dev("/dev/tty", 0666, 5, 0); // mknod -m 666 /dev/tty c 5 0 fs_logger("mknod /dev/tty"); #if 0 create_dev("/dev/tty0", "mknod -m 666 /dev/tty0 c 4 0"); create_dev("/dev/console", "mknod -m 622 /dev/console c 5 1"); #endif // pseudo-terminal mkdir_attr("/dev/pts", 0755, 0, 0); fs_logger("mkdir /dev/pts"); fs_logger("create /dev/pts"); create_char_dev("/dev/pts/ptmx", 0666, 5, 2); //"mknod -m 666 /dev/pts/ptmx c 5 2"); fs_logger("mknod /dev/pts/ptmx"); create_link("/dev/pts/ptmx", "/dev/ptmx"); // code before github issue #351 // mount -vt devpts -o newinstance -o ptmxmode=0666 devpts //dev/pts // if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL, "newinstance,ptmxmode=0666") < 0) // errExit("mounting /dev/pts"); // mount /dev/pts gid_t ttygid = get_group_id("tty"); char *data; if (asprintf(&data, "newinstance,gid=%d,mode=620,ptmxmode=0666", (int) ttygid) == -1) errExit("asprintf"); if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL, data) < 0) errExit("mounting /dev/pts"); free(data); fs_logger("clone /dev/pts"); // stdin, stdout, stderr #if 0 create_link("/proc/self/fd", "/dev/fd"); create_link("/proc/self/fd/0", "/dev/stdin"); create_link("/proc/self/fd/1", "/dev/stdout"); create_link("/proc/self/fd/2", "/dev/stderr"); #endif // symlinks for DVD/CD players if (stat("/dev/sr0", &s) == 0) { create_link("/dev/sr0", "/dev/cdrom"); create_link("/dev/sr0", "/dev/cdrw"); create_link("/dev/sr0", "/dev/dvd"); create_link("/dev/sr0", "/dev/dvdrw"); } }
static void empty_dev_shm(void) { // create an empty /dev/shm directory mkdir_attr("/dev/shm", 01777, 0, 0); fs_logger("mkdir /dev/shm"); fs_logger("create /dev/shm"); }
// whitelist for /home/user directory void fs_whitelist(void) { char *homedir = cfg.homedir; assert(homedir); ProfileEntry *entry = cfg.profile; if (!entry) return; char *new_name = NULL; int home_dir = 0; // /home/user directory flag int tmp_dir = 0; // /tmp directory flag int media_dir = 0; // /media directory flag int mnt_dir = 0; // /mnt directory flag int var_dir = 0; // /var directory flag int dev_dir = 0; // /dev directory flag int opt_dir = 0; // /opt directory flag int srv_dir = 0; // /srv directory flag // verify whitelist files, extract symbolic links, etc. while (entry) { // handle only whitelist commands if (strncmp(entry->data, "whitelist ", 10)) { entry = entry->next; continue; } // resolve ${DOWNLOADS} if (strcmp(entry->data + 10, "${DOWNLOADS}") == 0) { char *tmp = resolve_downloads(); if (tmp) entry->data = tmp; else { *entry->data = '\0'; fprintf(stderr, "***\n"); fprintf(stderr, "*** Warning: cannot whitelist Downloads directory\n"); fprintf(stderr, "*** \tAny file saved will be lost when the sandbox is closed.\n"); fprintf(stderr, "*** \tPlease create a proper Downloads directory for your application.\n"); fprintf(stderr, "***\n"); continue; } } // replace ~/ or ${HOME} into /home/username // if (new_name) // free(new_name); new_name = expand_home(entry->data + 10, cfg.homedir); assert(new_name); if (arg_debug) fprintf(stderr, "Debug %d: new_name #%s#\n", __LINE__, new_name); // valid path referenced to filesystem root if (*new_name != '/') { if (arg_debug) fprintf(stderr, "Debug %d: \n", __LINE__); goto errexit; } // extract the absolute path of the file // realpath function will fail with ENOENT if the file is not found char *fname = realpath(new_name, NULL); if (!fname) { // file not found, blank the entry in the list and continue if (arg_debug || arg_debug_whitelists) { printf("Removed whitelist path: %s\n", entry->data); printf("\texpanded: %s\n", new_name); printf("\treal path: (null)\n"); printf("\t"); fflush(0); perror("realpath"); } *entry->data = '\0'; // if 1 the file was not found; mount an empty directory if (strncmp(new_name, cfg.homedir, strlen(cfg.homedir)) == 0) { if(!arg_private) home_dir = 1; } else if (strncmp(new_name, "/tmp/", 5) == 0) tmp_dir = 1; else if (strncmp(new_name, "/media/", 7) == 0) media_dir = 1; else if (strncmp(new_name, "/mnt/", 5) == 0) mnt_dir = 1; else if (strncmp(new_name, "/var/", 5) == 0) var_dir = 1; else if (strncmp(new_name, "/dev/", 5) == 0) dev_dir = 1; else if (strncmp(new_name, "/opt/", 5) == 0) opt_dir = 1; else if (strncmp(new_name, "/srv/", 5) == 0) opt_dir = 1; continue; } // check for supported directories if (strncmp(new_name, cfg.homedir, strlen(cfg.homedir)) == 0) { // whitelisting home directory is disabled if --private option is present if (arg_private) { if (arg_debug || arg_debug_whitelists) printf("Removed whitelist path %s, --private option is present\n", entry->data); *entry->data = '\0'; continue; } entry->home_dir = 1; home_dir = 1; if (arg_debug || arg_debug_whitelists) fprintf(stderr, "Debug %d: fname #%s#, cfg.homedir #%s#\n", __LINE__, fname, cfg.homedir); // both path and absolute path are under /home if (strncmp(fname, cfg.homedir, strlen(cfg.homedir)) != 0) { // check if the file is owned by the user struct stat s; if (stat(fname, &s) == 0 && s.st_uid != getuid()) goto errexit; } } else if (strncmp(new_name, "/tmp/", 5) == 0) { entry->tmp_dir = 1; tmp_dir = 1; // both path and absolute path are under /tmp if (strncmp(fname, "/tmp/", 5) != 0) { goto errexit; } } else if (strncmp(new_name, "/media/", 7) == 0) { entry->media_dir = 1; media_dir = 1; // both path and absolute path are under /media if (strncmp(fname, "/media/", 7) != 0) { goto errexit; } } else if (strncmp(new_name, "/mnt/", 5) == 0) { entry->mnt_dir = 1; mnt_dir = 1; // both path and absolute path are under /mnt if (strncmp(fname, "/mnt/", 5) != 0) { goto errexit; } } else if (strncmp(new_name, "/var/", 5) == 0) { entry->var_dir = 1; var_dir = 1; // both path and absolute path are under /var // exceptions: /var/run and /var/lock if (strcmp(new_name, "/var/run")== 0) ; else if (strcmp(new_name, "/var/lock")== 0) ; else if (strncmp(fname, "/var/", 5) != 0) { goto errexit; } } else if (strncmp(new_name, "/dev/", 5) == 0) { entry->dev_dir = 1; dev_dir = 1; // both path and absolute path are under /dev if (strncmp(fname, "/dev/", 5) != 0) { goto errexit; } } else if (strncmp(new_name, "/opt/", 5) == 0) { entry->opt_dir = 1; opt_dir = 1; // both path and absolute path are under /dev if (strncmp(fname, "/opt/", 5) != 0) { goto errexit; } } else if (strncmp(new_name, "/srv/", 5) == 0) { entry->srv_dir = 1; srv_dir = 1; // both path and absolute path are under /srv if (strncmp(fname, "/srv/", 5) != 0) { goto errexit; } } else { goto errexit; } // mark symbolic links if (is_link(new_name)) entry->link = new_name; else { free(new_name); new_name = NULL; } // change file name in entry->data if (strcmp(fname, entry->data + 10) != 0) { char *newdata; if (asprintf(&newdata, "whitelist %s", fname) == -1) errExit("asprintf"); entry->data = newdata; if (arg_debug || arg_debug_whitelists) printf("Replaced whitelist path: %s\n", entry->data); } free(fname); entry = entry->next; } // /home/user if (home_dir) { // keep a copy of real home dir in RUN_WHITELIST_HOME_USER_DIR mkdir_attr(RUN_WHITELIST_HOME_USER_DIR, 0755, getuid(), getgid()); if (mount(cfg.homedir, RUN_WHITELIST_HOME_USER_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind"); // mount a tmpfs and initialize /home/user fs_private(); } // /tmp mountpoint if (tmp_dir) { // keep a copy of real /tmp directory in mkdir_attr(RUN_WHITELIST_TMP_DIR, 1777, 0, 0); if (mount("/tmp", RUN_WHITELIST_TMP_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind"); // mount tmpfs on /tmp if (arg_debug || arg_debug_whitelists) printf("Mounting tmpfs on /tmp directory\n"); if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=1777,gid=0") < 0) errExit("mounting tmpfs on /tmp"); fs_logger("tmpfs /tmp"); } // /media mountpoint if (media_dir) { // some distros don't have a /media directory struct stat s; if (stat("/media", &s) == 0) { // keep a copy of real /media directory in RUN_WHITELIST_MEDIA_DIR mkdir_attr(RUN_WHITELIST_MEDIA_DIR, 0755, 0, 0); if (mount("/media", RUN_WHITELIST_MEDIA_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind"); // mount tmpfs on /media if (arg_debug || arg_debug_whitelists) printf("Mounting tmpfs on /media directory\n"); if (mount("tmpfs", "/media", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /media"); fs_logger("tmpfs /media"); } else media_dir = 0; } // /mnt mountpoint if (mnt_dir) { // check if /mnt directory exists struct stat s; if (stat("/mnt", &s) == 0) { // keep a copy of real /mnt directory in RUN_WHITELIST_MNT_DIR mkdir_attr(RUN_WHITELIST_MNT_DIR, 0755, 0, 0); if (mount("/mnt", RUN_WHITELIST_MNT_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind"); // mount tmpfs on /mnt if (arg_debug || arg_debug_whitelists) printf("Mounting tmpfs on /mnt directory\n"); if (mount("tmpfs", "/mnt", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /mnt"); fs_logger("tmpfs /mnt"); } else mnt_dir = 0; } // /var mountpoint if (var_dir) { // keep a copy of real /var directory in RUN_WHITELIST_VAR_DIR mkdir_attr(RUN_WHITELIST_VAR_DIR, 0755, 0, 0); if (mount("/var", RUN_WHITELIST_VAR_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind"); // mount tmpfs on /var if (arg_debug || arg_debug_whitelists) printf("Mounting tmpfs on /var directory\n"); if (mount("tmpfs", "/var", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /var"); fs_logger("tmpfs /var"); } // /dev mountpoint if (dev_dir) { // keep a copy of real /dev directory in RUN_WHITELIST_DEV_DIR mkdir_attr(RUN_WHITELIST_DEV_DIR, 0755, 0, 0); if (mount("/dev", RUN_WHITELIST_DEV_DIR, NULL, MS_BIND|MS_REC, "mode=755,gid=0") < 0) errExit("mount bind"); // mount tmpfs on /dev if (arg_debug || arg_debug_whitelists) printf("Mounting tmpfs on /dev directory\n"); if (mount("tmpfs", "/dev", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /dev"); fs_logger("tmpfs /dev"); } // /opt mountpoint if (opt_dir) { // keep a copy of real /opt directory in RUN_WHITELIST_OPT_DIR mkdir_attr(RUN_WHITELIST_OPT_DIR, 0755, 0, 0); if (mount("/opt", RUN_WHITELIST_OPT_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind"); // mount tmpfs on /opt if (arg_debug || arg_debug_whitelists) printf("Mounting tmpfs on /opt directory\n"); if (mount("tmpfs", "/opt", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /opt"); fs_logger("tmpfs /opt"); } // /srv mountpoint if (srv_dir) { // check if /srv directory exists struct stat s; if (stat("/srv", &s) == 0) { // keep a copy of real /srv directory in RUN_WHITELIST_SRV_DIR mkdir_attr(RUN_WHITELIST_SRV_DIR, 0755, 0, 0); if (mount("/srv", RUN_WHITELIST_SRV_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind"); // mount tmpfs on /srv if (arg_debug || arg_debug_whitelists) printf("Mounting tmpfs on /srv directory\n"); if (mount("tmpfs", "/srv", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /srv"); fs_logger("tmpfs /srv"); } else srv_dir = 0; } // go through profile rules again, and interpret whitelist commands entry = cfg.profile; while (entry) { // handle only whitelist commands if (strncmp(entry->data, "whitelist ", 10)) { entry = entry->next; continue; } //printf("here %d#%s#\n", __LINE__, entry->data); // whitelist the real file if (strcmp(entry->data, "whitelist /run") == 0 && (strcmp(entry->link, "/var/run") == 0 || strcmp(entry->link, "/var/lock") == 0)) { int rv = symlink(entry->data + 10, entry->link); if (rv) fprintf(stderr, "Warning cannot create symbolic link %s\n", entry->link); else if (arg_debug || arg_debug_whitelists) printf("Created symbolic link %s -> %s\n", entry->link, entry->data + 10); } else { whitelist_path(entry); // create the link if any if (entry->link) { // if the link is already there, do not bother struct stat s; if (stat(entry->link, &s) != 0) { // create the path if necessary mkpath(entry->link, s.st_mode); int rv = symlink(entry->data + 10, entry->link); if (rv) fprintf(stderr, "Warning cannot create symbolic link %s\n", entry->link); else if (arg_debug || arg_debug_whitelists) printf("Created symbolic link %s -> %s\n", entry->link, entry->data + 10); } } } entry = entry->next; } // mask the real home directory, currently mounted on RUN_WHITELIST_HOME_DIR if (home_dir) { if (mount("tmpfs", RUN_WHITELIST_HOME_USER_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mount tmpfs"); fs_logger2("tmpfs", RUN_WHITELIST_HOME_USER_DIR); } // mask the real /tmp directory, currently mounted on RUN_WHITELIST_TMP_DIR if (tmp_dir) { if (mount("tmpfs", RUN_WHITELIST_TMP_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mount tmpfs"); fs_logger2("tmpfs", RUN_WHITELIST_TMP_DIR); } // mask the real /var directory, currently mounted on RUN_WHITELIST_VAR_DIR if (var_dir) { if (mount("tmpfs", RUN_WHITELIST_VAR_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mount tmpfs"); fs_logger2("tmpfs", RUN_WHITELIST_VAR_DIR); } // mask the real /opt directory, currently mounted on RUN_WHITELIST_OPT_DIR if (opt_dir) { if (mount("tmpfs", RUN_WHITELIST_OPT_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mount tmpfs"); fs_logger2("tmpfs", RUN_WHITELIST_OPT_DIR); } // mask the real /dev directory, currently mounted on RUN_WHITELIST_DEV_DIR if (dev_dir) { if (mount("tmpfs", RUN_WHITELIST_DEV_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mount tmpfs"); fs_logger2("tmpfs", RUN_WHITELIST_DEV_DIR); } // mask the real /media directory, currently mounted on RUN_WHITELIST_MEDIA_DIR if (media_dir) { if (mount("tmpfs", RUN_WHITELIST_MEDIA_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mount tmpfs"); fs_logger2("tmpfs", RUN_WHITELIST_MEDIA_DIR); } // mask the real /mnt directory, currently mounted on RUN_WHITELIST_MNT_DIR if (mnt_dir) { if (mount("tmpfs", RUN_WHITELIST_MNT_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mount tmpfs"); fs_logger2("tmpfs", RUN_WHITELIST_MNT_DIR); } // mask the real /srv directory, currently mounted on RUN_WHITELIST_SRV_DIR if (srv_dir) { if (mount("tmpfs", RUN_WHITELIST_SRV_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mount tmpfs"); fs_logger2("tmpfs", RUN_WHITELIST_SRV_DIR); } if (new_name) free(new_name); return; errexit: fprintf(stderr, "Error: invalid whitelist path %s\n", new_name); exit(1); }