Ejemplo n.º 1
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
				if (mkdir(lnk, S_IRWXU|S_IRWXG|S_IRWXO))
					errExit("mkdir");
				if (chown(lnk, 0, 0))
					errExit("chown");
				if (chmod(lnk, S_IRWXU|S_IRWXG|S_IRWXO))
					errExit("chmod");
			}
			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 {
			fprintf(stderr, "Warning: /var/lock not mounted\n");
			dbg_test_dir("/var/lock");
		}
	}
}
Ejemplo n.º 2
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");
	}
}
Ejemplo n.º 3
0
// private mode (--private=homedir):
// 	mount homedir on top of /home/user,
// 	tmpfs on top of  /root in nonroot mode,
// 	set skel files,
// 	restore .Xauthority
void fs_private_homedir(void) {
	char *homedir = cfg.homedir;
	char *private_homedir = cfg.home_private;
	assert(homedir);
	assert(private_homedir);
	
	int xflag = store_xauthority();
	int aflag = store_asoundrc();
	
	uid_t u = getuid();
	gid_t g = getgid();
	struct stat s;
	if (stat(homedir, &s) == -1) {
		fprintf(stderr, "Error: cannot find user home directory\n");
		exit(1);
	}
	

	// mount bind private_homedir on top of homedir
	if (arg_debug)
		printf("Mount-bind %s on top of %s\n", private_homedir, homedir);
	if (mount(private_homedir, homedir, NULL, MS_NOSUID | MS_NODEV | MS_BIND | MS_REC, NULL) < 0)
		errExit("mount bind");
	fs_logger3("mount-bind", private_homedir, cfg.homedir);
	fs_logger2("whitelist", cfg.homedir);
// 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_NOEXEC | MS_STRICTATIME | MS_REC,  "mode=700,gid=0") < 0)
			errExit("mounting home directory");
		fs_logger("tmpfs /root");
	}
	else {
		// mask /home
		if (arg_debug)
			printf("Mounting a new /home directory\n");
		if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_STRICTATIME | MS_REC,  "mode=755,gid=0") < 0)
			errExit("mounting home directory");
		fs_logger("tmpfs /home");
	}
	

	skel(homedir, u, g);
	if (xflag)
		copy_xauthority();
	if (aflag)
		copy_asoundrc();
}
Ejemplo n.º 4
0
void fs_var_lib(void) {
	struct stat s;
	
	// ISC DHCP multiserver
	if (stat("/var/lib/dhcp", &s) == 0) {
		if (arg_debug)
			printf("Mounting tmpfs on /var/lib/dhcp\n");
		if (mount("tmpfs", "/var/lib/dhcp", "tmpfs", MS_NOSUID |  MS_NOEXEC | MS_NODEV | MS_STRICTATIME | MS_REC,  "mode=755,gid=0") < 0)
			errExit("mounting /var/lib/dhcp");
		fs_logger("tmpfs /var/lib/dhcp");
			
		// isc dhcp server requires a /var/lib/dhcp/dhcpd.leases file
		FILE *fp = fopen("/var/lib/dhcp/dhcpd.leases", "w");
		
		if (fp) {
			fprintf(fp, "\n");
			fclose(fp);
			if (chown("/var/lib/dhcp/dhcpd.leases", 0, 0) == -1)
				errExit("chown");
			if (chmod("/var/lib/dhcp/dhcpd.leases", S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH))
				errExit("chmod");
			fs_logger("touch /var/lib/dhcp/dhcpd.leases");
		}
	}

	// nginx multiserver
	if (stat("/var/lib/nginx", &s) == 0) {
		if (arg_debug)
			printf("Mounting tmpfs on /var/lib/nginx\n");
		if (mount("tmpfs", "/var/lib/nginx", "tmpfs", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME | MS_REC,  "mode=755,gid=0") < 0)
			errExit("mounting /var/lib/nginx");
		fs_logger("tmpfs /var/lib/nginx");
	}			

	// net-snmp multiserver
	if (stat("/var/lib/snmp", &s) == 0) {
		if (arg_debug)
			printf("Mounting tmpfs on /var/lib/snmp\n");
		if (mount("tmpfs", "/var/lib/snmp", "tmpfs", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME | MS_REC,  "mode=755,gid=0") < 0)
			errExit("mounting /var/lib/snmp");
		fs_logger("tmpfs /var/lib/snmp");
	}			

	// this is where sudo remembers its state
	if (stat("/var/lib/sudo", &s) == 0) {
		if (arg_debug)
			printf("Mounting tmpfs on /var/lib/sudo\n");
		if (mount("tmpfs", "/var/lib/sudo", "tmpfs", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME | MS_REC,  "mode=755,gid=0") < 0)
			errExit("mounting /var/lib/sudo");
		fs_logger("tmpfs /var/lib/sudo");
	}			
}
Ejemplo n.º 5
0
void fs_trace(void) {
	// create the new ld.so.preload file and mount-bind it
	if (arg_debug)
		printf("Create the new ld.so.preload file\n");

	FILE *fp = fopen(RUN_LDPRELOAD_FILE, "w");
	if (!fp)
		errExit("fopen");
	const char *prefix = RUN_FIREJAIL_LIB_DIR;

	if (arg_trace) {
		fprintf(fp, "%s/libtrace.so\n", prefix);
	}
	else if (arg_tracelog) {
		fprintf(fp, "%s/libtracelog.so\n", prefix);
		fmessage("Blacklist violations are logged to syslog\n");
	}
	if (arg_seccomp_postexec) {
		fprintf(fp, "%s/libpostexecseccomp.so\n", prefix);
		fmessage("Post-exec seccomp protector enabled\n");
	}

	SET_PERMS_STREAM(fp, 0, 0, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH);
	fclose(fp);

	// mount the new preload file
	if (arg_debug)
		printf("Mount the new ld.so.preload file\n");
	if (mount(RUN_LDPRELOAD_FILE, "/etc/ld.so.preload", NULL, MS_BIND|MS_REC, NULL) < 0)
		errExit("mount bind ld.so.preload");
	fs_logger("create /etc/ld.so.preload");
}
Ejemplo n.º 6
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");
}
Ejemplo n.º 7
0
void fs_x11(void) {
#ifdef HAVE_X11
	int display = x11_display();
	if (display <= 0)
		return;

	char *x11file;
	if (asprintf(&x11file, "/tmp/.X11-unix/X%d", display) == -1)
		errExit("asprintf");
	struct stat s;
	if (stat(x11file, &s) == -1)
		return;

	// keep a copy of real /tmp/.X11-unix directory in WHITELIST_TMP_DIR
	int rv = mkdir(RUN_WHITELIST_X11_DIR, 1777);
	if (rv == -1)
		errExit("mkdir");
	if (chown(RUN_WHITELIST_X11_DIR, 0, 0) < 0)
		errExit("chown");
	if (chmod(RUN_WHITELIST_X11_DIR, 1777) < 0)
		errExit("chmod");

	if (mount("/tmp/.X11-unix", RUN_WHITELIST_X11_DIR, NULL, MS_BIND|MS_REC, NULL) < 0)
		errExit("mount bind");

	// mount tmpfs on /tmp/.X11-unix
	if (arg_debug || arg_debug_whitelists)
		printf("Mounting tmpfs on /tmp/.X11-unix directory\n");
	if (mount("tmpfs", "/tmp/.X11-unix", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC,  "mode=1777,gid=0") < 0)
		errExit("mounting tmpfs on /tmp");
	fs_logger("tmpfs /tmp/.X11-unix");

	// create an empty file
	FILE *fp = fopen(x11file, "w");
	if (!fp) {
		fprintf(stderr, "Error: cannot create empty file in x11 directory\n");
		exit(1);
	}
	// set file properties
	SET_PERMS_STREAM(fp, s.st_uid, s.st_gid, s.st_mode);
	fclose(fp);

	// mount
	char *wx11file;
	if (asprintf(&wx11file, "%s/X%d", RUN_WHITELIST_X11_DIR, display) == -1)
		errExit("asprintf");
	if (mount(wx11file, x11file, NULL, MS_BIND|MS_REC, NULL) < 0)
		errExit("mount bind");
	 fs_logger2("whitelist", x11file);

	free(x11file);
	free(wx11file);
	
	// block access to RUN_WHITELIST_X11_DIR
	 if (mount(RUN_RO_DIR, RUN_WHITELIST_X11_DIR, "none", MS_BIND, "mode=400,gid=0") == -1)
	 	errExit("mount");
	 fs_logger2("blacklist", RUN_WHITELIST_X11_DIR);
#endif
}
Ejemplo n.º 8
0
// private mode (--private):
//	mount tmpfs over /home/user,
// 	tmpfs on top of  /root in nonroot mode,
// 	set skel files,
// 	restore .Xauthority
void fs_private(void) {
	char *homedir = cfg.homedir;
	assert(homedir);
	uid_t u = getuid();
	gid_t g = getgid();

	int xflag = store_xauthority();
	int aflag = store_asoundrc();

	// mask /home
	if (arg_debug)
		printf("Mounting a new /home directory\n");
	if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_STRICTATIME | MS_REC,  "mode=755,gid=0") < 0)
		errExit("mounting home directory");
	fs_logger("tmpfs /home");

	// mask /root
	if (arg_debug)
		printf("Mounting a new /root directory\n");
	if (mount("tmpfs", "/root", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_STRICTATIME | MS_REC,  "mode=700,gid=0") < 0)
		errExit("mounting root directory");
	fs_logger("tmpfs /root");

	if (u != 0) {
		// create /home/user
		if (arg_debug)
			printf("Create a new user directory\n");
		if (mkdir(homedir, S_IRWXU) == -1) {
			if (mkpath_as_root(homedir) == -1)
				errExit("mkpath");
			if (mkdir(homedir, S_IRWXU) == -1)
				errExit("mkdir");
		}
		if (chown(homedir, u, g) < 0)
			errExit("chown");
		fs_logger2("mkdir", homedir);
	}
	
	skel(homedir, u, g);
	if (xflag)
		copy_xauthority();
	if (aflag)
		copy_asoundrc();

}
Ejemplo n.º 9
0
void fs_var_log(void) {
	build_list("/var/log");
	
	// create /var/log if it doesn't exit
	if (is_dir("/var/log")) {
		// extract group id for /var/log/wtmp
		struct stat s;
		gid_t wtmp_group = 0;
		if (stat("/var/log/wtmp", &s) == 0)
			wtmp_group = s.st_gid;
		
		// mount a tmpfs on top of /var/log
		if (arg_debug)
			printf("Mounting tmpfs on /var/log\n");
		if (mount("tmpfs", "/var/log", "tmpfs", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME | MS_REC,  "mode=755,gid=0") < 0)
			errExit("mounting /var/log");
		fs_logger("tmpfs /var/log");
		
		build_dirs();
		release_all();
		
		// create an empty /var/log/wtmp file
		/* coverity[toctou] */
		FILE *fp = fopen("/var/log/wtmp", "w");
		if (fp)
			fclose(fp);
		if (chown("/var/log/wtmp", 0, wtmp_group) < 0)
			errExit("chown");
		if (chmod("/var/log/wtmp", S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH ) < 0)
			errExit("chmod");
		fs_logger("touch /var/log/wtmp");
			
		// create an empty /var/log/btmp file
		fp = fopen("/var/log/btmp", "w");
		if (fp)
			fclose(fp);
		if (chown("/var/log/btmp", 0, wtmp_group) < 0)
			errExit("chown");
		if (chmod("/var/log/btmp", S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP) < 0)
			errExit("chmod");
		fs_logger("touch /var/log/btmp");
	}
	else
		fprintf(stderr, "Warning: cannot mount tmpfs on top of /var/log\n");
}
Ejemplo n.º 10
0
void fs_var_log(void) {
	build_list("/var/log");

	// note: /var/log is not created here, if it does not exist, this section fails.
	// create /var/log if it doesn't exit
	if (is_dir("/var/log")) {
		// extract group id for /var/log/wtmp
		struct stat s;
		gid_t wtmp_group = 0;
		if (stat("/var/log/wtmp", &s) == 0)
			wtmp_group = s.st_gid;

		// mount a tmpfs on top of /var/log
		if (arg_debug)
			printf("Mounting tmpfs on /var/log\n");
		if (mount("tmpfs", "/var/log", "tmpfs", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME | MS_REC,  "mode=755,gid=0") < 0)
			errExit("mounting /var/log");
		fs_logger("tmpfs /var/log");

		build_dirs();
		release_all();

		// create an empty /var/log/wtmp file
		/* coverity[toctou] */
		FILE *fp = fopen("/var/log/wtmp", "w");
		if (fp) {
			SET_PERMS_STREAM(fp, 0, wtmp_group, S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH);
			fclose(fp);
		}
		fs_logger("touch /var/log/wtmp");

		// create an empty /var/log/btmp file
		fp = fopen("/var/log/btmp", "w");
		if (fp) {
			SET_PERMS_STREAM(fp, 0, wtmp_group, S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP);
			fclose(fp);
		}
		fs_logger("touch /var/log/btmp");
	}
	else
		fwarning("cannot hide /var/log directory\n");
}
Ejemplo n.º 11
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_STRICTATIME | MS_REC,  "mode=755,gid=0") < 0)
			errExit("mounting /var/cache/apache2");
		fs_logger("mount tmpfs on /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_STRICTATIME | MS_REC,  "mode=755,gid=0") < 0)
			errExit("mounting /var/cache/lighttpd");
		fs_logger("mount tmpfs on /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;
		}
		
		int rv = mkdir("/var/cache/lighttpd/compress", S_IRWXU | S_IRWXG | S_IRWXO);
		if (rv == -1)
			errExit("mkdir");
		if (chown("/var/cache/lighttpd/compress", uid, gid) < 0)
			errExit("chown");
		fs_logger("mkdir /var/cache/lighttpd/compress");

		rv = mkdir("/var/cache/lighttpd/uploads", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
		if (rv == -1)
			errExit("mkdir");
		if (chown("/var/cache/lighttpd/uploads", uid, gid) < 0)
			errExit("chown");
		fs_logger("/var/cache/lighttpd/uploads");
	}			
}
Ejemplo n.º 12
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);
	
}
Ejemplo n.º 13
0
void fs_var_utmp(void) {
	struct stat s;

	// extract utmp group id
	gid_t utmp_group = 0;
	if (stat(UTMP_FILE, &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");

	/* coverity[toctou] */
	FILE *fp = fopen(RUN_UTMP_FILE, "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(RUN_UTMP_FILE, 0, utmp_group) < 0)
		errExit("chown");
	if (chmod(RUN_UTMP_FILE, 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(RUN_UTMP_FILE, UTMP_FILE, NULL, MS_BIND|MS_NOSUID|MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0)
		errExit("mount bind utmp");
	fs_logger("create /var/run/utmp");
}
Ejemplo n.º 14
0
static void sanitize_run(void) {
	if (arg_debug)
		printf("Cleaning /run/user directory\n");

	char *runuser;
	if (asprintf(&runuser, "/run/user/%u", getuid()) == -1)
		errExit("asprintf");

	struct stat s;
	if (stat(runuser, &s) == -1) {
		// cannot find /user/run/$UID directory, just return
		if (arg_debug)
			printf("Cannot find %s directory\n", runuser);
		free(runuser);
		return;
	}

	if (mkdir(RUN_WHITELIST_RUN_DIR, 0755) == -1)
		errExit("mkdir");

	// keep a copy of the /run/user/$UID directory
	if (mount(runuser, RUN_WHITELIST_RUN_DIR, NULL, MS_BIND|MS_REC, NULL) < 0)
		errExit("mount bind");

	// mount tmpfs on /run/user
	if (mount("tmpfs", "/run/user", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME,  "mode=755,gid=0") < 0)
		errExit("mount tmpfs");
	fs_logger("tmpfs /run/user");

	// create new user directory
	if (mkdir(runuser, 0700) == -1)
		errExit("mkdir");
	fs_logger2("mkdir", runuser);

	// set mode and ownership
	if (set_perms(runuser, getuid(), getgid(), 0700))
		errExit("set_perms");

	// mount user home directory
	if (mount(RUN_WHITELIST_RUN_DIR, runuser, NULL, MS_BIND|MS_REC, NULL) < 0)
		errExit("mount bind");

	// mask mirrored /run/user/$UID directory
	if (mount("tmpfs", RUN_WHITELIST_RUN_DIR, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME,  "mode=755,gid=0") < 0)
		errExit("mount tmpfs");
	fs_logger2("tmpfs", RUN_WHITELIST_RUN_DIR);

	free(runuser);
}
Ejemplo n.º 15
0
void fs_var_tmp(void) {
	struct stat s;
	if (stat("/var/tmp", &s) == 0) {
		if (!is_link("/var/tmp")) {
			if (arg_debug)
				printf("Mounting tmpfs on /var/tmp\n");
			if (mount("tmpfs", "/var/tmp", "tmpfs", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME | MS_REC,  "mode=1777,gid=0") < 0)
				errExit("mounting /var/tmp");
			fs_logger("tmpfs /var/tmp");
		}
	}
	else {
		fprintf(stderr, "Warning: /var/tmp not mounted\n");
		dbg_test_dir("/var/tmp");
	}
}
Ejemplo n.º 16
0
void fs_trace_preload(void) {
	struct stat s;

	// create an empty /etc/ld.so.preload
	if (stat("/etc/ld.so.preload", &s)) {
		if (arg_debug)
			printf("Creating an empty /etc/ld.so.preload file\n");
		/* coverity[toctou] */
		FILE *fp = fopen("/etc/ld.so.preload", "w");
		if (!fp)
			errExit("fopen");
		SET_PERMS_STREAM(fp, 0, 0, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH);
		fclose(fp);
		fs_logger("touch /etc/ld.so.preload");
	}
}
Ejemplo n.º 17
0
void restrict_users(void) {
	// only in user mode
	if (getuid()) {
		if (strncmp(cfg.homedir, "/home/", 6) == 0) {
			// user has the home directory under /home
			sanitize_home();
		}
		else {
			// user has the home diercotry outside /home
			// mount tmpfs on top of /home in order to hide it
			if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC,  "mode=755,gid=0") < 0)
				errExit("mount tmpfs");
			fs_logger("tmpfs /home");
		}
		sanitize_passwd();
		sanitize_group();
	}
}
Ejemplo n.º 18
0
void fs_dev_shm(void) {
	uid_t uid = getuid(); // set a new shm only if we started as root
	if (uid)
		return;

	if (is_dir("/dev/shm")) {
		if (arg_debug)
			printf("Mounting tmpfs on /dev/shm\n");
		if (mount("tmpfs", "/dev/shm", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC,  "mode=1777,gid=0") < 0)
			errExit("mounting /dev/shm");
		fs_logger("tmpfs /dev/shm");
	}
	else {
		char *lnk = realpath("/dev/shm", NULL);
		if (lnk) {
			if (!is_dir(lnk)) {
				// create directory
				if (mkdir(lnk, 01777))
					errExit("mkdir");
				// mkdir sets only the file permission bits
				if (chmod(lnk, 01777))
					errExit("chmod");
				ASSERT_PERMS(lnk, 0, 0, 01777);
			}
			if (arg_debug)
				printf("Mounting tmpfs on %s on behalf of /dev/shm\n", lnk);
			if (mount("tmpfs", lnk, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC,  "mode=1777,gid=0") < 0)
				errExit("mounting /var/tmp");
			fs_logger2("tmpfs", lnk);
			free(lnk);
		}
		else {
			fprintf(stderr, "Warning: /dev/shm not mounted\n");
			dbg_test_dir("/dev/shm");
		}
			
	}
}
Ejemplo n.º 19
0
void fs_resolvconf(void) {
	if (cfg.dns1 == 0)
		return;

	struct stat s;
	
	// create a new /etc/hostname
	if (stat("/etc/resolv.conf", &s) == 0) {
		if (arg_debug)
			printf("Creating a new /etc/resolv.conf file\n");
		FILE *fp = fopen(RUN_RESOLVCONF_FILE, "w");
		if (!fp) {
			fprintf(stderr, "Error: cannot create %s\n", RUN_RESOLVCONF_FILE);
			exit(1);
		}
		
		if (cfg.dns1)
			fprintf(fp, "nameserver %d.%d.%d.%d\n", PRINT_IP(cfg.dns1));
		if (cfg.dns2)
			fprintf(fp, "nameserver %d.%d.%d.%d\n", PRINT_IP(cfg.dns2));
		if (cfg.dns3)
			fprintf(fp, "nameserver %d.%d.%d.%d\n", PRINT_IP(cfg.dns3));

		// mode and owner
		SET_PERMS_STREAM(fp, 0, 0, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH);

		fclose(fp);
		
		// bind-mount the file on top of /etc/hostname
		if (mount(RUN_RESOLVCONF_FILE, "/etc/resolv.conf", NULL, MS_BIND|MS_REC, NULL) < 0)
			errExit("mount bind /etc/resolv.conf");
		fs_logger("create /etc/resolv.conf");
	}
	else {
		fprintf(stderr, "Error: cannot set DNS servers, /etc/resolv.conf file is missing\n");
		exit(1);
	}
}
Ejemplo n.º 20
0
static void skel(const char *homedir, uid_t u, gid_t g) {
	char *fname;
	// zsh
	if (arg_zsh) {
		// copy skel files
		if (asprintf(&fname, "%s/.zshrc", homedir) == -1)
			errExit("asprintf");
		struct stat s;
		// don't copy it if we already have the file
		if (stat(fname, &s) == 0)
			return;
		if (stat("/etc/skel/.zshrc", &s) == 0) {
			if (copy_file("/etc/skel/.zshrc", fname) == 0) {
				if (chown(fname, u, g) == -1)
					errExit("chown");
				fs_logger("clone /etc/skel/.zshrc");
			}
		}
		else { // 
			FILE *fp = fopen(fname, "w");
			if (fp) {
				fprintf(fp, "\n");
				fclose(fp);
				if (chown(fname, u, g) == -1)
					errExit("chown");
				if (chmod(fname, S_IRUSR | S_IWUSR) < 0)
					errExit("chown");
				fs_logger2("touch", fname);
			}
		}
		free(fname);
	}
	// csh
	else if (arg_csh) {
		// copy skel files
		if (asprintf(&fname, "%s/.cshrc", homedir) == -1)
			errExit("asprintf");
		struct stat s;
		// don't copy it if we already have the file
		if (stat(fname, &s) == 0)
			return;
		if (stat("/etc/skel/.cshrc", &s) == 0) {
			if (copy_file("/etc/skel/.cshrc", fname) == 0) {
				if (chown(fname, u, g) == -1)
					errExit("chown");
				fs_logger("clone /etc/skel/.cshrc");
			}
		}
		else { // 
			/* coverity[toctou] */
			FILE *fp = fopen(fname, "w");
			if (fp) {
				fprintf(fp, "\n");
				fclose(fp);
				if (chown(fname, u, g) == -1)
					errExit("chown");
				if (chmod(fname, S_IRUSR | S_IWUSR) < 0)
					errExit("chown");
				fs_logger2("touch", fname);
			}
		}
		free(fname);
	}
	// bash etc.
	else {
		// copy skel files
		if (asprintf(&fname, "%s/.bashrc", homedir) == -1)
			errExit("asprintf");
		struct stat s;
		// don't copy it if we already have the file
		if (stat(fname, &s) == 0) 
			return;
		if (stat("/etc/skel/.bashrc", &s) == 0) {
			if (copy_file("/etc/skel/.bashrc", fname) == 0) {
				/* coverity[toctou] */
				if (chown(fname, u, g) == -1)
					errExit("chown");
				fs_logger("clone /etc/skel/.bashrc");
			}
		}
		free(fname);
	}
}
Ejemplo n.º 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
}
Ejemplo n.º 22
0
static void sanitize_group(void) {
	struct stat s;
	if (stat("/etc/group", &s) == -1)
		return;
	assert(gid_min);
	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;

	// 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;
		assert(gid_min);
		if (gid < gid_min || gid == 65534) { // on Debian platforms 65534 is group nogroup
			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);
	SET_PERMS_STREAM(fpout, 0, 0, 0644);
	fclose(fpout);

	// 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:
	fwarning("failed to clean up /etc/group\n");
	if (fpin)
		fclose(fpin);
	if (fpout)
		fclose(fpout);
}
Ejemplo n.º 23
0
static void sanitize_passwd(void) {
	struct stat s;
	if (stat("/etc/passwd", &s) == -1)
		return;
	assert(uid_min);
	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;

	// 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;
		assert(uid_min);
		if (uid < uid_min || uid == 65534) { // on Debian platforms user nobody is 65534
			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);
	SET_PERMS_STREAM(fpout, 0, 0, 0644);
	fclose(fpout);

	// 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:
	fwarning("failed to clean up /etc/passwd\n");
	if (fpin)
		fclose(fpin);
	if (fpout)
		fclose(fpout);
}
Ejemplo n.º 24
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
}
Ejemplo n.º 25
0
static void skel(const char *homedir, uid_t u, gid_t g) {
	char *fname;

	// zsh
	if (!arg_shell_none && (strcmp(cfg.shell,"/usr/bin/zsh") == 0 || strcmp(cfg.shell,"/bin/zsh") == 0)) {
		// copy skel files
		if (asprintf(&fname, "%s/.zshrc", homedir) == -1)
			errExit("asprintf");
		struct stat s;
		// don't copy it if we already have the file
		if (stat(fname, &s) == 0)
			return;
		if (stat("/etc/skel/.zshrc", &s) == 0) {
			if (copy_file("/etc/skel/.zshrc", fname, u, g, 0644) == 0) {
				fs_logger("clone /etc/skel/.zshrc");
			}
		}
		else { // 
			FILE *fp = fopen(fname, "w");
			if (fp) {
				fprintf(fp, "\n");
				SET_PERMS_STREAM(fp, u, g, S_IRUSR | S_IWUSR);
				fclose(fp);
				fs_logger2("touch", fname);
			}
		}
		free(fname);
	}
	// csh
	else if (!arg_shell_none && strcmp(cfg.shell,"/bin/csh") == 0) {
		// copy skel files
		if (asprintf(&fname, "%s/.cshrc", homedir) == -1)
			errExit("asprintf");
		struct stat s;
		// don't copy it if we already have the file
		if (stat(fname, &s) == 0)
			return;
		if (stat("/etc/skel/.cshrc", &s) == 0) {
			if (copy_file("/etc/skel/.cshrc", fname, u, g, 0644) == 0) {
				fs_logger("clone /etc/skel/.cshrc");
			}
		}
		else { // 
			/* coverity[toctou] */
			FILE *fp = fopen(fname, "w");
			if (fp) {
				fprintf(fp, "\n");
				SET_PERMS_STREAM(fp, u, g, S_IRUSR | S_IWUSR);
				fclose(fp);
				fs_logger2("touch", fname);
			}
		}
		free(fname);
	}
	// bash etc.
	else {
		// copy skel files
		if (asprintf(&fname, "%s/.bashrc", homedir) == -1)
			errExit("asprintf");
		struct stat s;
		// don't copy it if we already have the file
		if (stat(fname, &s) == 0) 
			return;
		if (stat("/etc/skel/.bashrc", &s) == 0) {
			if (copy_file("/etc/skel/.bashrc", fname, u, g, 0644) == 0) {
				fs_logger("clone /etc/skel/.bashrc");
			}
		}
		free(fname);
	}
}
Ejemplo n.º 26
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);
}
Ejemplo n.º 27
0
int sandbox(void* sandbox_arg) {
	// Get rid of unused parameter warning
	(void)sandbox_arg;

	pid_t child_pid = getpid();
	if (arg_debug)
		printf("Initializing child process\n");	

 	// close each end of the unused pipes
 	close(parent_to_child_fds[1]);
 	close(child_to_parent_fds[0]);
 
 	// wait for parent to do base setup
 	wait_for_other(parent_to_child_fds[0]);

	if (arg_debug && child_pid == 1)
		printf("PID namespace installed\n");

	//****************************
	// set hostname
	//****************************
	if (cfg.hostname) {
		if (sethostname(cfg.hostname, strlen(cfg.hostname)) < 0)
			errExit("sethostname");
	}

	//****************************
	// mount namespace
	//****************************
	// mount events are not forwarded between the host the sandbox
	if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0) {
		chk_chroot();
	}
	
	
	//****************************
	// log sandbox data
	//****************************
	if (cfg.name)
		fs_logger2("sandbox name:", cfg.name);
	fs_logger2int("sandbox pid:", (int) sandbox_pid);
	if (cfg.chrootdir)
		fs_logger("sandbox filesystem: chroot");
	else if (arg_overlay)	
		fs_logger("sandbox filesystem: overlay");
	else
		fs_logger("sandbox filesystem: local");
	fs_logger("install mount namespace");
	
	//****************************
	// netfilter etc.
	//****************************
	if (arg_netfilter && any_bridge_configured()) { // assuming by default the client filter
		netfilter(arg_netfilter_file);
	}
	if (arg_netfilter6 && any_bridge_configured()) { // assuming by default the client filter
		netfilter6(arg_netfilter6_file);
	}

	// load IBUS env variables
	if (arg_nonetwork || any_bridge_configured() || any_interface_configured()) {
		// do nothing - there are problems with ibus version 1.5.11
	}
	else
		env_ibus_load();
	
	// grab a copy of cp command
	fs_build_cp_command();
	
	// trace pre-install
	if (arg_trace || arg_tracelog)
		fs_trace_preload();

	//****************************
	// configure filesystem
	//****************************
#ifdef HAVE_SECCOMP
	int enforce_seccomp = 0;
#endif
#ifdef HAVE_CHROOT		
	if (cfg.chrootdir) {
		fs_chroot(cfg.chrootdir);
		// redo cp command
		fs_build_cp_command();
		
		// force caps and seccomp if not started as root
		if (getuid() != 0) {
			// force default seccomp inside the chroot, no keep or drop list
			// the list build on top of the default drop list is kept intact
			arg_seccomp = 1;
#ifdef HAVE_SECCOMP
			enforce_seccomp = 1;
#endif
			if (cfg.seccomp_list_drop) {
				free(cfg.seccomp_list_drop);
				cfg.seccomp_list_drop = NULL;
			}
			if (cfg.seccomp_list_keep) {
				free(cfg.seccomp_list_keep);
				cfg.seccomp_list_keep = NULL;
			}
			
			// disable all capabilities
			if (arg_caps_default_filter || arg_caps_list)
				fprintf(stderr, "Warning: all capabilities disabled for a regular user during chroot\n");
			arg_caps_drop_all = 1;
			
			// drop all supplementary groups; /etc/group file inside chroot
			// is controlled by a regular usr
			arg_nogroups = 1;
			if (!arg_quiet)
				printf("Dropping all Linux capabilities and enforcing default seccomp filter\n");
		}
		else
			arg_seccomp = 1;
						
		//****************************
		// trace pre-install, this time inside chroot
		//****************************
		if (arg_trace || arg_tracelog)
			fs_trace_preload();
	}
	else 
#endif		
	if (arg_overlay)	
		fs_overlayfs();
	else
		fs_basic_fs();
	

	//****************************
	// set hostname in /etc/hostname
	//****************************
	if (cfg.hostname) {
		fs_hostname(cfg.hostname);
	}
	
	//****************************
	// private mode
	//****************************
	if (arg_private) {
		if (cfg.home_private)	// --private=
			fs_private_homedir();
		else // --private
			fs_private();
	}
	
	if (arg_private_dev)
		fs_private_dev();
	if (arg_private_etc) {
		fs_private_etc_list();
		// create /etc/ld.so.preload file again
		if (arg_trace || arg_tracelog)
			fs_trace_preload();
	}
	if (arg_private_bin)
		fs_private_bin_list();
	if (arg_private_tmp)
		fs_private_tmp();
	
	//****************************
	// apply the profile file
	//****************************
	if (cfg.profile) {
		// apply all whitelist commands ... 
		fs_whitelist();
		
		// ... followed by blacklist commands
		fs_blacklist();
	}
	
	//****************************
	// install trace
	//****************************
	if (arg_trace || arg_tracelog)
		fs_trace();
		
	//****************************
	// update /proc, /dev, /boot directorymy
	//****************************
	fs_proc_sys_dev_boot();
	
	//****************************
	// --nosound and fix for pulseaudio 7.0
	//****************************
	if (arg_nosound)
		pulseaudio_disable();
	else
		pulseaudio_init();
	
	//****************************
	// networking
	//****************************
	if (arg_nonetwork) {
		net_if_up("lo");
		if (arg_debug)
			printf("Network namespace enabled, only loopback interface available\n");
	}
	else if (any_bridge_configured() || any_interface_configured()) {
		// configure lo and eth0...eth3
		net_if_up("lo");
		
		if (mac_not_zero(cfg.bridge0.macsandbox))
			net_config_mac(cfg.bridge0.devsandbox, cfg.bridge0.macsandbox);
		sandbox_if_up(&cfg.bridge0);
		
		if (mac_not_zero(cfg.bridge1.macsandbox))
			net_config_mac(cfg.bridge1.devsandbox, cfg.bridge1.macsandbox);
		sandbox_if_up(&cfg.bridge1);
		
		if (mac_not_zero(cfg.bridge2.macsandbox))
			net_config_mac(cfg.bridge2.devsandbox, cfg.bridge2.macsandbox);
		sandbox_if_up(&cfg.bridge2);
		
		if (mac_not_zero(cfg.bridge3.macsandbox))
			net_config_mac(cfg.bridge3.devsandbox, cfg.bridge3.macsandbox);
		sandbox_if_up(&cfg.bridge3);
		
		// add a default route
		if (cfg.defaultgw) {
			// set the default route
			if (net_add_route(0, 0, cfg.defaultgw))
				fprintf(stderr, "Warning: cannot configure default route\n");
		}
		
		// enable interfaces
		if (cfg.interface0.configured && cfg.interface0.ip) {
			if (arg_debug)
				printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface0.ip), cfg.interface0.dev);
			net_if_ip(cfg.interface0.dev, cfg.interface0.ip, cfg.interface0.mask, cfg.interface0.mtu);
			net_if_up(cfg.interface0.dev);
		}			
		if (cfg.interface1.configured && cfg.interface1.ip) {
			if (arg_debug)
				printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface1.ip), cfg.interface1.dev);
			net_if_ip(cfg.interface1.dev, cfg.interface1.ip, cfg.interface1.mask, cfg.interface1.mtu);
			net_if_up(cfg.interface1.dev);
		}			
		if (cfg.interface2.configured && cfg.interface2.ip) {
			if (arg_debug)
				printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface2.ip), cfg.interface2.dev);
			net_if_ip(cfg.interface2.dev, cfg.interface2.ip, cfg.interface2.mask, cfg.interface2.mtu);
			net_if_up(cfg.interface2.dev);
		}			
		if (cfg.interface3.configured && cfg.interface3.ip) {
			if (arg_debug)
				printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface3.ip), cfg.interface3.dev);
			net_if_ip(cfg.interface3.dev, cfg.interface3.ip, cfg.interface3.mask, cfg.interface3.mtu);
			net_if_up(cfg.interface3.dev);
		}			
			
		if (arg_debug)
			printf("Network namespace enabled\n");
	}
	
	// if any dns server is configured, it is time to set it now
	fs_resolvconf();
	fs_logger_print();
	fs_logger_change_owner();

	// print network configuration
	if (!arg_quiet) {
		if (any_bridge_configured() || any_interface_configured() || cfg.defaultgw || cfg.dns1) {
			printf("\n");
			if (any_bridge_configured() || any_interface_configured())
				net_ifprint();
			if (cfg.defaultgw != 0)
				printf("Default gateway %d.%d.%d.%d\n", PRINT_IP(cfg.defaultgw));
			if (cfg.dns1 != 0)
				printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns1));
			if (cfg.dns2 != 0)
				printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns2));
			if (cfg.dns3 != 0)
				printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns3));
			printf("\n");
		}
	}
	
	fs_delete_cp_command();

	//****************************
	// set application environment
	//****************************
	prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); // kill the child in case the parent died
	int cwd = 0;
	if (cfg.cwd) {
		if (chdir(cfg.cwd) == 0)
			cwd = 1;
	}
	
	if (!cwd) {
		if (chdir("/") < 0)
			errExit("chdir");
		if (cfg.homedir) {
			struct stat s;
			if (stat(cfg.homedir, &s) == 0) {
				/* coverity[toctou] */
				if (chdir(cfg.homedir) < 0)
					errExit("chdir");
			}
		}
	}
	
	// set environment
	env_defaults();
	
	// set user-supplied environment variables
	env_apply();

	// set nice
	if (arg_nice) {
		errno = 0;
		int rv = nice(cfg.nice);
		(void) rv;
		if (errno) {
			fprintf(stderr, "Warning: cannot set nice value\n");
			errno = 0;
		}
	}
	
	// clean /tmp/.X11-unix sockets
	fs_x11();
	
	//****************************
	// set security filters
	//****************************
	// set capabilities
	if (!arg_noroot)
		set_caps();

	// set rlimits
	set_rlimits();

	// set seccomp
#ifdef HAVE_SECCOMP
	// install protocol filter
	if (cfg.protocol) {
		protocol_filter();	// install filter	
		protocol_filter_save();	// save filter in PROTOCOL_CFG
	}

	// if a keep list is available, disregard the drop list
	if (arg_seccomp == 1) {
		if (cfg.seccomp_list_keep)
			seccomp_filter_keep();
		else if (cfg.seccomp_list_errno)
			seccomp_filter_errno(); 
		else
			seccomp_filter_drop(enforce_seccomp);
	}
#endif

	// set cpu affinity
	if (cfg.cpus) {
		save_cpu(); // save cpu affinity mask to CPU_CFG file
		set_cpu_affinity();
	}
	
	// save cgroup in CGROUP_CFG file
	if (cfg.cgroup)
		save_cgroup();

	//****************************************
	// drop privileges or create a new user namespace
	//****************************************
	save_nogroups();
	if (arg_noroot) {
		int rv = unshare(CLONE_NEWUSER);
		if (rv == -1) {
			fprintf(stderr, "Error: cannot mount a new user namespace\n");
			perror("unshare");
			drop_privs(arg_nogroups);
		}
	}
	else
		drop_privs(arg_nogroups);
 	
	// notify parent that new user namespace has been created so a proper
 	// UID/GID map can be setup
 	notify_other(child_to_parent_fds[1]);
 	close(child_to_parent_fds[1]);
 
 	// wait for parent to finish setting up a proper UID/GID map
 	wait_for_other(parent_to_child_fds[0]);
 	close(parent_to_child_fds[0]);

	// somehow, the new user namespace resets capabilities;
	// we need to do them again
	if (arg_noroot) {
		set_caps();
		if (arg_debug)
			printf("noroot user namespace installed\n");
	}


	//****************************************
	// fork the application and monitor it
	//****************************************
	pid_t app_pid = fork();
	if (app_pid == -1)
		errExit("fork");
		
	if (app_pid == 0) {
		prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); // kill the child in case the parent died
		start_application();	// start app
	}

	monitor_application(app_pid);	// monitor application
	
	return 0;
}
Ejemplo n.º 28
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");
}
Ejemplo n.º 29
0
// mount /proc and /sys directories
void fs_proc_sys_dev_boot(void) {
	struct stat s;

	if (arg_debug)
		printf("Remounting /proc and /proc/sys filesystems\n");
	if (mount("proc", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0)
		errExit("mounting /proc");
	fs_logger("remount /proc");

	// remount /proc/sys readonly
	if (mount("/proc/sys", "/proc/sys", NULL, MS_BIND | MS_REC, NULL) < 0)
		errExit("mounting /proc/sys");

	if (mount(NULL, "/proc/sys", NULL, MS_BIND | MS_REMOUNT | MS_RDONLY | MS_REC, NULL) < 0)
		errExit("mounting /proc/sys");
	fs_logger("read-only /proc/sys");


	/* Mount a version of /sys that describes the network namespace */
	if (arg_debug)
		printf("Remounting /sys directory\n");
	if (umount2("/sys", MNT_DETACH) < 0)
		fprintf(stderr, "Warning: failed to unmount /sys\n");
	else {
		if (mount("sysfs", "/sys", "sysfs", MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REC, NULL) < 0)
			fprintf(stderr, "Warning: failed to mount /sys\n");
		else
			fs_logger("remount /sys");
	}
		
	if (stat("/sys/firmware", &s) == 0) {
		disable_file(BLACKLIST_FILE, "/sys/firmware");
	}
		
	if (stat("/sys/hypervisor", &s) == 0) {
		disable_file(BLACKLIST_FILE, "/sys/hypervisor");
	}

	if (stat("/sys/fs", &s) == 0) {
		disable_file(BLACKLIST_FILE, "/sys/fs");
	}

	if (stat("/sys/module", &s) == 0) {
		disable_file(BLACKLIST_FILE, "/sys/module");
	}

	if (stat("/sys/power", &s) == 0) {
		disable_file(BLACKLIST_FILE, "/sys/power");
	}

//	if (mount("sysfs", "/sys", "sysfs", MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REC, NULL) < 0)
//		errExit("mounting /sys");

	// Disable SysRq
	// a linux box can be shut down easily using the following commands (as root):
	// # echo 1 > /proc/sys/kernel/sysrq
	// #echo b > /proc/sysrq-trigger
	// for more information see https://www.kernel.org/doc/Documentation/sysrq.txt
	if (arg_debug)
		printf("Disable /proc/sysrq-trigger\n");
	fs_rdonly_noexit("/proc/sysrq-trigger");
	
	// disable hotplug and uevent_helper
	if (arg_debug)
		printf("Disable /proc/sys/kernel/hotplug\n");
	fs_rdonly_noexit("/proc/sys/kernel/hotplug");
	if (arg_debug)
		printf("Disable /sys/kernel/uevent_helper\n");
	fs_rdonly_noexit("/sys/kernel/uevent_helper");
	
	// read-only /proc/irq and /proc/bus
	if (arg_debug)
		printf("Disable /proc/irq\n");
	fs_rdonly_noexit("/proc/irq");
	if (arg_debug)
		printf("Disable /proc/bus\n");
	fs_rdonly_noexit("/proc/bus");
	
	// disable /proc/kcore
	disable_file(BLACKLIST_FILE, "/proc/kcore");

	// disable /proc/kallsyms
	disable_file(BLACKLIST_FILE, "/proc/kallsyms");
	
	// disable /boot
	if (stat("/boot", &s) == 0) {
		if (arg_debug)
			printf("Disable /boot directory\n");
		disable_file(BLACKLIST_FILE, "/boot");
	}
	
	// disable /selinux
	if (stat("/selinux", &s) == 0) {
		if (arg_debug)
			printf("Disable /selinux directory\n");
		disable_file(BLACKLIST_FILE, "/selinux");
	}
	
	// disable /dev/port
	if (stat("/dev/port", &s) == 0) {
		disable_file(BLACKLIST_FILE, "/dev/port");
	}
	
	if (getuid() != 0) {
		// disable /dev/kmsg
		if (stat("/dev/kmsg", &s) == 0) {
			disable_file(BLACKLIST_FILE, "/dev/kmsg");
		}
		
		// disable /proc/kmsg
		if (stat("/proc/kmsg", &s) == 0) {
			disable_file(BLACKLIST_FILE, "/proc/kmsg");
		}
	}
}
Ejemplo n.º 30
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");
	}
}