Begin sandboxing support, README updates.
This commit is contained in:
parent
232ff75ae0
commit
5656d3208f
4
Makefile
4
Makefile
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
CXXFLAGS=-std=c++17 -O0 -g -no-pie -pipe -MMD -Wall -Wextra
|
CXXFLAGS=-std=c++17 -O0 -g -no-pie -pipe -MMD -Wall -Wextra
|
||||||
RELEASE_CXXFLAGS=-std=c++17 -O3 -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++
|
CXX=g++
|
||||||
|
|
||||||
@ -12,12 +12,14 @@ SOURCES+=$(wildcard gateway/*.cpp)
|
|||||||
SOURCES+=$(wildcard handlers/*.cpp)
|
SOURCES+=$(wildcard handlers/*.cpp)
|
||||||
SOURCES+=$(wildcard database/*.cpp)
|
SOURCES+=$(wildcard database/*.cpp)
|
||||||
SOURCES+=$(wildcard cache/*.cpp)
|
SOURCES+=$(wildcard cache/*.cpp)
|
||||||
|
SOURCES+=$(wildcard sandbox/*.cpp)
|
||||||
|
|
||||||
HEADERS=$(wildcard *.h)
|
HEADERS=$(wildcard *.h)
|
||||||
HEADERS+=$(wildcard gateway/*.h)
|
HEADERS+=$(wildcard gateway/*.h)
|
||||||
HEADERS+=$(wildcard handlers/*.h)
|
HEADERS+=$(wildcard handlers/*.h)
|
||||||
HEADERS+=$(wildcard database/*.h)
|
HEADERS+=$(wildcard database/*.h)
|
||||||
HEADERS+=$(wildcard cache/*.h)
|
HEADERS+=$(wildcard cache/*.h)
|
||||||
|
HEADERS+=$(wildcard sandbox/*.h)
|
||||||
|
|
||||||
|
|
||||||
OBJECTS=$(patsubst %.cpp, %.o, $(SOURCES))
|
OBJECTS=$(patsubst %.cpp, %.o, $(SOURCES))
|
||||||
|
56
README.md
56
README.md
@ -9,35 +9,40 @@ History
|
|||||||
====
|
====
|
||||||
A couple of years ago, I wanted to setup a personal wiki on my raspberry
|
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
|
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
|
for ARM. So instead of switching distributions or searching for other
|
||||||
to approach the problem and indeed, I may have had too much time back
|
wikis that I could use, I decided I would write one in C. Yes,
|
||||||
then. Also, I wanted to see how it's like to write a "web app" in C
|
that's an odd way to approach the problem and indeed, I may have had too
|
||||||
and wanted to sharpen my C a little bit.
|
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.
|
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
|
And indeed, that would have been more than enough for my use cases.
|
||||||
around and started using FastCGI (with the official library from now
|
Then I decided to play around and started using FastCGI (with the official
|
||||||
defunct fastcgi.com) and created a multi-threaded version. It initially
|
library from now defunct fastcgi.com) and created a multi-threaded version.
|
||||||
used a "pile of files database", but that became too painful, so then
|
It initially used a "pile of files database", but that became too painful,
|
||||||
I started using sqlite.
|
so then I started using sqlite.
|
||||||
|
|
||||||
C++
|
C++
|
||||||
---
|
---
|
||||||
Eventually the code became unmaintainable. Initially, I wanted something
|
Eventually, since it was mostly a playground for me, the code became
|
||||||
quick. I did not care about memory leaks (as it was CGI initially).
|
unmaintainable. Furthermore, I wanted something quick and given that
|
||||||
After FastCGI, they became an issue. In the end, the task of avoiding
|
it was CGI, I didn't bother taking care of memory leaks.
|
||||||
memory leaks became too annoying. And of course, C does not include any
|
After initiating a FastCGI interface, they became an issue and then the
|
||||||
"batteries" and while I could manage, this too was another good reason.
|
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
|
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
|
nearly as bad as you would expect perhaps. Some things are surprisingly
|
||||||
convenient even. Still, the standard library is lacking and
|
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
|
Features
|
||||||
========
|
========
|
||||||
To be fair, at this point it doesn't even have a "diff" between revisions
|
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
|
- CGI
|
||||||
- HTTP server using the header only library cpp-httplib. It's more
|
- 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
|
Security
|
||||||
========
|
========
|
||||||
The most reasonable way would have been to add some sort sandboxing
|
On Linux namespaces are used to restrict the process to only access
|
||||||
support right away, but this is lacking so far. As for "web security",
|
files it needs. It doesn't have access to other paths in the system.
|
||||||
all POST requests are centrally protected against CSRF attacks and all
|
In addition, Seccomp is used to restrict the syscalls the qswiki process
|
||||||
input is escaped against XSS attacks.
|
can call. As for "web security", all POST requests are centrally
|
||||||
|
protected against CSRF attacks and all input is escaped against XSS
|
||||||
|
attacks.
|
||||||
|
|
||||||
Building
|
Building
|
||||||
========
|
========
|
||||||
Dependencies:
|
Dependencies:
|
||||||
- cpp-httplib: https://github.com/yhirose/cpp-httplib
|
- cpp-httplib: https://github.com/yhirose/cpp-httplib
|
||||||
- SqliteModernCpp: https://github.com/SqliteModernCpp
|
- SqliteModernCpp: https://github.com/SqliteModernCpp
|
||||||
|
- libseccomp: https://github.com/seccomp/libseccomp
|
||||||
|
- sqlite3: https://sqlite.org/index.html
|
||||||
|
|
||||||
Given the fact those are header-only libraries, they are already
|
The first two are header-only libraries that are already included here.
|
||||||
included here, so you only need to run:
|
|
||||||
|
|
||||||
|
If all dependencies are available, run:
|
||||||
```make release```
|
```make release```
|
||||||
|
|
||||||
|
|
||||||
Setup
|
Setup
|
||||||
=====
|
=====
|
||||||
To be written
|
To be written
|
||||||
|
2
cache/fscache.cpp
vendored
2
cache/fscache.cpp
vendored
@ -7,7 +7,7 @@ FsCache::FsCache(std::string path)
|
|||||||
{
|
{
|
||||||
if(!std::filesystem::exists(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;
|
this->path = path;
|
||||||
}
|
}
|
||||||
|
35
qswiki.cpp
35
qswiki.cpp
@ -24,6 +24,7 @@ SOFTWARE.
|
|||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <filesystem>
|
||||||
#include "gateway/gatewayinterface.h"
|
#include "gateway/gatewayinterface.h"
|
||||||
#include "gateway/gatewayfactory.h"
|
#include "gateway/gatewayfactory.h"
|
||||||
#include "handlers/handlerfactory.h"
|
#include "handlers/handlerfactory.h"
|
||||||
@ -35,6 +36,7 @@ SOFTWARE.
|
|||||||
#include "urlprovider.h"
|
#include "urlprovider.h"
|
||||||
#include "requestworker.h"
|
#include "requestworker.h"
|
||||||
#include "cache/fscache.h"
|
#include "cache/fscache.h"
|
||||||
|
#include "sandbox/sandboxfactory.h"
|
||||||
void sigterm_handler(int arg)
|
void sigterm_handler(int arg)
|
||||||
{
|
{
|
||||||
//TODO: proper shutdown.
|
//TODO: proper shutdown.
|
||||||
@ -69,6 +71,19 @@ int main(int argc, char **argv)
|
|||||||
std::cerr << "Do not run this as root!" << std::endl;
|
std::cerr << "Do not run this as root!" << std::endl;
|
||||||
return 1;
|
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)
|
if(argc < 2)
|
||||||
{
|
{
|
||||||
std::cerr << "no path to config file provided" << std::endl;
|
std::cerr << "no path to config file provided" << std::endl;
|
||||||
@ -80,6 +95,20 @@ int main(int argc, char **argv)
|
|||||||
ConfigReader configreader(argv[1]);
|
ConfigReader configreader(argv[1]);
|
||||||
Config config = configreader.readConfig();
|
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();
|
setup_signal_handlers();
|
||||||
|
|
||||||
std::fstream logstream;
|
std::fstream logstream;
|
||||||
@ -114,6 +143,12 @@ int main(int argc, char **argv)
|
|||||||
RequestWorker requestWorker (*database, siteTemplate, urlprovider, *cache );
|
RequestWorker requestWorker (*database, siteTemplate, urlprovider, *cache );
|
||||||
|
|
||||||
auto interface = createGateway(config);
|
auto interface = createGateway(config);
|
||||||
|
|
||||||
|
if(!sandbox->enableForWorker())
|
||||||
|
{
|
||||||
|
Logger::error() << "Sandboxing for worker could not be enabled!";
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
interface->work(requestWorker);
|
interface->work(requestWorker);
|
||||||
}
|
}
|
||||||
catch(const std::exception &e)
|
catch(const std::exception &e)
|
||||||
|
272
sandbox/sandbox-linux.cpp
Normal file
272
sandbox/sandbox-linux.cpp
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
19
sandbox/sandbox-linux.h
Normal file
19
sandbox/sandbox-linux.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#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
Normal file
15
sandbox/sandbox-openbsd.h
Normal file
@ -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
|
27
sandbox/sandbox.h
Normal file
27
sandbox/sandbox.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#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
Normal file
11
sandbox/sandboxfactory.h
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user