Пример #1
0
static int store_xauthority(void) {
	// put a copy of .Xauthority in XAUTHORITY_FILE
	fs_build_mnt_dir();

	char *src;
	char *dest = RUN_XAUTHORITY_FILE;
	if (asprintf(&src, "%s/.Xauthority", cfg.homedir) == -1)
		errExit("asprintf");
	
	struct stat s;
	if (stat(src, &s) == 0) {
		if (is_link(src)) {
			fprintf(stderr, "Error: invalid .Xauthority file\n");
			exit(1);
		}
			
		int rv = copy_file(src, dest);
		if (rv) {
			fprintf(stderr, "Warning: cannot transfer .Xauthority in private home directory\n");
			return 0;
		}
		return 1; // file copied
	}
	
	return 0;
}
Пример #2
0
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();
	int rv = mkdir(RUN_ETC_DIR, 0755);
	if (rv == -1)
		errExit("mkdir");
	if (chown(RUN_ETC_DIR, 0, 0) < 0)
		errExit("chown");
	if (chmod(RUN_ETC_DIR, 0755) < 0)
		errExit("chmod");
	
	// copy the list of files in the new etc directory
	// using a new child process without root privileges
	fs_logger_print();	// save the current log
	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");
}
Пример #3
0
static int store_asoundrc(void) {
	// put a copy of .Xauthority in XAUTHORITY_FILE
	fs_build_mnt_dir();

	char *src;
	char *dest = RUN_ASOUNDRC_FILE;
	if (asprintf(&src, "%s/.asoundrc", cfg.homedir) == -1)
		errExit("asprintf");
	
	struct stat s;
	if (stat(src, &s) == 0) {
		if (is_link(src)) {
			// make sure the real path of the file is inside the home directory
			char* rp = realpath(src, NULL);
			if (!rp) {
				fprintf(stderr, "Error: Cannot access %s\n", src);
				exit(1);
			}
			if (strncmp(rp, cfg.homedir, strlen(cfg.homedir)) != 0) {
				fprintf(stderr, "Error: .asoundrc is a symbolic link pointing to a file outside home directory\n");
				exit(1);
			}
			free(rp);
		}

		int rv = copy_file(src, dest);
		if (rv) {
			fprintf(stderr, "Warning: cannot transfer .asoundrc in private home directory\n");
			return 0;
		}
		return 1; // file copied
	}
	
	return 0;
}
Пример #4
0
// grab a copy of cp command
void fs_build_cp_command(void) {
	struct stat s;
	fs_build_mnt_dir();
	if (stat(RUN_CP_COMMAND, &s)) {
		char* fname = realpath("/bin/cp", NULL);
		if (fname == NULL) {
			fprintf(stderr, "Error: /bin/cp not found\n");
			exit(1);
		}
		if (stat(fname, &s)) {
			fprintf(stderr, "Error: /bin/cp not found\n");
			exit(1);
		}
		if (is_link(fname)) {
			fprintf(stderr, "Error: invalid /bin/cp file\n");
			exit(1);
		}
		int rv = copy_file(fname, RUN_CP_COMMAND);
		if (rv) {
			fprintf(stderr, "Error: cannot access /bin/cp\n");
			exit(1);
		}
		/* coverity[toctou] */
		if (chown(RUN_CP_COMMAND, 0, 0))
			errExit("chown");
		if (chmod(RUN_CP_COMMAND, 0755))
			errExit("chmod");
			
		free(fname);
	}
}
Пример #5
0
void fs_trace(void) {
	// create /tmp/firejail/mnt directory
	fs_build_mnt_dir();
	
	// create the new ld.so.preload file and mount-bind it
	if (arg_debug)
		printf("Create the new ld.so.preload file\n");
	char *preload;
	if (asprintf(&preload, "%s/ld.so.preload", MNT_DIR) == -1)
		errExit("asprintf");
	FILE *fp = fopen(preload, "w");
	if (!fp)
		errExit("fopen");
	fprintf(fp, "%s/lib/firejail/libtrace.so\n", PREFIX);
	fclose(fp);
	if (chown(preload, 0, 0) < 0)
		errExit("chown");
	if (chmod(preload, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH ) < 0)
		errExit("chmod");
	
	// mount the new preload file
	if (arg_debug)
		printf("Mount the new ld.so.preload file\n");
	if (mount(preload, "/etc/ld.so.preload", NULL, MS_BIND|MS_REC, NULL) < 0)
		errExit("mount bind ls.so.preload");
}
Пример #6
0
static void sanitize_home(void) {
	assert(getuid() != 0);	// this code works only for regular users
	
	if (arg_debug)
		printf("Cleaning /home directory\n");
	
	struct stat s;
	if (stat(cfg.homedir, &s) == -1) {
		// cannot find home directory, just return
		fprintf(stderr, "Warning: cannot find home directory\n");
		return;
	}
	
	fs_build_mnt_dir();
	if (mkdir(RUN_WHITELIST_HOME_DIR, 0755) == -1)
		errExit("mkdir");

	// keep a copy of the user home directory
	if (mount(cfg.homedir, RUN_WHITELIST_HOME_DIR, NULL, MS_BIND|MS_REC, NULL) < 0)
		errExit("mount bind");

	// mount tmpfs in the new home
	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");

	// create user home directory
	if (mkdir(cfg.homedir, 0755) == -1) {
		if (mkpath_as_root(cfg.homedir))
			errExit("mkpath");
		if (mkdir(cfg.homedir, 0755) == -1)
			errExit("mkdir");
	}
	fs_logger2("mkdir", cfg.homedir);
	
	// set mode and ownership
	if (chown(cfg.homedir, s.st_uid, s.st_gid) == -1)
		errExit("chown");
	if (chmod(cfg.homedir, s.st_mode) == -1)
		errExit("chmod");

	// mount user home directory
	if (mount(RUN_WHITELIST_HOME_DIR, cfg.homedir, NULL, MS_BIND|MS_REC, NULL) < 0)
		errExit("mount bind");

	// mask home dir under /run
	if (mount("tmpfs", RUN_WHITELIST_HOME_DIR, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC,  "mode=755,gid=0") < 0)
		errExit("mount tmpfs");
	fs_logger2("tmpfs", RUN_WHITELIST_HOME_DIR);
	if (!arg_private)
		fs_logger2("whitelist", cfg.homedir);
	
}
Пример #7
0
void fs_var_utmp(void) {
	struct stat s;

	// extract utmp group id
	gid_t utmp_group = 0;
	if (stat("/var/run/utmp", &s) == 0)
		utmp_group = s.st_gid;
	else {
		fprintf(stderr, "Warning: cannot find /var/run/utmp\n");
		return;
	}

	// create /tmp/firejail/mnt directory
	fs_build_mnt_dir();
	
	// create a new utmp file
	if (arg_debug)
		printf("Create the new utmp file\n");
	char *utmp;
	if (asprintf(&utmp, "%s/utmp", MNT_DIR) == -1)
		errExit("asprintf");
	FILE *fp = fopen(utmp, "w");
	if (!fp)
		errExit("fopen");
		
	// read current utmp
	struct utmp *u;
	struct utmp u_boot;
	setutent();
	while ((u = getutent()) != NULL) {
		if (u->ut_type == BOOT_TIME) {
			memcpy(&u_boot, u, sizeof(u_boot));
			u_boot.ut_tv.tv_sec = (unsigned) time(NULL);
		}
	}
	endutent();
			
	// save new utmp file
	fwrite(&u_boot, sizeof(u_boot), 1, fp);
	fclose(fp);
	if (chown(utmp, 0, utmp_group) < 0)
		errExit("chown");
	if (chmod(utmp, S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH ) < 0)
		errExit("chmod");
	
	// mount the new utmp file
	if (arg_debug)
		printf("Mount the new utmp file\n");
	if (mount(utmp, "/var/run/utmp", NULL, MS_BIND|MS_REC, NULL) < 0)
		errExit("mount bind utmp");
}
Пример #8
0
void fs_mount_xauthority(void) {
	// put a copy of .Xauthority in MNT_DIR
	fs_build_mnt_dir();

	char *src;
	char *dest;
	if (asprintf(&dest, "%s/.Xauthority", cfg.homedir) == -1)
		errExit("asprintf");
	if (asprintf(&src, "%s/.Xauthority", MNT_DIR) == -1)
		errExit("asprintf");
		
	// bind-mount the file on top of /etc/hostname
	if (mount(src, "dest", NULL, MS_BIND|MS_REC, NULL) < 0)
		errExit("mount bind ~/.Xauthority");
}
Пример #9
0
// disable shm in pulseaudio
void pulseaudio_init(void) {
	struct stat s;
	
	// do we have pulseaudio in the system?
	if (stat("/etc/pulse/client.conf", &s) == -1)
		return;

	 
 	// create the new user pulseaudio directory
	 fs_build_mnt_dir();
	char *pulsedir;
	if (asprintf(&pulsedir, "%s/pulse", MNT_DIR) == -1)
		errExit("asprintf");
	int rv = mkdir(pulsedir, S_IRWXU | S_IRWXG | S_IRWXO);
	if (rv == -1)
		errExit("mkdir");
	if (chown(pulsedir, getuid(), getgid()) < 0)
		errExit("chown");
	if (chmod(pulsedir, 0700) < 0)
		errExit("chmod");

	// create the new client.conf file
	char *pulsecfg = NULL;
	if (asprintf(&pulsecfg, "%s/client.conf", pulsedir) == -1)
		errExit("asprintf");
	if (copy_file("/etc/pulse/client.conf", pulsecfg))
		errExit("copy_file");
	FILE *fp = fopen(pulsecfg, "a+");
	if (!fp)
		errExit("fopen");
	fprintf(fp, "%s", "\nenable-shm = no\n");
	fclose(fp);
	if (chmod(pulsecfg, 0644) == -1)
		errExit("chmod");
	if (chown(pulsecfg, getuid(), getgid()) == -1)
		errExit("chown");


	// set environment
	if (setenv("PULSE_CLIENTCONFIG", pulsecfg, 1) < 0)
		errExit("setenv");
	

	free(pulsecfg);
	free(pulsedir);		
}
Пример #10
0
void protocol_filter_save(void) {
	// save protocol filter configuration in PROTOCOL_CFG
	fs_build_mnt_dir();

	FILE *fp = fopen(RUN_PROTOCOL_CFG, "w");
	if (!fp)
		errExit("fopen");
	fprintf(fp, "%s\n", cfg.protocol);
	fclose(fp);

	if (chmod(RUN_PROTOCOL_CFG, 0600) < 0)
		errExit("chmod");

	if (chown(RUN_PROTOCOL_CFG, 0, 0) < 0)
		errExit("chown");

}
Пример #11
0
// save seccomp filter in  /tmp/firejail/mnt/seccomp
static void write_seccomp_file(void) {
	fs_build_mnt_dir();
	assert(sfilter);

	int fd = open(RUN_SECCOMP_CFG, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
	if (fd == -1)
		errExit("open");

	if (arg_debug)
		printf("Save seccomp filter, size %u bytes\n", (unsigned) (sfilter_index * sizeof(struct sock_filter)));
	errno = 0;
	ssize_t sz = write(fd, sfilter, sfilter_index * sizeof(struct sock_filter));
	if (sz != (ssize_t)(sfilter_index * sizeof(struct sock_filter))) {
		fprintf(stderr, "Error: cannot save seccomp filter\n");
		exit(1);
	}
	close(fd);
	if (chown(RUN_SECCOMP_CFG, 0, 0) < 0)
		errExit("chown");
}
Пример #12
0
static int store_xauthority(void) {
	// put a copy of .Xauthority in MNT_DIR
	fs_build_mnt_dir();

	char *src;
	char *dest;
	if (asprintf(&src, "%s/.Xauthority", cfg.homedir) == -1)
		errExit("asprintf");
	if (asprintf(&dest, "%s/.Xauthority", MNT_DIR) == -1)
		errExit("asprintf");
	
	struct stat s;
	if (stat(src, &s) == 0) {	
		int rv = copy_file(src, dest);
		if (rv) {
			exechelp_logerrv("firejail", FIREJAIL_WARNING, "Error: cannot transfer .Xauthority in private home directory\n");
			return 0;
		}
		return 1; // file copied
	}
	
	return 0;
}
Пример #13
0
static int store_xauthority(void) {
	// put a copy of .Xauthority in MNT_DIR
	fs_build_mnt_dir();

	char *src;
	char *dest;
	if (asprintf(&src, "%s/.Xauthority", cfg.homedir) == -1)
		errExit("asprintf");
	if (asprintf(&dest, "%s/.Xauthority", MNT_DIR) == -1)
		errExit("asprintf");
	
	struct stat s;
	if (stat(src, &s) == 0) {	
		int rv = copy_file(src, dest);
		if (rv) {
			fprintf(stderr, "Warning: cannot transfer .Xauthority in private home directory\n");
			return 0;
		}
		return 1; // file copied
	}
	
	return 0;
}
Пример #14
0
static void copy_xauthority(void) {
	// put a copy of .Xauthority in MNT_DIR
	fs_build_mnt_dir();

	char *src;
	char *dest;
	if (asprintf(&dest, "%s/.Xauthority", cfg.homedir) == -1)
		errExit("asprintf");
	if (asprintf(&src, "%s/.Xauthority", MNT_DIR) == -1)
		errExit("asprintf");
	int rv = copy_file(src, dest);
	if (rv)
		exechelp_logerrv("firejail", FIREJAIL_WARNING, "Error: cannot transfer .Xauthority in private home directory\n");

	// set permissions and ownership
	if (chown(dest, getuid(), getgid()) < 0)
		errExit("chown");
	if (chmod(dest, S_IRUSR | S_IWUSR) < 0)
		errExit("chmod");

	// delete the temporary file
	unlink(src);
}
Пример #15
0
void fs_copy_xauthority(void) {
	// put a copy of .Xauthority in MNT_DIR
	fs_build_mnt_dir();

	char *src;
	char *dest;
	if (asprintf(&dest, "%s/.Xauthority", cfg.homedir) == -1)
		errExit("asprintf");
	if (asprintf(&src, "%s/.Xauthority", MNT_DIR) == -1)
		errExit("asprintf");
	int rv = copy_file(src, dest);
	if (rv)
		fprintf(stderr, "Warning: cannot transfer .Xauthority in private home directory\n");

	// set permissions and ownership
	if (chown(dest, getuid(), getgid()) < 0)
		errExit("chown");
	if (chmod(dest, S_IRUSR | S_IWUSR) < 0)
		errExit("chmod");

	// delete the temporary file
	unlink(src);
}
Пример #16
0
// save seccomp filter in  /tmp/firejail/mnt/seccomp
static void write_seccomp_file(void) {
	fs_build_mnt_dir();
	assert(sfilter);

	char *fname;
	if (asprintf(&fname, "%s/seccomp", MNT_DIR) == -1)
		errExit("asprintf");
	int fd = open(fname, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
	if (fd == -1)
		errExit("open");

	if (arg_debug)
		printf("Save seccomp filter, size %lu bytes\n", sfilter_index * sizeof(struct sock_filter));
	errno = 0;
	ssize_t sz = write(fd, sfilter, sfilter_index * sizeof(struct sock_filter));
	if (sz != (ssize_t)(sfilter_index * sizeof(struct sock_filter))) {
		exechelp_logerrv("firejail", FIREJAIL_ERROR, "Error: cannot save seccomp filter\n");
		exit(1);
	}
	close(fd);
	if (chown(fname, 0, 0) < 0)
		errExit("chown");
	free(fname);
}
Пример #17
0
// grab a copy of cp command
void fs_build_cp_command(void) {
	struct stat s;
	fs_build_mnt_dir();
	if (stat(CP_COMMAND, &s)) {
		char* fname = realpath("/bin/cp", NULL);
		if (fname == NULL) {
			fprintf(stderr, "Error: /bin/cp not found\n");
			exit(1);
		}
		if (stat(fname, &s)) {
			fprintf(stderr, "Error: /bin/cp not found\n");
			exit(1);
		}
		int rv = copy_file(fname, CP_COMMAND);
		if (rv) {
			fprintf(stderr, "Error: cannot access /bin/cp\n");
			exit(1);
		}
		if (chmod(CP_COMMAND, 0755))
			errExit("chmod");
			
		free(fname);
	}
}
Пример #18
0
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);
}
Пример #19
0
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);
}
Пример #20
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 var_dir = 0;		// /var directory flag
	int dev_dir = 0;		// /dev directory flag
	int opt_dir = 0;		// /opt 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
		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);

		// 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';
			continue;
		}
		
		// valid path referenced to filesystem root
		if (*new_name != '/') {
			if (arg_debug)
				fprintf(stderr, "Debug %d: \n", __LINE__);
			goto errexit;
		}

		// check for supported directories
		if (strncmp(new_name, cfg.homedir, strlen(cfg.homedir)) == 0) {
			// whitelisting home directory is disabled if --private or --private-home 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;
			// both path and absolute path are under /home
			if (strncmp(fname, cfg.homedir, strlen(cfg.homedir)) != 0) {
				if (arg_debug)
					fprintf(stderr, "Debug %d: fname #%s#, cfg.homedir #%s#\n",
						__LINE__, fname, cfg.homedir);
				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) {
				if (arg_debug)
					fprintf(stderr, "Debug %d: fname #%s#\n", __LINE__, fname);
				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) {
				if (arg_debug)
					fprintf(stderr, "Debug %d: fname #%s#\n", __LINE__, fname);
				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
			if (strncmp(fname, "/var/", 5) != 0) {
				if (arg_debug)
					fprintf(stderr, "Debug %d: fname #%s#\n", __LINE__, fname);
				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) {
				if (arg_debug)
					fprintf(stderr, "Debug %d: fname #%s#\n", __LINE__, fname);
				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) {
				if (arg_debug)
					fprintf(stderr, "Debug %d: fname #%s#\n", __LINE__, fname);
				goto errexit;
			}
		}
		else {
			if (arg_debug)
				fprintf(stderr, "Debug %d: \n", __LINE__);
			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;
	}
		
	// create mount points
	fs_build_mnt_dir();
	

	// /home/user
	if (home_dir) {
		// keep a copy of real home dir in RUN_WHITELIST_HOME_USER_DIR
		int rv = mkdir(RUN_WHITELIST_HOME_USER_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
		if (rv == -1)
			errExit("mkdir");
		if (chown(RUN_WHITELIST_HOME_USER_DIR, getuid(), getgid()) < 0)
			errExit("chown");
		if (chmod(RUN_WHITELIST_HOME_USER_DIR, 0755) < 0)
			errExit("chmod");
	
		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 WHITELIST_TMP_DIR
		int rv = mkdir(RUN_WHITELIST_TMP_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
		if (rv == -1)
			errExit("mkdir");
		if (chown(RUN_WHITELIST_TMP_DIR, 0, 0) < 0)
			errExit("chown");
		if (chmod(RUN_WHITELIST_TMP_DIR, 0777) < 0)
			errExit("chmod");
	
		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=777,gid=0") < 0)
			errExit("mounting tmpfs on /tmp");
		fs_logger("mount tmpfs on /tmp");
	}
	
	// /media mountpoint
	if (media_dir) {
		// keep a copy of real /media directory in RUN_WHITELIST_MEDIA_DIR
		int rv = mkdir(RUN_WHITELIST_MEDIA_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
		if (rv == -1)
			errExit("mkdir");
		if (chown(RUN_WHITELIST_MEDIA_DIR, 0, 0) < 0)
			errExit("chown");
		if (chmod(RUN_WHITELIST_MEDIA_DIR, 0755) < 0)
			errExit("chmod");
	
		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("mount tmpfs on /media");
	}

	// /var mountpoint
	if (var_dir) {
		// keep a copy of real /var directory in RUN_WHITELIST_VAR_DIR
		int rv = mkdir(RUN_WHITELIST_VAR_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
		if (rv == -1)
			errExit("mkdir");
		if (chown(RUN_WHITELIST_VAR_DIR, 0, 0) < 0)
			errExit("chown");
		if (chmod(RUN_WHITELIST_VAR_DIR, 0755) < 0)
			errExit("chmod");
	
		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("mount tmpfs on /var");
	}

	// /dev mountpoint
	if (dev_dir) {
		// keep a copy of real /dev directory in RUN_WHITELIST_DEV_DIR
		int rv = mkdir(RUN_WHITELIST_DEV_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
		if (rv == -1)
			errExit("mkdir");
		if (chown(RUN_WHITELIST_DEV_DIR, 0, 0) < 0)
			errExit("chown");
		if (chmod(RUN_WHITELIST_DEV_DIR, 0755) < 0)
			errExit("chmod");
	
		if (mount("/dev", RUN_WHITELIST_DEV_DIR, NULL, MS_BIND|MS_REC, NULL) < 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("mount tmpfs on /dev");
	}

	// /opt mountpoint
	if (opt_dir) {
		// keep a copy of real /opt directory in RUN_WHITELIST_DEV_DIR
		int rv = mkdir(RUN_WHITELIST_OPT_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
		if (rv == -1)
			errExit("mkdir");
		if (chown(RUN_WHITELIST_OPT_DIR, 0, 0) < 0)
			errExit("chown");
		if (chmod(RUN_WHITELIST_OPT_DIR, 0755) < 0)
			errExit("chmod");
	
		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("mount tmpfs on /opt");
	}

	// 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
		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");
	}
	
	// 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");
	}

	if (new_name)
		free(new_name);
		
	return;

errexit:
	fprintf(stderr, "Error: invalid whitelist path %s\n", new_name);
	exit(1);
}
Пример #21
0
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
}
Пример #22
0
void fs_private_bin_list(void) {
	char *private_list = cfg.bin_private_keep;
	assert(private_list);
	
	// create /tmp/firejail/mnt/bin directory
	fs_build_mnt_dir();
	int rv = mkdir(RUN_BIN_DIR, 0755);
	if (rv == -1)
		errExit("mkdir");
	if (chown(RUN_BIN_DIR, 0, 0) < 0)
		errExit("chown");
	if (chmod(RUN_BIN_DIR, 0755) < 0)
		errExit("chmod");
	
	
	// copy the list of files in the new etc directory
	// using a new child process without root privileges
	fs_logger_print();	// save the current log
	pid_t child = fork();
	if (child < 0)
		errExit("fork");
	if (child == 0) {
		if (arg_debug)
			printf("Copying files in the new home:\n");

		// elevate privileges - files in the new /bin 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);

	// mount-bind
	int i = 0;
	while (paths[i]) {
		struct stat s;
		if (stat(paths[i], &s) == 0) {
			if (arg_debug)
				printf("Mount-bind %s on top of %s\n", RUN_BIN_DIR, paths[i]);
			if (mount(RUN_BIN_DIR, paths[i], NULL, MS_BIND|MS_REC, NULL) < 0)
				errExit("mount bind");
			fs_logger2("tmpfs", paths[i]);
			fs_logger2("mount", paths[i]);
		}
		i++;
	}
	
	// log cloned files
	char *dlist = strdup(private_list);
	if (!dlist)
		errExit("strdup");
	
	
	char *ptr = strtok(dlist, ",");
	while (ptr) {
		i = 0;
		while (paths[i]) {
			struct stat s;
			if (stat(paths[i], &s) == 0) {
				char *fname;
				if (asprintf(&fname, "%s/%s", paths[i], ptr) == -1)
					errExit("asprintf");
				fs_logger2("clone", fname);
				free(fname);
			}
			i++;
		}
		ptr = strtok(NULL, ",");
	}
	free(dlist);
}
Пример #23
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 var_dir = 0;		// /var directory flag
    int dev_dir = 0;		// /dev 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;
        }

        // replace ~/ or ${HOME} into /home/username
        new_name = expand_home(entry->data + 10, cfg.homedir);
        assert(new_name);

        // 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)
                printf("Removed whitelist path: %s\n", entry->data);
            *entry->data = '\0';
            continue;
        }

        // valid path referenced to filesystem root
        if (*new_name != '/')
            goto errexit;

        // check for supported directories
        if (strncmp(new_name, cfg.homedir, strlen(cfg.homedir)) == 0) {
            entry->home_dir = 1;
            home_dir = 1;
            // both path and absolute path are under /home
            if (strncmp(fname, cfg.homedir, strlen(cfg.homedir)) != 0)
                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, "/var/", 5) == 0) {
            entry->var_dir = 1;
            var_dir = 1;
            // both path and absolute path are under /var
            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
            goto errexit;

        // mark symbolic links
        if (is_link(new_name))
            entry->link = new_name;
        else
            free(new_name);

        // 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)
                printf("Replaced whitelist path: %s\n", entry->data);
        }
        free(fname);
        entry = entry->next;
    }

    // create mount points
    fs_build_mnt_dir();

    // /home/user
    if (home_dir) {
        // keep a copy of real home dir in WHITELIST_HOME_DIR
        int rv = mkdir(WHITELIST_HOME_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
        if (rv == -1)
            errExit("mkdir");
        if (chown(WHITELIST_HOME_DIR, getuid(), getgid()) < 0)
            errExit("chown");
        if (chmod(WHITELIST_HOME_DIR, 0755) < 0)
            errExit("chmod");

        if (mount(cfg.homedir, WHITELIST_HOME_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 WHITELIST_TMP_DIR
        int rv = mkdir(WHITELIST_TMP_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
        if (rv == -1)
            errExit("mkdir");
        if (chown(WHITELIST_TMP_DIR, 0, 0) < 0)
            errExit("chown");
        if (chmod(WHITELIST_TMP_DIR, 0777) < 0)
            errExit("chmod");

        if (mount("/tmp", WHITELIST_TMP_DIR, NULL, MS_BIND|MS_REC, NULL) < 0)
            errExit("mount bind");

        // mount tmpfs on /tmp
        if (arg_debug)
            printf("Mounting tmpfs on /tmp directory\n");
        if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC,  "mode=777,gid=0") < 0)
            errExit("mounting tmpfs on /tmp");
    }

    // /media mountpoint
    if (media_dir) {
        // keep a copy of real /media directory in WHITELIST_MEDIA_DIR
        int rv = mkdir(WHITELIST_MEDIA_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
        if (rv == -1)
            errExit("mkdir");
        if (chown(WHITELIST_MEDIA_DIR, 0, 0) < 0)
            errExit("chown");
        if (chmod(WHITELIST_MEDIA_DIR, 0755) < 0)
            errExit("chmod");

        if (mount("/media", WHITELIST_MEDIA_DIR, NULL, MS_BIND|MS_REC, NULL) < 0)
            errExit("mount bind");

        // mount tmpfs on /media
        if (arg_debug)
            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");
    }

    // /media mountpoint
    if (var_dir) {
        // keep a copy of real /var directory in WHITELIST_VAR_DIR
        int rv = mkdir(WHITELIST_VAR_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
        if (rv == -1)
            errExit("mkdir");
        if (chown(WHITELIST_VAR_DIR, 0, 0) < 0)
            errExit("chown");
        if (chmod(WHITELIST_VAR_DIR, 0755) < 0)
            errExit("chmod");

        if (mount("/var", WHITELIST_VAR_DIR, NULL, MS_BIND|MS_REC, NULL) < 0)
            errExit("mount bind");

        // mount tmpfs on /var
        if (arg_debug)
            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");
    }

    // /dev mountpoint
    if (dev_dir) {
        // keep a copy of real /dev directory in WHITELIST_DEV_DIR
        int rv = mkdir(WHITELIST_DEV_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
        if (rv == -1)
            errExit("mkdir");
        if (chown(WHITELIST_DEV_DIR, 0, 0) < 0)
            errExit("chown");
        if (chmod(WHITELIST_DEV_DIR, 0755) < 0)
            errExit("chmod");

        if (mount("/dev", WHITELIST_DEV_DIR, NULL, MS_BIND|MS_REC, NULL) < 0)
            errExit("mount bind");

        // mount tmpfs on /var
        if (arg_debug)
            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");
    }

    // 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
        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) {
                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)
                    printf("Created symbolic link %s -> %s\n", entry->link, entry->data + 10);
            }
        }

        entry = entry->next;
    }

    // mask the real home directory, currently mounted on WHITELIST_HOME_DIR
    if (home_dir) {
        if (mount("tmpfs", WHITELIST_HOME_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC,  "mode=755,gid=0") < 0)
            errExit("mount tmpfs");
    }

    // mask the real /tmp directory, currently mounted on WHITELIST_TMP_DIR
    if (tmp_dir) {
        if (mount("tmpfs", WHITELIST_TMP_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC,  "mode=755,gid=0") < 0)
            errExit("mount tmpfs");
    }

    return;

errexit:
    fprintf(stderr, "Error: invalid whitelist path %s\n", new_name);
    exit(1);
}
Пример #24
0
static void sanitize_passwd(void) {
	struct stat s;
	if (stat("/etc/passwd", &s) == -1)
		return;
	if (arg_debug)
		printf("Sanitizing /etc/passwd, UID_MIN %d\n", UID_MIN);
	if (is_link("/etc/passwd")) {
		fprintf(stderr, "Error: invalid /etc/passwd\n");
		exit(1);
	}

	FILE *fpin = NULL;
	FILE *fpout = NULL;
	fs_build_mnt_dir();

	// open files
	/* coverity[toctou] */
	fpin = fopen("/etc/passwd", "r");
	if (!fpin)
		goto errout;
	fpout = fopen(RUN_PASSWD_FILE, "w");
	if (!fpout)
		goto errout;
	
	// read the file line by line
	char buf[MAXBUF];
	uid_t myuid = getuid();
	while (fgets(buf, MAXBUF, fpin)) {
		// comments and empty lines
		if (*buf == '\0' || *buf == '#')
			continue;
		
		// sample line:
		// 	www-data:x:33:33:www-data:/var/www:/bin/sh
		// drop lines with uid > 1000 and not the current user
		char *ptr = buf;
		
		// advance to uid
		while (*ptr != ':' && *ptr != '\0')
			ptr++;
		if (*ptr == '\0')
			goto errout;
		char *ptr1 = ptr;
		ptr++;
		while (*ptr != ':' && *ptr != '\0')
			ptr++;
		if (*ptr == '\0')
			goto errout;
		ptr++;
		if (*ptr == '\0')
			goto errout;

		// process uid
		int uid;
		int rv = sscanf(ptr, "%d:", &uid);
		if (rv == 0 || uid < 0)
			goto errout;
		if (uid < UID_MIN) {
			fprintf(fpout, "%s", buf);
			continue;
		}
		if ((uid_t) uid != myuid) {
			// store user name - necessary to process /etc/group
			*ptr1 = '\0';
			char *user = strdup(buf);
			if (!user)
				errExit("malloc");
			ulist_add(user);
			continue; // skip line
		}
		fprintf(fpout, "%s", buf);
	}
	fclose(fpin);
	fclose(fpout);
	if (chown(RUN_PASSWD_FILE, 0, 0) == -1)
		errExit("chown");
	if (chmod(RUN_PASSWD_FILE, 0644) == -1)
		errExit("chmod");
		
	// mount-bind tne new password file
	if (mount(RUN_PASSWD_FILE, "/etc/passwd", "none", MS_BIND, "mode=400,gid=0") < 0)
		errExit("mount");
	fs_logger("create /etc/passwd");
	
	return;	
	
errout:
	fprintf(stderr, "Warning: failed to clean up /etc/passwd\n");
	if (fpin)
		fclose(fpin);
	if (fpout)
		fclose(fpout);
}
Пример #25
0
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);
}
Пример #26
0
// disable shm in pulseaudio
void pulseaudio_init(void) {
	struct stat s;
	
	// do we have pulseaudio in the system?
	if (stat("/etc/pulse/client.conf", &s) == -1)
		return;
	 
 	// create the new user pulseaudio directory
	 fs_build_mnt_dir();
	int rv = mkdir(RUN_PULSE_DIR, 0700);
	(void) rv; // in --chroot mode the directory can already be there
	if (chown(RUN_PULSE_DIR, getuid(), getgid()) < 0)
		errExit("chown");
	if (chmod(RUN_PULSE_DIR, 0700) < 0)
		errExit("chmod");

	// create the new client.conf file
	char *pulsecfg = NULL;
	if (asprintf(&pulsecfg, "%s/client.conf", RUN_PULSE_DIR) == -1)
		errExit("asprintf");
	if (copy_file("/etc/pulse/client.conf", pulsecfg))
		errExit("copy_file");
	FILE *fp = fopen(pulsecfg, "a+");
	if (!fp)
		errExit("fopen");
	fprintf(fp, "%s", "\nenable-shm = no\n");
	fclose(fp);
	if (chmod(pulsecfg, 0644) == -1)
		errExit("chmod");
	if (chown(pulsecfg, getuid(), getgid()) == -1)
		errExit("chown");

	// create ~/.config/pulse directory if not present
	char *dir1;
	if (asprintf(&dir1, "%s/.config", cfg.homedir) == -1)
		errExit("asprintf");
	if (stat(dir1, &s) == -1) {
		int rv = mkdir(dir1, 0755);
		if (rv == 0) {
			rv = chown(dir1, getuid(), getgid());
			(void) rv;
			rv = chmod(dir1, 0755);
			(void) rv;
		}
	}
	free(dir1);
	if (asprintf(&dir1, "%s/.config/pulse", cfg.homedir) == -1)
		errExit("asprintf");
	if (stat(dir1, &s) == -1) {
		int rv = mkdir(dir1, 0700);
		if (rv == 0) {
			rv = chown(dir1, getuid(), getgid());
			(void) rv;
			rv = chmod(dir1, 0700);
			(void) rv;
		}
	}
	free(dir1);
	
	
	// if we have ~/.config/pulse mount the new directory, else set environment variable
	char *homeusercfg;
	if (asprintf(&homeusercfg, "%s/.config/pulse", cfg.homedir) == -1)
		errExit("asprintf");
	if (stat(homeusercfg, &s) == 0) {
		if (mount(RUN_PULSE_DIR, homeusercfg, "none", MS_BIND, NULL) < 0)
			errExit("mount pulseaudio");
		fs_logger2("tmpfs", homeusercfg);
	}
	else {
		// set environment
		if (setenv("PULSE_CLIENTCONFIG", pulsecfg, 1) < 0)
			errExit("setenv");
	}
		
	free(pulsecfg);
	free(homeusercfg);
}
Пример #27
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();
	
	uid_t u = getuid();
	gid_t g = getgid();
	struct stat s;
	if (stat(homedir, &s) == -1) {
		exechelp_logerrv("firejail", FIREJAIL_ERROR, "Error: cannot find user home directory\n");
		exit(1);
	}

	// create /tmp/firejail/mnt/home directory
	fs_build_mnt_dir();
	int rv = mkdir(HOME_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
	if (rv == -1)
		errExit("mkdir");
	if (chown(HOME_DIR, u, g) < 0)
		errExit("chown");
	if (chmod(HOME_DIR, 0755) < 0)
		errExit("chmod");
	
	// copy the list of files in the new home directory
	// using a new child process without root privileges
	pid_t child = fork();
	if (child < 0)
		errExit("fork");
	if (child == 0) {
		if (arg_debug)
			printf("Copying files in the new home:\n");
		
		// drop privileges
		if (setgroups(0, NULL) < 0)
			errExit("setgroups");
		if (setgid(getgid()) < 0)
			errExit("setgid/getgid");
		if (setuid(getuid()) < 0)
			errExit("setuid/getuid");
		
		// 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);
		free(dlist);	
		exit(0);
	}
	// wait for the child to finish
	waitpid(child, NULL, 0);

	// mount bind private_homedir on top of homedir
	char *newhome;
	if (asprintf(&newhome, "%s%s", HOME_DIR, cfg.homedir) == -1)
		errExit("asprintf");

	if (arg_debug)
		printf("Mount-bind %s on top of %s\n", newhome, homedir);
	if (mount(newhome, homedir, NULL, MS_BIND|MS_REC, NULL) < 0)
		errExit("mount bind");
// preserve mode and ownership
//	if (chown(homedir, s.st_uid, s.st_gid) == -1)
//		errExit("mount-bind chown");
//	if (chmod(homedir, s.st_mode) == -1)
//		errExit("mount-bind chmod");

	if (u != 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");

		// mask /tmp only in root mode; KDE keeps all kind of sockets in /tmp!
		if (arg_debug)
			printf("Mounting a new /tmp directory\n");
		if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC,  "mode=777,gid=0") < 0)
			errExit("mounting tmp directory");
	}

	skel(homedir, u, g);
	if (xflag)
		copy_xauthority();

}
Пример #28
0
void fs_private_dev(void){
	int rv;
	// install a new /dev directory
	if (arg_debug)
		printf("Mounting tmpfs on /dev\n");

	int have_dri = 0;
	struct stat s;
	if (stat("/dev/dri", &s) == 0)
		have_dri = 1;

	// create DRI_DIR
	fs_build_mnt_dir();
	if (have_dri) {
		/* coverity[toctou] */
		rv = mkdir(RUN_DRI_DIR, 0755);
		if (rv == -1)
			errExit("mkdir");
		if (chown(RUN_DRI_DIR, 0, 0) < 0)
			errExit("chown");
		if (chmod(RUN_DRI_DIR, 0755) < 0)
			errExit("chmod");
	
		// keep a copy of /dev/dri under DRI_DIR
		if (mount("/dev/dri", RUN_DRI_DIR, NULL, MS_BIND|MS_REC, NULL) < 0)
			errExit("mounting /dev/dri");
	}
	
	// restore /dev/log
	int have_devlog = 0;
	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=777,gid=0") < 0)
		errExit("mounting /dev");
	fs_logger("mount tmpfs on /dev");

	// 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 back the /dev/dri directory
	if (have_dri) {
		/* coverity[toctou] */
		rv = mkdir("/dev/dri", 0755);
		if (rv == -1)
			errExit("mkdir");
		if (chown("/dev/dri", 0, 0) < 0)
			errExit("chown");
		if (chmod("/dev/dri",0755) < 0)
			errExit("chmod");
		if (mount(RUN_DRI_DIR, "/dev/dri", NULL, MS_BIND|MS_REC, NULL) < 0)
			errExit("mounting /dev/dri");
		fs_logger("clone /dev/dri");
	}
	
	// create /dev/shm
	if (arg_debug)
		printf("Create /dev/shm directory\n");
	rv = mkdir("/dev/shm", 0777);
	if (rv == -1)
		errExit("mkdir");
	if (chown("/dev/shm", 0, 0) < 0)
		errExit("chown");
	if (chmod("/dev/shm", 0777) < 0)
		errExit("chmod");
	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
	rv = mkdir("/dev/pts", 0755);
	if (rv == -1)
		errExit("mkdir");
	if (chown("/dev/pts", 0, 0) < 0)
		errExit("chown");
	if (chmod("/dev/pts", 0755) < 0)
		errExit("chmod");
	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");
	// 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");
	fs_logger("mount devpts");

#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
}
Пример #29
0
static void sanitize_group(void) {
	struct stat s;
	if (stat("/etc/group", &s) == -1)
		return;
	if (arg_debug)
		printf("Sanitizing /etc/group, GID_MIN %d\n", GID_MIN);
	if (is_link("/etc/group")) {
		fprintf(stderr, "Error: invalid /etc/group\n");
		exit(1);
	}

	FILE *fpin = NULL;
	FILE *fpout = NULL;
	fs_build_mnt_dir();

	// open files
	/* coverity[toctou] */
	fpin = fopen("/etc/group", "r");
	if (!fpin)
		goto errout;
	fpout = fopen(RUN_GROUP_FILE, "w");
	if (!fpout)
		goto errout;
	
	// read the file line by line
	char buf[MAXBUF];
	gid_t mygid = getgid();
	while (fgets(buf, MAXBUF, fpin)) {
		// comments and empty lines
		if (*buf == '\0' || *buf == '#')
			continue;
		
		// sample line:
		// 	pulse:x:115:netblue,bingo
		// drop lines with uid > 1000 and not the current user group
		char *ptr = buf;
		
		// advance to uid
		while (*ptr != ':' && *ptr != '\0')
			ptr++;
		if (*ptr == '\0')
			goto errout;
		ptr++;
		while (*ptr != ':' && *ptr != '\0')
			ptr++;
		if (*ptr == '\0')
			goto errout;
		ptr++;
		if (*ptr == '\0')
			goto errout;

		// process uid
		int gid;
		int rv = sscanf(ptr, "%d:", &gid);
		if (rv == 0 || gid < 0)
			goto errout;
		if (gid < GID_MIN) {
			if (copy_line(fpout, buf, ptr))
				goto errout;
			continue;
		}
		if ((gid_t) gid != mygid) {
			continue; // skip line
		}
		if (copy_line(fpout, buf, ptr))
			goto errout;
	}
	fclose(fpin);
	fclose(fpout);
	if (chown(RUN_GROUP_FILE, 0, 0) == -1)
		errExit("chown");
	if (chmod(RUN_GROUP_FILE, 0644) == -1)
		errExit("chmod");
		
	// mount-bind tne new group file
	if (mount(RUN_GROUP_FILE, "/etc/group", "none", MS_BIND, "mode=400,gid=0") < 0)
		errExit("mount");
	fs_logger("create /etc/group");
	
	return;	
	
errout:
	fprintf(stderr, "Warning: failed to clean up /etc/group\n");
	if (fpin)
		fclose(fpin);
	if (fpout)
		fclose(fpout);
}
Пример #30
0
static void fs_build_remount_mnt_dir(void) {
	tmpfs_mounted = 0;
	fs_build_mnt_dir();
}