139 řádky
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			139 řádky
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include <vector>
 | 
						|
#include <initializer_list>
 | 
						|
#include <string.h>
 | 
						|
#include <sched.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <fstream>
 | 
						|
#include <sys/types.h>
 | 
						|
#include <sys/stat.h>
 | 
						|
#include <fcntl.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <string.h>
 | 
						|
#include <filesystem>
 | 
						|
#include <sys/mount.h>
 | 
						|
#include <sys/capability.h>
 | 
						|
#include <qssb.h>
 | 
						|
#include "../logger.h"
 | 
						|
#include "../utils.h"
 | 
						|
#include "../random.h"
 | 
						|
 | 
						|
#include "sandbox-linux.h"
 | 
						|
 | 
						|
/* TODO: make a whitelist approach. So far we simply blacklist
 | 
						|
 * obvious systemcalls. To whitelist, we need to analyse our
 | 
						|
 * dependencies (http library, sqlite wrapper, sqlite lib etc.) */
 | 
						|
 | 
						|
bool SandboxLinux::enableForInit()
 | 
						|
{
 | 
						|
	umask(0027);
 | 
						|
	struct qssb_policy *policy = qssb_init_policy();
 | 
						|
	if(policy == NULL)
 | 
						|
	{
 | 
						|
		Logger::error() << "Failed to init sandboxing policy (init)";
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
	policy->namespace_options = QSSB_UNSHARE_USER;
 | 
						|
	policy->drop_caps = 0;
 | 
						|
	qssb_append_syscall_policy(policy, QSSB_SYSCALL_DENY_KILL_PROCESS, QSSB_SYS(execveat));
 | 
						|
	qssb_append_syscall_policy(policy, QSSB_SYSCALL_DENY_KILL_PROCESS, QSSB_SYS(execve));
 | 
						|
	qssb_append_syscall_default_policy(policy, QSSB_SYSCALL_ALLOW);
 | 
						|
 | 
						|
	int result = qssb_enable_policy(policy);
 | 
						|
	if(result != 0)
 | 
						|
	{
 | 
						|
		Logger::error() << "Failed to enable sandboxing policy (init): " << result;
 | 
						|
		qssb_free_policy(policy);
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
	qssb_free_policy(policy);
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
bool SandboxLinux::enablePreWorker(std::vector<std::string> fsPaths)
 | 
						|
{
 | 
						|
	std::sort(fsPaths.begin(), fsPaths.end(),
 | 
						|
			  [](const std::string &a, const std::string &b) { return a.length() < b.length(); });
 | 
						|
 | 
						|
	struct qssb_policy *policy = qssb_init_policy();
 | 
						|
	if(policy == NULL)
 | 
						|
	{
 | 
						|
		Logger::error() << "Failed to init sandboxing policy (pre)";
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
	for(unsigned int i = 0; i < fsPaths.size(); i++)
 | 
						|
	{
 | 
						|
		qssb_append_path_policy(policy, QSSB_FS_ALLOW_READ | QSSB_FS_ALLOW_WRITE, fsPaths[i].c_str());
 | 
						|
	}
 | 
						|
 | 
						|
	policy->namespace_options = QSSB_UNSHARE_MOUNT;
 | 
						|
	policy->drop_caps = 0;
 | 
						|
	policy->mount_path_policies_to_chroot = 1;
 | 
						|
 | 
						|
	qssb_append_syscall_policy(policy, QSSB_SYSCALL_DENY_KILL_PROCESS, QSSB_SYS(execveat));
 | 
						|
	qssb_append_syscall_policy(policy, QSSB_SYSCALL_DENY_KILL_PROCESS, QSSB_SYS(execve));
 | 
						|
	qssb_append_syscall_default_policy(policy, QSSB_SYSCALL_ALLOW);
 | 
						|
 | 
						|
	int result = qssb_enable_policy(policy);
 | 
						|
	if(result != 0)
 | 
						|
	{
 | 
						|
		Logger::error() << "Failed to install sandboxing policy (preworker): %i" << result;
 | 
						|
		qssb_free_policy(policy);
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
	qssb_free_policy(policy);
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
bool SandboxLinux::supported()
 | 
						|
{
 | 
						|
	std::fstream stream;
 | 
						|
	stream.open("/proc/sys/kernel/unprivileged_userns_clone");
 | 
						|
	if(stream.is_open())
 | 
						|
	{
 | 
						|
		std::string str;
 | 
						|
		stream >> str;
 | 
						|
		if(str[0] == '0')
 | 
						|
		{
 | 
						|
			Logger::error() << "Please write '1' to /proc/sys/kernel/unprivileged_userns_clone in order to enable "
 | 
						|
							   "sandboxing support on this system";
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return true;
 | 
						|
}
 | 
						|
bool SandboxLinux::enableForWorker()
 | 
						|
{
 | 
						|
	struct qssb_policy *policy = qssb_init_policy();
 | 
						|
	if(policy == NULL)
 | 
						|
	{
 | 
						|
		Logger::error() << "Failed to init sandboxing policy (worker) ";
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
	policy->drop_caps = 1;
 | 
						|
	policy->not_dumpable = 1;
 | 
						|
	policy->no_new_privs = 1;
 | 
						|
	policy->namespace_options = 0;
 | 
						|
 | 
						|
	/* TODO: as said, a whitelist approach is better. As such, this list is bound to be incomplete in the
 | 
						|
	 * sense that more could be listed here and some critical ones are probably missing */
 | 
						|
 | 
						|
	/* TODO: use qssb groups */
 | 
						|
	long blacklisted_syscalls[] = {QSSB_SYS(setuid),	  QSSB_SYS(connect), QSSB_SYS(chroot),	QSSB_SYS(pivot_root),
 | 
						|
								   QSSB_SYS(mount),		  QSSB_SYS(setns),	 QSSB_SYS(unshare), QSSB_SYS(ptrace),
 | 
						|
								   QSSB_SYS(personality), QSSB_SYS(prctl)};
 | 
						|
 | 
						|
	qssb_append_syscalls_policy(policy, QSSB_SYSCALL_DENY_KILL_PROCESS, blacklisted_syscalls,
 | 
						|
								sizeof(blacklisted_syscalls) / sizeof(blacklisted_syscalls[0]));
 | 
						|
	qssb_append_syscall_default_policy(policy, QSSB_SYSCALL_ALLOW);
 | 
						|
 | 
						|
	if(qssb_enable_policy(policy) != 0)
 | 
						|
	{
 | 
						|
		Logger::error() << "Sandbox: Activation of seccomp blacklist failed!";
 | 
						|
		qssb_free_policy(policy);
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
	qssb_free_policy(policy);
 | 
						|
	return true;
 | 
						|
}
 |