Exemple #1
0
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");
	}
}
Exemple #2
0
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);
}
Exemple #3
0
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");
		}
	}
}
Exemple #4
0
// 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();
}
Exemple #5
0
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;
	}
}
Exemple #6
0
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;
	}
}
Exemple #7
0
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++;
	}
}
Exemple #8
0
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
}
Exemple #9
0
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);
}
Exemple #10
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");
	}
}
Exemple #11
0
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");
}
Exemple #12
0
// 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);
}