From 813792115472081dc575a5c9f97829d0802a0441 Mon Sep 17 00:00:00 2001 From: dongresource Date: Sat, 28 Sep 2024 14:14:49 +0200 Subject: [PATCH] [sandbox] Initial Landlock support --- src/main.cpp | 4 ++ src/sandbox/Sandbox.hpp | 7 +++ src/sandbox/openbsd.cpp | 3 ++ src/sandbox/seccomp.cpp | 95 ++++++++++++++++++++++++++++++++++++++++- 4 files changed, 107 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 288e537..68e93a8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -49,6 +49,7 @@ CNShardServer *shardServer = nullptr; std::thread *shardThread = nullptr; void startShard(CNShardServer* server) { + sandbox_thread_start(); server->start(); } @@ -150,6 +151,8 @@ int main() { /* not reached */ } + sandbox_init(); + std::cout << "[INFO] Starting Server Threads..." << std::endl; CNLoginServer loginServer(settings::LOGINPORT); shardServer = new CNShardServer(settings::SHARDPORT); @@ -157,6 +160,7 @@ int main() { shardThread = new std::thread(startShard, (CNShardServer*)shardServer); sandbox_start(); + sandbox_thread_start(); loginServer.start(); diff --git a/src/sandbox/Sandbox.hpp b/src/sandbox/Sandbox.hpp index 7c115eb..90eb302 100644 --- a/src/sandbox/Sandbox.hpp +++ b/src/sandbox/Sandbox.hpp @@ -4,11 +4,16 @@ #if defined(__linux__) || defined(__OpenBSD__) # if !defined(CONFIG_NOSANDBOX) +void sandbox_init(); void sandbox_start(); +void sandbox_thread_start(); # else #include +inline void sandbox_init() {} +inline void sandbox_thread_start() {} + inline void sandbox_start() { std::cout << "[WARN] Built without a sandbox" << std::endl; } @@ -17,5 +22,7 @@ inline void sandbox_start() { #else // stub for unsupported platforms +inline void sandbox_init() {} inline void sandbox_start() {} +inline void sandbox_thread_start() {} #endif diff --git a/src/sandbox/openbsd.cpp b/src/sandbox/openbsd.cpp index 0b5ac9f..d9882cb 100644 --- a/src/sandbox/openbsd.cpp +++ b/src/sandbox/openbsd.cpp @@ -13,6 +13,9 @@ static void eunveil(const char *path, const char *permissions) { err(1, "unveil"); } +void sandbox_init() {} +void sandbox_thread_start() {} + void sandbox_start() { /* * There shouldn't ever be a reason to disable this one, but might as well diff --git a/src/sandbox/seccomp.cpp b/src/sandbox/seccomp.cpp index 6d930fd..355f9e1 100644 --- a/src/sandbox/seccomp.cpp +++ b/src/sandbox/seccomp.cpp @@ -4,6 +4,7 @@ #include "settings.hpp" #include +#include #include #include @@ -17,6 +18,8 @@ #include #include // for socketcall() args +#include + /* * Macros adapted from https://outflux.net/teach-seccomp/ * Relevant license: @@ -297,19 +300,84 @@ static sock_fprog prog = { ARRLEN(filter), filter }; -// our own wrapper for the seccomp() syscall +struct landlock_ruleset_attr ruleset_attr = { + .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE + | LANDLOCK_ACCESS_FS_WRITE_FILE + | LANDLOCK_ACCESS_FS_READ_DIR + | LANDLOCK_ACCESS_FS_REMOVE_FILE + | LANDLOCK_ACCESS_FS_MAKE_REG + | LANDLOCK_ACCESS_FS_TRUNCATE +}; + +int landlock_fd; + +/* + * Our own wrappers for sandboxing syscalls. + */ + int seccomp(unsigned int operation, unsigned int flags, void *args) { return syscall(__NR_seccomp, operation, flags, args); } -void sandbox_start() { +int landlock_create_ruleset(const struct landlock_ruleset_attr *attr, size_t size, uint32_t flags) { + return syscall(__NR_landlock_create_ruleset, attr, size, flags); +} + +int landlock_add_rule(int ruleset_fd, enum landlock_rule_type rule_type, const void *rule_attr, uint32_t flags) { + return syscall(__NR_landlock_add_rule, ruleset_fd, rule_type, rule_attr, flags); +} + +int landlock_restrict_self(int ruleset_fd, uint32_t flags) { + return syscall(__NR_landlock_restrict_self, ruleset_fd, flags); +} + +void landlock_path(std::string path, uint32_t perms) { + struct landlock_path_beneath_attr path_beneath = { + .allowed_access = perms + }; + + std::cout << "Landlock path: " << path << std::endl; + + path_beneath.parent_fd = open(path.c_str(), O_PATH|O_CLOEXEC); + if (path_beneath.parent_fd < 0) { + perror("open"); + exit(1); + } + + if (landlock_add_rule(landlock_fd, LANDLOCK_RULE_PATH_BENEATH, &path_beneath, 0)) { + perror("landlock_add_rule"); + exit(1); + } + + close(path_beneath.parent_fd); +} + +void sandbox_init() { if (!settings::SANDBOX) { std::cout << "[WARN] Running without a sandbox" << std::endl; return; } + std::cout << "[INFO] Setting up Landlock sandbox..." << std::endl; + + landlock_fd = landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); + if (landlock_fd < 0) { + perror("landlock_create_ruleset"); + exit(1); + } + + landlock_path(".", ruleset_attr.handled_access_fs); + landlock_path("/dev/urandom", LANDLOCK_ACCESS_FS_READ_FILE); + //landlock_path("/tmp/coredumps", ruleset_attr.handled_access_fs); +} + +void sandbox_start() { + if (!settings::SANDBOX) + return; + std::cout << "[INFO] Starting seccomp-bpf sandbox..." << std::endl; +#if 0 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { perror("prctl"); exit(1); @@ -319,6 +387,29 @@ void sandbox_start() { perror("seccomp"); exit(1); } +#endif +} + +void sandbox_thread_start() { + if (!settings::SANDBOX) + return; + + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { + perror("prctl"); + exit(1); + } + + if (landlock_restrict_self(landlock_fd, 0)) { + perror("landlock_restrict_self"); + exit(1); + } + +#if 0 + if (seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog) < 0) { + perror("seccomp"); + exit(1); + } +#endif } #endif