示例#1
0
文件: ct.c 项目: mkatkar/libct
static int try_mount_proc(struct container *ct)
{
	/* Not requested by user */
	if (!(ct->flags & CT_AUTO_PROC))
		return 0;

	/* Container w/o pidns can work on existing proc */
	if (!(ct->nsmask & CLONE_NEWPID) && !ct->root_path)
		return 0;

	/* Container with shared FS has no place for new proc */
	if (!fs_private(ct))
		return -1;

	return re_mount_proc(ct);
}
示例#2
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);
}
示例#3
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;
}
示例#4
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();
	}
	
	//****************************
	// netfilter
	//****************************
	if (arg_netfilter && any_bridge_configured()) { // assuming by default the client filter
		netfilter(arg_netfilter_file);
	}

	//****************************
	// trace pre-install
	//****************************
	if (arg_trace)
		fs_trace_preload();

	//****************************
	// configure filesystem
	//****************************
	
#ifdef HAVE_CHROOT		
	if (cfg.chrootdir) {
		fs_chroot(cfg.chrootdir);
		// 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;
			if (arg_seccomp_list_drop) {
				free(arg_seccomp_list_drop);
				arg_seccomp_list_drop = NULL;
			}
			if (arg_seccomp_list_keep) {
				free(arg_seccomp_list_keep);
				arg_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;
			printf("Dropping all Linux capabilities and enforcing default seccomp filter\n");
		}
						
		//****************************
		// trace pre-install, this time inside chroot
		//****************************
		if (arg_trace)
			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);
	}
	
	//****************************
	// apply the profile file
	//****************************
	if (cfg.profile)
		fs_blacklist(cfg.homedir);
	
	//****************************
	// private mode
	//****************************
	if (arg_private) {
		if (cfg.home_private)	// --private=
			fs_private_homedir();
		else if (cfg.home_private_keep) // --private-home=
			fs_private_home_list();
		else // --private
			fs_private();
	}
	
	if (arg_private_dev)
		fs_private_dev();
	if (arg_private_etc)
		fs_private_etc_list();
	
	//****************************
	// install trace
	//****************************
	if (arg_trace)
		fs_trace();
		
	//****************************
	// update /proc, /dev, /boot directorymy
	//****************************
	fs_proc_sys_dev_boot();
	
	//****************************
	// 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()) {
		// 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");
		}
			
		if (arg_debug)
			printf("Network namespace enabled\n");
	}
	
	// if any dns server is configured, it is time to set it now
	fs_resolvconf();

	// print network configuration
	if (any_bridge_configured() || cfg.defaultgw || cfg.dns1) {
		printf("\n");
		if (any_bridge_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");
	}
	
	

	//****************************
	// start executable
	//****************************
	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
	// fix qt 4.8
	if (setenv("QT_X11_NO_MITSHM", "1", 1) < 0)
		errExit("setenv");
	if (setenv("container", "firejail", 1) < 0) // LXC sets container=lxc,
		errExit("setenv");
	if (arg_zsh && setenv("SHELL", "/usr/bin/zsh", 1) < 0)
		errExit("setenv");
	if (arg_csh && setenv("SHELL", "/bin/csh", 1) < 0)
		errExit("setenv");
	if (cfg.shell && setenv("SHELL", cfg.shell, 1) < 0)
		errExit("setenv");
	// set prompt color to green
	//export PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\] '
	if (setenv("PROMPT_COMMAND", "export PS1=\"\\[\\e[1;32m\\][\\u@\\h \\W]\\$\\[\\e[0m\\] \"", 1) < 0)
		errExit("setenv");
	// set user-supplied environment variables
	env_apply();

	// set capabilities
	if (!arg_noroot)
		set_caps();

	// set rlimits
	set_rlimits();

	// set seccomp
#ifdef HAVE_SECCOMP
	// if a keep list is available, disregard the drop list
	if (arg_seccomp == 1) {
		if (arg_seccomp_list_keep)
			seccomp_filter_keep(); // this will also save the fmyilter to MNT_DIR/seccomp file
		else
			seccomp_filter_drop(); // this will also save the filter to MNT_DIR/seccomp file
	}
#endif

	// set cpu affinity
	if (cfg.cpus) {
		save_cpu(); // save cpu affinity mask to MNT_DIR/cpu file
		set_cpu_affinity();
	}
	
	// save cgroup in MNT_DIR/cgroup 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("User namespace (noroot) installed\n");
	}


	//****************************************
	// start the program without using a shell
	//****************************************
	if (arg_shell_none) {
		if (arg_debug) {
			int i;
			for (i = cfg.original_program_index; i < cfg.original_argc; i++) {
				if (cfg.original_argv[i] == NULL)
					break;
				printf("execvp argument %d: %s\n", i - cfg.original_program_index, cfg.original_argv[i]);
			}
		}

		if (!arg_command)
			printf("Child process initialized\n");
		execvp(cfg.original_argv[cfg.original_program_index], &cfg.original_argv[cfg.original_program_index]);
	}
	//****************************************
	// start the program using a shell
	//****************************************
	else {
		// choose the shell requested by the user, or use bash as default
		char *sh;
		if (cfg.shell)
	 		sh = cfg.shell;
		else if (arg_zsh)
			sh = "/usr/bin/zsh";
		else if (arg_csh)
			sh = "/bin/csh";
		else
			sh = "/bin/bash";
			
		char *arg[5];
		int index = 0;
		arg[index++] = sh;
		arg[index++] = "-c";
		assert(cfg.command_line);
		if (arg_debug)
			printf("Starting %s\n", cfg.command_line);
		if (arg_doubledash) 
			arg[index++] = "--";
		arg[index++] = cfg.command_line;
		arg[index] = NULL;
		assert(index < 5);
		
		if (arg_debug) {
			char *msg;
			if (asprintf(&msg, "sandbox %d, execvp into %s", sandbox_pid, cfg.command_line) == -1)
				errExit("asprintf");
			logmsg(msg);
			free(msg);
		}
		
		if (arg_debug) {
			int i;
			for (i = 0; i < 5; i++) {
				if (arg[i] == NULL)
					break;
				printf("execvp argument %d: %s\n", i, arg[i]);
			}
		}
		
		if (!arg_command)
			printf("Child process initialized\n");
		execvp(sh, arg);
	}
	

	perror("execvp");
	return 0;
}
示例#5
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);
}
示例#6
0
文件: sandbox.c 项目: spnow/firejail
int sandbox(void* sandbox_arg) {
	if (arg_debug)
		printf("Initializing child process\n");	

	//****************************
	// wait for the parent to be initialized
	//****************************
	char childstr[BUFLEN + 1];
	FILE* stream;
	close(fds[1]);
	stream = fdopen(fds[0], "r");
	*childstr = '\0';
	if (fgets(childstr, BUFLEN, stream)) {
		// remove \n
		char *ptr = childstr;
		while(*ptr !='\0' && *ptr != '\n')
			ptr++;
		if (*ptr == '\0')
			errExit("fgets");
		*ptr = '\0';
	}
	else {
		fprintf(stderr, "Error: cannot establish communication with the parent, exiting...\n");
		exit(1);
	}
	close(fds[0]);
	if (arg_debug && getpid() == 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) {
		// if we are starting firejail inside firejail, we don't care about this
		char *mycont = getenv("container");
		if (mycont == NULL)
			errExit("mounting filesystem as slave");
		if (strcmp(mycont, "firejail") != 0)
			errExit("mounting filesystem as slave");
	}
	
	//****************************
	// trace pre-install
	//****************************
	if (arg_trace)
		fs_trace_preload();

	//****************************
	// configure filesystem
	//****************************
	int drop_caps = 0;
	if (cfg.chrootdir) {
		fs_chroot(cfg.chrootdir);
		// force caps and seccomp if not started as root
		if (getuid() != 0) {
			arg_seccomp = 1;
			arg_caps = 0;
			drop_caps = 1;
			printf("Dropping all Linux capabilities and enforcing default seccomp filter\n");
		}
						
		//****************************
		// trace pre-install, this time inside chroot
		//****************************
		if (arg_trace)
			fs_trace_preload();
	}
	else if (arg_overlay)
		fs_overlayfs();
	else
		fs_basic_fs();
	

	//****************************
	// set hostname in /etc/hostname
	//****************************
	if (cfg.hostname) {
		fs_hostname(cfg.hostname);
	}
	
	//****************************
	// apply the profile file
	//****************************
	if (cfg.profile)
		fs_blacklist(cfg.homedir);
	
	//****************************
	// private mode
	//****************************
	if (arg_private) {
		if (cfg.home_private)
			fs_private_home();
		else
			fs_private();
	}
	
	//****************************
	// install trace
	//****************************
	if (arg_trace)
		fs_trace();
		
	//****************************
	// update /proc, /dev, /boot directory
	//****************************
	fs_proc_sys_dev_boot();
	
	//****************************
	// networking
	//****************************
	if (arg_nonetwork) {
		net_if_up("lo");
	}
	else if (arg_noip) {
		net_if_up("lo");
		if (cfg.bridge0.configured)
			net_if_up("eth0");
		if (cfg.bridge1.configured)
			net_if_up("eth1");
		if (cfg.bridge2.configured)
			net_if_up("eth2");
		if (cfg.bridge3.configured)
			net_if_up("eth3");
	}
	else if (any_bridge_configured()) {
		// configure lo and eth0...eth3
		net_if_up("lo");
		if (cfg.bridge0.configured) {
			Bridge *br = &cfg.bridge0;
			net_if_up("eth0");
			assert(br->ipaddress);
			if (arg_debug)
				printf("Configuring %d.%d.%d.%d address on interface eth0\n", PRINT_IP(br->ipaddress));
			net_if_ip("eth0", br->ipaddress, br->mask);
			net_if_up("eth0");
		}
		if (cfg.bridge1.configured) {
			Bridge *br = &cfg.bridge1;
			net_if_up("eth1");
			assert(br->ipaddress);
			if (arg_debug)
				printf("Configuring %d.%d.%d.%d address on interface eth1\n", PRINT_IP(br->ipaddress));
			net_if_ip("eth1", br->ipaddress, br->mask);
			net_if_up("eth1");
		}
		if (cfg.bridge2.configured) {
			Bridge *br = &cfg.bridge2;
			net_if_up("eth2");
			assert(br->ipaddress);
			if (arg_debug)
				printf("Configuring %d.%d.%d.%d address on interface eth2\n", PRINT_IP(br->ipaddress));
			net_if_ip("eth2", br->ipaddress, br->mask);
			net_if_up("eth2");
		}
		if (cfg.bridge3.configured) {
			Bridge *br = &cfg.bridge3;
			net_if_up("eth3");
			assert(br->ipaddress);
			if (arg_debug)
				printf("Configuring %d.%d.%d.%d address on interface eth3\n", PRINT_IP(br->ipaddress));
			net_if_ip("eth3", br->ipaddress, br->mask);
			net_if_up("eth3");
		}
		
		// add a default route
		if (!cfg.defaultgw) {
			// set the default route as IP address of first bridge
			cfg.defaultgw = cfg.bridge0.ip;
			if (arg_debug)
				printf("Using first bridge address as default route\n");
		}
		if (net_add_route(0, 0, cfg.defaultgw))
			fprintf(stderr, "Warning: cannot configure default route\n");
			
		if (arg_debug)
			printf("Network namespace enabled\n");
	}
	net_ifprint();
	
	//****************************
	// start executable
	//****************************
	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) {
				if (chdir(cfg.homedir) < 0)
					errExit("chdir");
			}
		}
	}
	
	// set environment
	// fix qt 4.8
	if (setenv("QT_X11_NO_MITSHM", "1", 1) < 0)
		errExit("setenv");
	if (setenv("container", "firejail", 1) < 0) // LXC sets container=lxc,
		errExit("setenv");
	if (arg_zsh && setenv("SHELL", "/usr/bin/zsh", 1) < 0)
		errExit("setenv");
	if (arg_csh && setenv("SHELL", "/bin/csh", 1) < 0)
		errExit("setenv");
	if (cfg.shell && setenv("SHELL", cfg.shell, 1) < 0)
		errExit("setenv");
	// set prompt color to green
	//export PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\] '
	if (setenv("PROMPT_COMMAND", "export PS1=\"\\[\\e[1;32m\\][\\u@\\h \\W]\\$\\[\\e[0m\\] \"", 1) < 0)
		errExit("setenv");
		

	// set capabilities
	if (arg_caps == 1)
		caps_filter();
	if (drop_caps)
		caps_drop_all();

	// set rlimits
	set_rlimits();

	// set seccomp
#ifdef HAVE_SECCOMP
	if (arg_seccomp == 1)
		seccomp_filter();
#endif

	// drop privileges
	drop_privs();
	
		
	// set the shell
	char *sh;
	if (cfg.shell)
 		sh = cfg.shell;
	else if (arg_zsh)
		sh = "/usr/bin/zsh";
	else if (arg_csh)
		sh = "/bin/csh";
	else
		sh = "/bin/bash";
		
	char *arg[4];
	arg[0] = sh;
	arg[1] = "-c";
	assert(cfg.command_line);
	if (arg_debug)
		printf("Starting %s\n", cfg.command_line);
	arg[2] = cfg.command_line;
	arg[3] = NULL;

	if (!arg_command)
		printf("Child process initialized\n");
	if (arg_debug) {
		char *msg;
		if (asprintf(&msg, "child pid %s, execvp into %s", childstr, cfg.command_line) == -1)
			errExit("asprintf");
		logmsg(msg);
		free(msg);
	}
	execvp(sh, arg); 

	perror("execvp");
	return 0;
}
示例#7
0
// whitelist for /home/user directory
void fs_whitelist(void) {
	char *homedir = cfg.homedir;
	assert(homedir);
	ProfileEntry *entry = cfg.profile;
	if (!entry)
		return;
	
	// realpath function will fail with ENOENT if the file is not found
	// we need to expand the path before installing a new, empty home directory
	while (entry) {
		// handle only whitelist commands
		if (strncmp(entry->data, "whitelist ", 10)) {
			entry = entry->next;
			continue;
		}

		char *new_name = expand_home(entry->data + 10, cfg.homedir);
		assert(new_name);
		char *fname = realpath(new_name, NULL);
		free(new_name);
		if (fname) {
			// 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);
		}
		else {
			// file not found, blank the entry in the list
			if (arg_debug)
				printf("Removed whitelist path: %s\n", entry->data);
			*entry->data = '\0';
		}
		entry = entry->next;
	}
		
	// create /tmp/firejail/mnt/whome directory
	fs_build_mnt_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");

	// keep a copy of real home dir in /tmp/firejail/mnt/whome
	if (mount(cfg.homedir, WHITELIST_HOME_DIR, NULL, MS_BIND|MS_REC, NULL) < 0)
		errExit("mount bind");

	// start building the new home directory by mounting a tmpfs fielsystem
	 fs_private();

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

		whitelist_path(entry->data + 10);

		entry = entry->next;
	}

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