diff --git a/src/sandbox/seccomp.cpp b/src/sandbox/seccomp.cpp index 355f9e1..3b75dc6 100644 --- a/src/sandbox/seccomp.cpp +++ b/src/sandbox/seccomp.cpp @@ -6,6 +6,8 @@ #include #include +#include + #include #include #include // for mmap() args @@ -18,7 +20,9 @@ #include #include // for socketcall() args +#ifndef CONFIG_NOLANDLOCK #include +#endif /* * Macros adapted from https://outflux.net/teach-seccomp/ @@ -300,25 +304,50 @@ static sock_fprog prog = { ARRLEN(filter), filter }; +// Our own wrapper for the seccomp() syscall. +int seccomp(unsigned int operation, unsigned int flags, void *args) { + return syscall(__NR_seccomp, operation, flags, args); +} + +#ifndef CONFIG_NOLANDLOCK + +// Support compilation on systems that only have older Landlock headers. +#ifndef LANDLOCK_ACCESS_FS_REFER +#define LANDLOCK_ACCESS_FS_REFER 0 +#endif +#ifndef LANDLOCK_ACCESS_FS_TRUNCATE +#define LANDLOCK_ACCESS_FS_TRUNCATE 0 +#endif + 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_MAKE_DIR + | LANDLOCK_ACCESS_FS_MAKE_SYM + | LANDLOCK_ACCESS_FS_MAKE_SOCK + | LANDLOCK_ACCESS_FS_MAKE_FIFO + | LANDLOCK_ACCESS_FS_MAKE_BLOCK + | LANDLOCK_ACCESS_FS_REMOVE_FILE + | LANDLOCK_ACCESS_FS_REMOVE_DIR | LANDLOCK_ACCESS_FS_TRUNCATE + | LANDLOCK_ACCESS_FS_REFER }; +uint64_t landlock_perms = LANDLOCK_ACCESS_FS_READ_FILE + | LANDLOCK_ACCESS_FS_WRITE_FILE + | LANDLOCK_ACCESS_FS_TRUNCATE + | LANDLOCK_ACCESS_FS_MAKE_REG + | LANDLOCK_ACCESS_FS_REMOVE_FILE; + int landlock_fd; +bool landlock_supported; /* - * Our own wrappers for sandboxing syscalls. + * Our own wrappers for Landlock syscalls. */ -int seccomp(unsigned int operation, unsigned int flags, void *args) { - return syscall(__NR_seccomp, operation, flags, args); -} - 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); } @@ -331,16 +360,14 @@ 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) { +static 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"); + perror(path.c_str()); exit(1); } @@ -352,23 +379,73 @@ void landlock_path(std::string path, uint32_t perms) { close(path_beneath.parent_fd); } -void sandbox_init() { - if (!settings::SANDBOX) { - std::cout << "[WARN] Running without a sandbox" << std::endl; - return; +static bool landlock_detect() { + int abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION); + + if (abi < 0) { + if (errno == ENOSYS || errno == EOPNOTSUPP) { + std::cout << "[WARN] No Landlock support on this system" << std::endl; + return false; + } + perror("landlock_create_ruleset"); + exit(1); } + std::cout << "[INFO] Landlock ABI version: " << abi << std::endl; + + switch (abi) { + case 1: + ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER; + landlock_perms &= ~LANDLOCK_ACCESS_FS_REFER; + // fallthrough + case 2: + ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE; + landlock_perms &= ~LANDLOCK_ACCESS_FS_TRUNCATE; + } + + return true; +} + +static void landlock_init() { std::cout << "[INFO] Setting up Landlock sandbox..." << std::endl; + landlock_supported = landlock_detect(); + + if (!landlock_supported) + return; + 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); + std::string dbdir = std::filesystem::path(settings::DBPATH).parent_path(); + + // for the DB files (we can't rely on them being in the working directory) + landlock_path(dbdir == "" ? "." : dbdir, landlock_perms); + // for writing the gruntwork file + landlock_path(settings::TDATADIR, landlock_perms); + // for passowrd salting during account creation landlock_path("/dev/urandom", LANDLOCK_ACCESS_FS_READ_FILE); - //landlock_path("/tmp/coredumps", ruleset_attr.handled_access_fs); + // for core dumps, optionally + if (settings::SANDBOXEXTRAPATH != "") + landlock_path(settings::SANDBOXEXTRAPATH, landlock_perms); +} + +#endif // !CONFIG_NOLANDLOCK + +void sandbox_init() { + if (!settings::SANDBOX) { + std::cout << "[WARN] Running without a sandbox" << std::endl; + return; + } + +#ifndef CONFIG_NOLANDLOCK + landlock_init(); +#else + std::cout << "[WARN] Built without Landlock" << std::endl; +#endif } void sandbox_start() { @@ -377,17 +454,7 @@ void sandbox_start() { 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); - } - - if (seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, &prog) < 0) { - perror("seccomp"); - exit(1); - } -#endif + // Sandboxing starts in sandbox_thread_start(). } void sandbox_thread_start() { @@ -399,17 +466,19 @@ void sandbox_thread_start() { exit(1); } - if (landlock_restrict_self(landlock_fd, 0)) { - perror("landlock_restrict_self"); - exit(1); +#ifndef CONFIG_NOLANDLOCK + if (landlock_supported) { + if (landlock_restrict_self(landlock_fd, 0)) { + perror("landlock_restrict_self"); + exit(1); + } } +#endif -#if 0 if (seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog) < 0) { perror("seccomp"); exit(1); } -#endif } #endif diff --git a/src/settings.cpp b/src/settings.cpp index 9815a40..19c9b13 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -9,6 +9,7 @@ // defaults :) int settings::VERBOSITY = 1; bool settings::SANDBOX = true; +std::string settings::SANDBOXEXTRAPATH = ""; int settings::LOGINPORT = 23000; bool settings::APPROVEALLNAMES = true; @@ -85,6 +86,7 @@ void settings::init() { VERBOSITY = reader.GetInteger("", "verbosity", VERBOSITY); SANDBOX = reader.GetBoolean("", "sandbox", SANDBOX); + SANDBOXEXTRAPATH = reader.Get("", "sandboxextrapath", SANDBOXEXTRAPATH); LOGINPORT = reader.GetInteger("login", "port", LOGINPORT); APPROVEALLNAMES = reader.GetBoolean("login", "acceptallcustomnames", APPROVEALLNAMES); AUTOCREATEACCOUNTS = reader.GetBoolean("login", "autocreateaccounts", AUTOCREATEACCOUNTS); diff --git a/src/settings.hpp b/src/settings.hpp index 302c4f6..eb17c8d 100644 --- a/src/settings.hpp +++ b/src/settings.hpp @@ -5,6 +5,7 @@ namespace settings { extern int VERBOSITY; extern bool SANDBOX; + extern std::string SANDBOXEXTRAPATH; extern int LOGINPORT; extern bool APPROVEALLNAMES; extern bool AUTOCREATEACCOUNTS;