qswiki/sandbox/sandbox-linux.cpp

118 lines
3.2 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 = {0};
int blacklisted_syscalls[] = {QSSB_SYS(execveat), QSSB_SYS(execve), -1};
policy.blacklisted_syscalls = blacklisted_syscalls;
policy.no_new_privs = 1;
int result = qssb_enable_policy(&policy);
if(result != 0)
{
Logger::error() << "Failed to install sandboxing policy (init): " << result;
return false;
}
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_path_policy *policies = new qssb_path_policy[fsPaths.size()];
for(unsigned int i = 0; i < fsPaths.size(); i++)
{
policies[i].next = policies + (i + 1);
policies[i].mountpoint = fsPaths[i].c_str();
policies[i].policy = QSSB_MOUNT_ALLOW_READ | QSSB_MOUNT_ALLOW_WRITE;
}
policies[fsPaths.size() - 1].next = NULL;
struct qssb_policy policy = {0};
policy.path_policies = policies;
policy.namespace_options |= QSSB_UNSHARE_MOUNT;
policy.namespace_options |= QSSB_UNSHARE_USER;
int blacklisted_syscalls[] = {QSSB_SYS(execveat), QSSB_SYS(execve), -1};
policy.blacklisted_syscalls = blacklisted_syscalls;
int result = qssb_enable_policy(&policy);
if(result != 0)
{
Logger::error() << "Failed to install sandboxing policy (preworker): %i" << result;
return false;
}
delete[] policies;
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 = {0};
policy.drop_caps = 1;
policy.not_dumpable = 1;
policy.no_new_privs = 1;
/* 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 */
int 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),
-1};
policy.blacklisted_syscalls = blacklisted_syscalls;
if(qssb_enable_policy(&policy) != 0)
{
Logger::error() << "Sandbox: Activation of seccomp blacklist failed!";
return false;
}
return true;
}