Begin sandboxing support, README updates.
Tento commit je obsažen v:
		
							
								
								
									
										4
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								Makefile
									
									
									
									
									
								
							@@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
CXXFLAGS=-std=c++17 -O0 -g -no-pie -pipe -MMD -Wall -Wextra
 | 
			
		||||
RELEASE_CXXFLAGS=-std=c++17 -O3 -pipe -MMD -Wall -Wextra
 | 
			
		||||
LDFLAGS=-lsqlite3 -lpthread -lcrypto -lboost_regex -lstdc++fs
 | 
			
		||||
LDFLAGS=-lsqlite3 -lpthread -lcrypto -lboost_regex -lstdc++fs -lseccomp
 | 
			
		||||
 | 
			
		||||
CXX=g++
 | 
			
		||||
 | 
			
		||||
@@ -12,12 +12,14 @@ SOURCES+=$(wildcard gateway/*.cpp)
 | 
			
		||||
SOURCES+=$(wildcard handlers/*.cpp)
 | 
			
		||||
SOURCES+=$(wildcard database/*.cpp)
 | 
			
		||||
SOURCES+=$(wildcard cache/*.cpp) 
 | 
			
		||||
SOURCES+=$(wildcard sandbox/*.cpp) 
 | 
			
		||||
 | 
			
		||||
HEADERS=$(wildcard *.h)
 | 
			
		||||
HEADERS+=$(wildcard gateway/*.h)
 | 
			
		||||
HEADERS+=$(wildcard handlers/*.h)
 | 
			
		||||
HEADERS+=$(wildcard database/*.h)
 | 
			
		||||
HEADERS+=$(wildcard cache/*.h) 
 | 
			
		||||
HEADERS+=$(wildcard sandbox/*.h) 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
OBJECTS=$(patsubst %.cpp, %.o, $(SOURCES))
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										58
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								README.md
									
									
									
									
									
								
							@@ -9,35 +9,40 @@ History
 | 
			
		||||
====
 | 
			
		||||
A couple of years ago, I wanted to setup a personal wiki on my raspberry 
 | 
			
		||||
pi. However, the distribution I used back then did not have a PHP package 
 | 
			
		||||
for ARM. So I decided I would write one in C. Yes, that's an odd way 
 | 
			
		||||
to approach the problem and indeed, I may have had too much time back 
 | 
			
		||||
then. Also, I wanted to see how it's like to write a "web app" in C 
 | 
			
		||||
and wanted to sharpen my C a little bit.
 | 
			
		||||
for ARM. So instead of switching distributions or searching for other
 | 
			
		||||
wikis that I could use, I decided I would write one in C. Yes, 
 | 
			
		||||
that's an odd way  to approach the problem and indeed, I may have had too 
 | 
			
		||||
much time back  then. Also, I wanted to see how it's like to write a 
 | 
			
		||||
"web app" in C and wanted to sharpen my C skills a little bit.
 | 
			
		||||
 | 
			
		||||
Of course, it's pretty straightforward at first. No really. Just use CGI. 
 | 
			
		||||
And indeed, that's probably more than enough. Then I decided to play 
 | 
			
		||||
around and started using FastCGI (with the official library from now 
 | 
			
		||||
defunct fastcgi.com) and created a multi-threaded version. It initially 
 | 
			
		||||
used a "pile of files database", but that became too painful, so then 
 | 
			
		||||
I started using sqlite.
 | 
			
		||||
Of course, it's pretty straightforward at first. No really: Just use CGI. 
 | 
			
		||||
And indeed, that would have been more than enough for my use cases. 
 | 
			
		||||
Then I decided to play around and started using FastCGI (with the official 
 | 
			
		||||
library from now  defunct fastcgi.com) and created a multi-threaded version.
 | 
			
		||||
It initially  used a "pile of files database", but that became too painful, 
 | 
			
		||||
so then I started using sqlite.
 | 
			
		||||
 | 
			
		||||
C++
 | 
			
		||||
---
 | 
			
		||||
Eventually the code became unmaintainable. Initially, I wanted something 
 | 
			
		||||
quick. I did not care about memory leaks (as it was CGI initially). 
 | 
			
		||||
After FastCGI, they became an issue. In the end, the task of avoiding
 | 
			
		||||
memory leaks became too annoying. And of course, C does not include any 
 | 
			
		||||
"batteries" and while I could manage, this too was another good reason.
 | 
			
		||||
Eventually, since it was mostly a playground for me, the code became 
 | 
			
		||||
unmaintainable. Furthermore, I wanted something quick and given that 
 | 
			
		||||
it was CGI, I didn't bother taking care of memory leaks. 
 | 
			
		||||
After initiating a FastCGI interface, they became an issue and then the 
 | 
			
		||||
task of avoiding memory leaks became too annoying. And of course, C does n
 | 
			
		||||
ot include any "batteries" and while I could manage, this too was another 
 | 
			
		||||
good reason.
 | 
			
		||||
 | 
			
		||||
Overall, I am just continuing the experiment with C++17 now. It's not 
 | 
			
		||||
nearly as bad as you would expect perhaps. Some things are surprisingly 
 | 
			
		||||
convenient even. Still, the standard library is lacking and 
 | 
			
		||||
I would hope for a some better built-in Unicode support in the future.
 | 
			
		||||
I would hope for a some better built-in Unicode support in future C++ 
 | 
			
		||||
standards.
 | 
			
		||||
 | 
			
		||||
Features
 | 
			
		||||
========
 | 
			
		||||
To be fair, at this point it doesn't even have a "diff" between revisions 
 | 
			
		||||
yet and does not have features that make you prefer it over other wikis.
 | 
			
		||||
yet and does not have features that would make you prefer it over other 
 | 
			
		||||
wikis.
 | 
			
		||||
 | 
			
		||||
 - CGI
 | 
			
		||||
 - HTTP server using the header only library cpp-httplib. It's more 
 | 
			
		||||
@@ -55,23 +60,26 @@ yet and does not have features that make you prefer it over other wikis.
 | 
			
		||||
 | 
			
		||||
Security
 | 
			
		||||
========
 | 
			
		||||
The most reasonable way would have been to add some sort sandboxing 
 | 
			
		||||
support right away, but this is lacking so far. As for "web security", 
 | 
			
		||||
all POST requests are centrally protected against CSRF attacks and all 
 | 
			
		||||
input is escaped against XSS attacks.
 | 
			
		||||
On Linux namespaces are used to restrict the process to only access
 | 
			
		||||
files it needs. It doesn't have access to other paths in the system.
 | 
			
		||||
In addition, Seccomp is used to restrict the syscalls the qswiki process
 | 
			
		||||
can call.  As for "web security", all POST requests are centrally
 | 
			
		||||
protected against CSRF attacks and all input is escaped against XSS 
 | 
			
		||||
attacks.
 | 
			
		||||
 | 
			
		||||
Building
 | 
			
		||||
========
 | 
			
		||||
Dependencies:
 | 
			
		||||
  - cpp-httplib: https://github.com/yhirose/cpp-httplib
 | 
			
		||||
  - SqliteModernCpp: https://github.com/SqliteModernCpp
 | 
			
		||||
 
 | 
			
		||||
Given the fact those are header-only libraries, they are already
 | 
			
		||||
included here, so you only need to run: 
 | 
			
		||||
  - libseccomp: https://github.com/seccomp/libseccomp
 | 
			
		||||
  - sqlite3: https://sqlite.org/index.html
 | 
			
		||||
    
 | 
			
		||||
The first two are header-only libraries that are already included here.
 | 
			
		||||
 | 
			
		||||
If all dependencies are available, run:
 | 
			
		||||
```make release```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Setup
 | 
			
		||||
=====
 | 
			
		||||
To be written
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								cache/fscache.cpp
									
									
									
									
										vendorováno
									
									
								
							
							
						
						
									
										2
									
								
								cache/fscache.cpp
									
									
									
									
										vendorováno
									
									
								
							@@ -7,7 +7,7 @@ FsCache::FsCache(std::string path)
 | 
			
		||||
{
 | 
			
		||||
	if(!std::filesystem::exists(path))
 | 
			
		||||
	{
 | 
			
		||||
		throw std::runtime_error{"Directory does not exist"};
 | 
			
		||||
		throw std::runtime_error{"Cache directory does not exist"};
 | 
			
		||||
	}
 | 
			
		||||
	this->path = path;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										34
									
								
								qswiki.cpp
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								qswiki.cpp
									
									
									
									
									
								
							@@ -24,6 +24,7 @@ SOFTWARE.
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <filesystem>
 | 
			
		||||
#include "gateway/gatewayinterface.h"
 | 
			
		||||
#include "gateway/gatewayfactory.h"
 | 
			
		||||
#include "handlers/handlerfactory.h"
 | 
			
		||||
@@ -35,6 +36,7 @@ SOFTWARE.
 | 
			
		||||
#include "urlprovider.h"
 | 
			
		||||
#include "requestworker.h"
 | 
			
		||||
#include "cache/fscache.h"
 | 
			
		||||
#include "sandbox/sandboxfactory.h"
 | 
			
		||||
void sigterm_handler(int arg)
 | 
			
		||||
{
 | 
			
		||||
	// TODO: proper shutdown.
 | 
			
		||||
@@ -68,6 +70,19 @@ int main(int argc, char **argv)
 | 
			
		||||
		std::cerr << "Do not run this as root!" << std::endl;
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
	auto sandbox = createSandbox();
 | 
			
		||||
	// TODO: do we want to keep it mandatory or configurable?
 | 
			
		||||
	if(!sandbox->supported())
 | 
			
		||||
	{
 | 
			
		||||
		Logger::error() << "Sandbox is not supported, exiting";
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
	}
 | 
			
		||||
	if(!sandbox->enableForInit())
 | 
			
		||||
	{
 | 
			
		||||
		Logger::error() << "Sandboxing for init mode could not be activated.";
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(argc < 2)
 | 
			
		||||
	{
 | 
			
		||||
		std::cerr << "no path to config file provided" << std::endl;
 | 
			
		||||
@@ -79,6 +94,19 @@ int main(int argc, char **argv)
 | 
			
		||||
		ConfigReader configreader(argv[1]);
 | 
			
		||||
		Config config = configreader.readConfig();
 | 
			
		||||
 | 
			
		||||
		// TODO: config.connectiontring only works as long as we only support sqlite of course
 | 
			
		||||
 | 
			
		||||
		if(!sandbox->enablePreWorker({
 | 
			
		||||
			   config.getConfig("cache_fs_dir"),
 | 
			
		||||
			   config.templatepath,
 | 
			
		||||
			   std::filesystem::path(config.logfile).parent_path(),
 | 
			
		||||
			   std::filesystem::path(config.connectionstring).parent_path(),
 | 
			
		||||
		   }))
 | 
			
		||||
		{
 | 
			
		||||
			Logger::error() << "Sandboxing for pre worker stage could not be activated.";
 | 
			
		||||
			exit(EXIT_FAILURE);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		setup_signal_handlers();
 | 
			
		||||
 | 
			
		||||
		std::fstream logstream;
 | 
			
		||||
@@ -110,6 +138,12 @@ int main(int argc, char **argv)
 | 
			
		||||
		RequestWorker requestWorker(*database, siteTemplate, urlprovider, *cache);
 | 
			
		||||
 | 
			
		||||
		auto interface = createGateway(config);
 | 
			
		||||
 | 
			
		||||
		if(!sandbox->enableForWorker())
 | 
			
		||||
		{
 | 
			
		||||
			Logger::error() << "Sandboxing for worker could not be enabled!";
 | 
			
		||||
			exit(EXIT_FAILURE);
 | 
			
		||||
		}
 | 
			
		||||
		interface->work(requestWorker);
 | 
			
		||||
	}
 | 
			
		||||
	catch(const std::exception &e)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										256
									
								
								sandbox/sandbox-linux.cpp
									
									
									
									
									
										Normální soubor
									
								
							
							
						
						
									
										256
									
								
								sandbox/sandbox-linux.cpp
									
									
									
									
									
										Normální soubor
									
								
							@@ -0,0 +1,256 @@
 | 
			
		||||
#include <sys/prctl.h>
 | 
			
		||||
#include <seccomp.h>
 | 
			
		||||
#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 "../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.) */
 | 
			
		||||
 | 
			
		||||
/* TODO: cleanup our sandboxing directory (unmount and delete folders) after exit */
 | 
			
		||||
bool SandboxLinux::seccomp_blacklist(std::initializer_list<int> syscalls)
 | 
			
		||||
{
 | 
			
		||||
	scmp_filter_ctx ctx;
 | 
			
		||||
	ctx = seccomp_init(SCMP_ACT_ALLOW);
 | 
			
		||||
	if(ctx == NULL)
 | 
			
		||||
	{
 | 
			
		||||
		Logger::error() << "failed to init seccomp_init";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for(auto sc : syscalls)
 | 
			
		||||
	{
 | 
			
		||||
		if(seccomp_rule_add(ctx, SCMP_ACT_KILL_PROCESS, sc, 0) < 0)
 | 
			
		||||
		{
 | 
			
		||||
			Logger::error() << "Failed to add a seccomp rule";
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool success = seccomp_load(ctx) == 0;
 | 
			
		||||
	if(!success)
 | 
			
		||||
	{
 | 
			
		||||
		Logger::error() << "Failed to load seccomp filter";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	return success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SandboxLinux::bindMountPaths(std::string target_root, std::initializer_list<std::string> paths)
 | 
			
		||||
{
 | 
			
		||||
	for(const std::string &path : paths)
 | 
			
		||||
	{
 | 
			
		||||
		std::string chroot_target_path = target_root + path;
 | 
			
		||||
		if(std::filesystem::exists(chroot_target_path))
 | 
			
		||||
		{
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		if(std::filesystem::is_regular_file(path))
 | 
			
		||||
		{
 | 
			
		||||
			std::fstream f1;
 | 
			
		||||
			f1.open(chroot_target_path, std::ios::out);
 | 
			
		||||
			f1.close();
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			std::error_code ec;
 | 
			
		||||
			// TODO: fails if the stuff already exists, but it shouldn't according to doc?
 | 
			
		||||
			if(!std::filesystem::create_directories(chroot_target_path, ec))
 | 
			
		||||
			{
 | 
			
		||||
				Logger::error() << "Error while trying to duplicate structure for sandbox. Dir creation failed. Path: "
 | 
			
		||||
								<< chroot_target_path << " Error: " << ec.message();
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if(mount(path.c_str(), chroot_target_path.c_str(), NULL, MS_BIND, NULL) == -1)
 | 
			
		||||
			{
 | 
			
		||||
				Logger::error() << "Bind mount failed! " << strerror(errno);
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SandboxLinux::isolateNamespaces(std::vector<std::string> fsPaths)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	auto current_uid = getuid();
 | 
			
		||||
	auto current_gid = getgid();
 | 
			
		||||
	if(unshare(CLONE_NEWUSER) == -1)
 | 
			
		||||
	{
 | 
			
		||||
		Logger::error() << "Failed to unshare user namespace: " << strerror(errno);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::fstream setgroups;
 | 
			
		||||
	setgroups.open("/proc/self/setgroups", std::ios::out | std::ios::app);
 | 
			
		||||
	setgroups << "deny";
 | 
			
		||||
	setgroups.flush();
 | 
			
		||||
	setgroups.close();
 | 
			
		||||
 | 
			
		||||
	std::fstream uid_map;
 | 
			
		||||
	uid_map.open("/proc/self/uid_map", std::ios::out | std::ios::app);
 | 
			
		||||
	uid_map << "0 " << current_uid << " 1\n";
 | 
			
		||||
	uid_map.flush();
 | 
			
		||||
	uid_map.close();
 | 
			
		||||
 | 
			
		||||
	std::fstream gid_map;
 | 
			
		||||
	gid_map.open("/proc/self/gid_map", std::ios::out);
 | 
			
		||||
	uid_map << "0 " << current_gid << " 1\n";
 | 
			
		||||
	gid_map.flush();
 | 
			
		||||
	gid_map.close();
 | 
			
		||||
 | 
			
		||||
	if(unshare(CLONE_NEWNS) == -1)
 | 
			
		||||
	{
 | 
			
		||||
		Logger::error() << "Failed to unshare mount namespace: " << strerror(errno);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * TODO: breaks server.
 | 
			
		||||
	 * TODO: fork?
 | 
			
		||||
	 * if(unshare(CLONE_NEWPID) == -1)
 | 
			
		||||
	{
 | 
			
		||||
		Logger::error() << "Failed to unshare pid namespace: " << strerror(errno);
 | 
			
		||||
		return false;
 | 
			
		||||
	}*/
 | 
			
		||||
 | 
			
		||||
	// The purpose is to start with a clean sandbox dir.
 | 
			
		||||
	// We maybe could work with mkdirat, and check whether it exists alrady, to avoid
 | 
			
		||||
	// some attacks where an attacker gueses the dir, but in that case the system is already compromised
 | 
			
		||||
	// TODO: still, check, whether this is something we must consider here or not...
 | 
			
		||||
	Random random;
 | 
			
		||||
	std::string rootpath = "/tmp/qswiki_sandbox_" + random.getRandomHexString(10) + "/";
 | 
			
		||||
	if(!std::filesystem::create_directory(rootpath))
 | 
			
		||||
	{
 | 
			
		||||
		Logger::error() << "Failed to create chroot directory for sandbox";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for(std::string &path : fsPaths)
 | 
			
		||||
	{
 | 
			
		||||
		if(!bindMountPaths(rootpath, {path}))
 | 
			
		||||
		{
 | 
			
		||||
			Logger::error() << "Bind mount for " << path << " failed!";
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(chroot(rootpath.c_str()) == -1)
 | 
			
		||||
	{
 | 
			
		||||
		Logger::error() << "chroot to sandbox failed!";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	if(chdir("/") == -1)
 | 
			
		||||
	{
 | 
			
		||||
		Logger::error() << "chdir to sandbox failed!";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SandboxLinux::enableForInit()
 | 
			
		||||
{
 | 
			
		||||
	umask(0027);
 | 
			
		||||
 | 
			
		||||
	// TODO. there is execv for SPARC. Sigh...
 | 
			
		||||
	if(!seccomp_blacklist({SCMP_SYS(execveat), SCMP_SYS(execve)}))
 | 
			
		||||
	{
 | 
			
		||||
		Logger::error() << "Failed to install blacklisting seccomp filter";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SandboxLinux::enablePreWorker(std::vector<std::string> fsPaths)
 | 
			
		||||
{
 | 
			
		||||
	if(!isolateNamespaces(fsPaths))
 | 
			
		||||
	{
 | 
			
		||||
		Logger::error() << "Failed to isolate namespaces";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SandboxLinux::supported()
 | 
			
		||||
{
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
bool SandboxLinux::enableForWorker()
 | 
			
		||||
{
 | 
			
		||||
	int cap = 0;
 | 
			
		||||
	int res = 0;
 | 
			
		||||
	while((res = prctl(PR_CAPBSET_DROP, cap++, 0, 0, 0)) == 0)
 | 
			
		||||
		;
 | 
			
		||||
	if(res == -1 && errno != EINVAL)
 | 
			
		||||
	{
 | 
			
		||||
		Logger::error() << "Failed to drop the capability bounding set!";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	__user_cap_header_struct h = {0};
 | 
			
		||||
	h.pid = 0;
 | 
			
		||||
	h.version = _LINUX_CAPABILITY_VERSION_3;
 | 
			
		||||
	__user_cap_data_struct drop[2];
 | 
			
		||||
	drop[0].effective = 0;
 | 
			
		||||
	drop[0].permitted = 0;
 | 
			
		||||
	drop[0].inheritable = 0;
 | 
			
		||||
	drop[1].effective = 0;
 | 
			
		||||
	drop[1].permitted = 0;
 | 
			
		||||
	drop[1].inheritable = 0;
 | 
			
		||||
	if(capset(&h, drop) == -1)
 | 
			
		||||
	{
 | 
			
		||||
		Logger::error() << "Failed to drop capabilities: " << strerror(errno);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* 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 */
 | 
			
		||||
	if(!seccomp_blacklist({SCMP_SYS(setuid), SCMP_SYS(setuid32), SCMP_SYS(connect), SCMP_SYS(chroot),
 | 
			
		||||
						   SCMP_SYS(pivot_root), SCMP_SYS(mount), SCMP_SYS(setns), SCMP_SYS(unshare), SCMP_SYS(ptrace),
 | 
			
		||||
						   SCMP_SYS(personality)
 | 
			
		||||
 | 
			
		||||
	   }))
 | 
			
		||||
	{
 | 
			
		||||
		Logger::error() << "Sandbox: Activation of seccomp blacklist failed!";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	if(prctl(PR_SET_DUMPABLE, 0) == -1)
 | 
			
		||||
	{
 | 
			
		||||
		Logger::error() << "prctl: PR_SET_DUMPABLE failed";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	if(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
 | 
			
		||||
	{
 | 
			
		||||
		Logger::error() << "prctl: PR_SET_NO_NEW_PRIVS failed: " << strerror(errno);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(!seccomp_blacklist({SCMP_SYS(prctl)}))
 | 
			
		||||
	{
 | 
			
		||||
		Logger::error() << "Sandbox: Activation of seccomp blacklist failed!";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								sandbox/sandbox-linux.h
									
									
									
									
									
										Normální soubor
									
								
							
							
						
						
									
										20
									
								
								sandbox/sandbox-linux.h
									
									
									
									
									
										Normální soubor
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
#ifndef SANDBOXLINUX_H
 | 
			
		||||
#define SANDBOXLINUX_H
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "sandbox.h"
 | 
			
		||||
class SandboxLinux : public Sandbox
 | 
			
		||||
{
 | 
			
		||||
  public:
 | 
			
		||||
	using Sandbox::Sandbox;
 | 
			
		||||
	bool supported() override;
 | 
			
		||||
	bool enableForInit() override;
 | 
			
		||||
	bool enablePreWorker(std::vector<std::string> fsPaths) override;
 | 
			
		||||
	bool enableForWorker() override;
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
	bool isolateNamespaces(std::vector<std::string> fsPaths);
 | 
			
		||||
	bool seccomp_blacklist(std::initializer_list<int> syscalls);
 | 
			
		||||
	bool bindMountPaths(std::string target_root, std::initializer_list<std::string> paths);
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										15
									
								
								sandbox/sandbox-openbsd.h
									
									
									
									
									
										Normální soubor
									
								
							
							
						
						
									
										15
									
								
								sandbox/sandbox-openbsd.h
									
									
									
									
									
										Normální soubor
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
#ifndef SANDBOXOPENBSD_H
 | 
			
		||||
#define SANDBOXOPENBSD_H
 | 
			
		||||
#include "sandbox.h"
 | 
			
		||||
 | 
			
		||||
class SandboxOpenBSD : public Sandbox
 | 
			
		||||
{
 | 
			
		||||
  public:
 | 
			
		||||
	bool supported() override;
 | 
			
		||||
	bool enableForInit() override;
 | 
			
		||||
	bool enableForWorker() override;
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
	bool seccomp_blacklist(std::vector<int> syscalls);
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										25
									
								
								sandbox/sandbox.h
									
									
									
									
									
										Normální soubor
									
								
							
							
						
						
									
										25
									
								
								sandbox/sandbox.h
									
									
									
									
									
										Normální soubor
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
#ifndef SANDBOX_H
 | 
			
		||||
#define SANDBOX_H
 | 
			
		||||
#include <vector>
 | 
			
		||||
class Sandbox
 | 
			
		||||
{
 | 
			
		||||
  public:
 | 
			
		||||
	Sandbox()
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
	/* Whether the platform has everything required to active all sandbnox modes */
 | 
			
		||||
	virtual bool supported() = 0;
 | 
			
		||||
 | 
			
		||||
	/* Activated early. At this point, we need more system calls
 | 
			
		||||
	 * than later on */
 | 
			
		||||
	virtual bool enableForInit() = 0;
 | 
			
		||||
 | 
			
		||||
	/* Activated after config has been read. Now we now which paths we need access to */
 | 
			
		||||
	virtual bool enablePreWorker(std::vector<std::string> fsPaths) = 0;
 | 
			
		||||
 | 
			
		||||
	/* Activated after we have acquired resources (bound to ports etc.)
 | 
			
		||||
	 *
 | 
			
		||||
	 * This should allow us to further restrcit the process */
 | 
			
		||||
	virtual bool enableForWorker() = 0;
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										11
									
								
								sandbox/sandboxfactory.h
									
									
									
									
									
										Normální soubor
									
								
							
							
						
						
									
										11
									
								
								sandbox/sandboxfactory.h
									
									
									
									
									
										Normální soubor
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
#ifndef SANDBOXFACTORY_H
 | 
			
		||||
#define SANDBOXFACTORY_H
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include "sandbox.h"
 | 
			
		||||
#include "sandbox-linux.h"
 | 
			
		||||
#include "sandbox-openbsd.h"
 | 
			
		||||
inline std::unique_ptr<Sandbox> createSandbox()
 | 
			
		||||
{
 | 
			
		||||
	return std::make_unique<SandboxLinux>();
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
		Odkázat v novém úkolu
	
	Zablokovat Uživatele