static void create_char_dev(const char *path, mode_t mode, int major, int minor) { dev_t dev = makedev(major, minor); if (mknod(path, S_IFCHR | mode, dev) == -1) goto errexit; if (chmod(path, mode) < 0) goto errexit; ASSERT_PERMS(path, 0, 0, mode); return; errexit: fprintf(stderr, "Error: cannot create %s device\n", path); exit(1); }
void create_empty_dir_as_root(const char *dir, mode_t mode) { assert(dir); mode &= 07777; struct stat s; if (stat(dir, &s)) { if (arg_debug) printf("Creating empty %s directory\n", dir); /* coverity[toctou] */ if (mkdir(dir, mode) == -1) errExit("mkdir"); if (set_perms(dir, 0, 0, mode)) errExit("set_perms"); ASSERT_PERMS(dir, 0, 0, mode); } }
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) { 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) { if (mkdir(dev[i].dev_fname, 0755) == -1) errExit("mkdir"); if (chmod(dev[i].dev_fname, 0755) == -1) errExit("chmod"); ASSERT_PERMS(dev[i].dev_fname, 0, 0, 0755); } else { struct stat s; if (stat(dev[i].run_fname, &s) == -1) { if (arg_debug) printf("Warning: 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 fs_dev_shm(void) { uid_t uid = getuid(); // set a new shm only if we started as root if (uid) return; if (is_dir("/dev/shm")) { if (arg_debug) printf("Mounting tmpfs on /dev/shm\n"); if (mount("tmpfs", "/dev/shm", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=1777,gid=0") < 0) errExit("mounting /dev/shm"); fs_logger("tmpfs /dev/shm"); } else { char *lnk = realpath("/dev/shm", NULL); if (lnk) { if (!is_dir(lnk)) { // create directory if (mkdir(lnk, 01777)) errExit("mkdir"); // mkdir sets only the file permission bits if (chmod(lnk, 01777)) errExit("chmod"); ASSERT_PERMS(lnk, 0, 0, 01777); } if (arg_debug) printf("Mounting tmpfs on %s on behalf of /dev/shm\n", lnk); if (mount("tmpfs", lnk, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=1777,gid=0") < 0) errExit("mounting /var/tmp"); fs_logger2("tmpfs", lnk); free(lnk); } else { fprintf(stderr, "Warning: /dev/shm not mounted\n"); dbg_test_dir("/dev/shm"); } } }
void mkdir_attr(const char *fname, mode_t mode, uid_t uid, gid_t gid) { assert(fname); mode &= 07777; #if 0 printf("fname %s, uid %d, gid %d, mode %x - ", fname, uid, gid, (unsigned) mode); if (S_ISLNK(mode)) printf("l"); else if (S_ISDIR(mode)) printf("d"); else if (S_ISCHR(mode)) printf("c"); else if (S_ISBLK(mode)) printf("b"); else if (S_ISSOCK(mode)) printf("s"); else printf("-"); printf( (mode & S_IRUSR) ? "r" : "-"); printf( (mode & S_IWUSR) ? "w" : "-"); printf( (mode & S_IXUSR) ? "x" : "-"); printf( (mode & S_IRGRP) ? "r" : "-"); printf( (mode & S_IWGRP) ? "w" : "-"); printf( (mode & S_IXGRP) ? "x" : "-"); printf( (mode & S_IROTH) ? "r" : "-"); printf( (mode & S_IWOTH) ? "w" : "-"); printf( (mode & S_IXOTH) ? "x" : "-"); printf("\n"); #endif if (mkdir(fname, mode) == -1 || chmod(fname, mode) == -1 || chown(fname, uid, gid)) { fprintf(stderr, "Error: failed to create %s directory\n", fname); errExit("mkdir/chmod"); } ASSERT_PERMS(fname, uid, gid, mode); }
void fs_private_dev(void){ // install a new /dev directory if (arg_debug) printf("Mounting tmpfs on /dev\n"); // create DRI_DIR fs_build_mnt_dir(); // keep a copy of dev directory if (mkdir(RUN_DEV_DIR, 0755) == -1) errExit("mkdir"); if (chmod(RUN_DEV_DIR, 0755) == -1) errExit("chmod"); ASSERT_PERMS(RUN_DEV_DIR, 0, 0, 0755); if (mount("/dev", RUN_DEV_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mounting /dev/dri"); // 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"); 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"); } } if (mount(RUN_RO_DIR, RUN_DEV_DIR, "none", MS_BIND, "mode=400,gid=0") < 0) errExit("disable /dev/snd"); // create /dev/shm if (arg_debug) printf("Create /dev/shm directory\n"); if (mkdir("/dev/shm", 01777) == -1) errExit("mkdir"); // mkdir sets only the file permission bits if (chmod("/dev/shm", 01777) < 0) errExit("chmod"); ASSERT_PERMS("/dev/shm", 0, 0, 01777); fs_logger("mkdir /dev/shm"); // create 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 if (mkdir("/dev/pts", 0755) == -1) errExit("mkdir"); if (chmod("/dev/pts", 0755) == -1) errExit("chmod"); ASSERT_PERMS("/dev/pts", 0, 0, 0755); fs_logger("mkdir /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_tty_gid(); 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"); #if 0 // stdin, stdout, stderr 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 }
void fs_private_etc_list(void) { char *private_list = cfg.etc_private_keep; assert(private_list); struct stat s; if (stat("/etc", &s) == -1) { fprintf(stderr, "Error: cannot find user /etc directory\n"); exit(1); } // create /tmp/firejail/mnt/etc directory fs_build_mnt_dir(); if (mkdir(RUN_ETC_DIR, 0755) == -1) errExit("mkdir"); if (chmod(RUN_ETC_DIR, 0755) == -1) errExit("chmod"); ASSERT_PERMS(RUN_ETC_DIR, 0, 0, 0755); fs_logger("tmpfs /etc"); fs_logger_print(); // save the current log // copy the list of files in the new etc directory // using a new child process with root privileges if (*private_list != '\0') { pid_t child = fork(); if (child < 0) errExit("fork"); if (child == 0) { if (arg_debug) printf("Copying files in the new etc directory:\n"); // elevate privileges - files in the new /etc directory belong to root if (setreuid(0, 0) < 0) errExit("setreuid"); if (setregid(0, 0) < 0) errExit("setregid"); // copy the list of files in the new home directory char *dlist = strdup(private_list); if (!dlist) errExit("strdup"); char *ptr = strtok(dlist, ","); duplicate(ptr); while ((ptr = strtok(NULL, ",")) != NULL) duplicate(ptr); free(dlist); fs_logger_print(); exit(0); } // wait for the child to finish waitpid(child, NULL, 0); } if (arg_debug) printf("Mount-bind %s on top of /etc\n", RUN_ETC_DIR); if (mount(RUN_ETC_DIR, "/etc", NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind"); fs_logger("mount /etc"); }