269 lines
9.1 KiB
C++
269 lines
9.1 KiB
C++
/*
|
|
* This might break with something other than glibc, new versions of glibc, i2pd and other libraries, on a different architecture, etc.
|
|
*/
|
|
#ifdef SANDBOX
|
|
#include <linux/landlock.h>
|
|
#include <seccomp.h>
|
|
#include <fcntl.h>
|
|
|
|
#include "Config.h"
|
|
#include "FS.h"
|
|
#include "Log.h"
|
|
#include "Sandbox.h"
|
|
|
|
#ifndef landlock_create_ruleset
|
|
static inline int landlock_create_ruleset(const struct landlock_ruleset_attr *const attr, const size_t size, const __u32 flags) {
|
|
return syscall(__NR_landlock_create_ruleset, attr, size, flags);
|
|
}
|
|
#endif
|
|
|
|
#ifndef landlock_add_rule
|
|
static inline int landlock_add_rule(const int ruleset_fd, const enum landlock_rule_type rule_type, const void *const rule_attr, const __u32 flags) {
|
|
return syscall(__NR_landlock_add_rule, ruleset_fd, rule_type, rule_attr, flags);
|
|
}
|
|
#endif
|
|
|
|
#ifndef landlock_restrict_self
|
|
static inline int landlock_restrict_self(const int ruleset_fd, const __u32 flags) {
|
|
return syscall(__NR_landlock_restrict_self, ruleset_fd, flags);
|
|
}
|
|
#endif
|
|
|
|
namespace i2p {
|
|
namespace sandbox {
|
|
int loadSeccomp() {
|
|
|
|
int filter[] = {
|
|
SCMP_SYS(accept),
|
|
SCMP_SYS(accept4),
|
|
SCMP_SYS(arch_prctl),
|
|
SCMP_SYS(bind),
|
|
SCMP_SYS(brk),
|
|
SCMP_SYS(chdir),
|
|
SCMP_SYS(clock_nanosleep),
|
|
SCMP_SYS(clone),
|
|
SCMP_SYS(clone3),
|
|
SCMP_SYS(close),
|
|
SCMP_SYS(connect),
|
|
SCMP_SYS(dup),
|
|
SCMP_SYS(dup2),
|
|
SCMP_SYS(dup3),
|
|
SCMP_SYS(epoll_create),
|
|
SCMP_SYS(epoll_create1),
|
|
SCMP_SYS(epoll_ctl),
|
|
SCMP_SYS(epoll_wait),
|
|
SCMP_SYS(epoll_pwait),
|
|
SCMP_SYS(eventfd2),
|
|
SCMP_SYS(exit),
|
|
SCMP_SYS(exit_group),
|
|
SCMP_SYS(fcntl),
|
|
SCMP_SYS(fstat),
|
|
SCMP_SYS(ftruncate),
|
|
SCMP_SYS(futex),
|
|
SCMP_SYS(getdents64),
|
|
SCMP_SYS(getgid),
|
|
SCMP_SYS(getegid),
|
|
SCMP_SYS(getuid),
|
|
SCMP_SYS(geteuid),
|
|
SCMP_SYS(getpeername),
|
|
SCMP_SYS(getpid),
|
|
SCMP_SYS(getrandom),
|
|
SCMP_SYS(getsockname),
|
|
SCMP_SYS(getsockopt),
|
|
SCMP_SYS(gettid),
|
|
SCMP_SYS(ioctl),
|
|
SCMP_SYS(landlock_add_rule),
|
|
SCMP_SYS(landlock_create_ruleset),
|
|
SCMP_SYS(landlock_restrict_self),
|
|
SCMP_SYS(listen),
|
|
SCMP_SYS(lseek),
|
|
SCMP_SYS(madvise),
|
|
SCMP_SYS(membarrier),
|
|
SCMP_SYS(mkdir),
|
|
SCMP_SYS(mkdirat),
|
|
SCMP_SYS(mmap),
|
|
SCMP_SYS(mprotect),
|
|
SCMP_SYS(munmap),
|
|
SCMP_SYS(nanosleep),
|
|
SCMP_SYS(newfstatat),
|
|
SCMP_SYS(open),
|
|
SCMP_SYS(openat),
|
|
SCMP_SYS(poll),
|
|
SCMP_SYS(ppoll),
|
|
SCMP_SYS(prctl),
|
|
SCMP_SYS(prlimit64),
|
|
SCMP_SYS(read),
|
|
SCMP_SYS(recvfrom),
|
|
SCMP_SYS(recvmsg),
|
|
SCMP_SYS(restart_syscall),
|
|
SCMP_SYS(rseq),
|
|
SCMP_SYS(rt_sigaction),
|
|
SCMP_SYS(rt_sigprocmask),
|
|
SCMP_SYS(rt_sigreturn),
|
|
SCMP_SYS(sched_getaffinity),
|
|
SCMP_SYS(sched_getparam),
|
|
SCMP_SYS(sendmsg),
|
|
SCMP_SYS(sendmmsg),
|
|
SCMP_SYS(sendto),
|
|
SCMP_SYS(set_robust_list),
|
|
SCMP_SYS(set_tid_address),
|
|
SCMP_SYS(setsid),
|
|
SCMP_SYS(setsockopt),
|
|
SCMP_SYS(shutdown),
|
|
SCMP_SYS(socket),
|
|
SCMP_SYS(stat),
|
|
SCMP_SYS(statx),
|
|
SCMP_SYS(sysinfo),
|
|
SCMP_SYS(tgkill),
|
|
SCMP_SYS(timerfd_create),
|
|
SCMP_SYS(timerfd_settime),
|
|
SCMP_SYS(umask),
|
|
SCMP_SYS(unlink),
|
|
SCMP_SYS(unlinkat),
|
|
SCMP_SYS(uname),
|
|
SCMP_SYS(write),
|
|
SCMP_SYS(writev),
|
|
};
|
|
|
|
int rc;
|
|
scmp_filter_ctx ctx;
|
|
|
|
/* Initialize seccomp */
|
|
ctx = seccomp_init(SCMP_ACT_KILL_PROCESS); // Kill the process if a violation occurs
|
|
if (ctx == NULL) {
|
|
//LogPrint(eLogError, "Sandbox: Could not initialize seccomp");
|
|
std::cerr << "Sandbox: Could not initialize seccomp" << std::endl;
|
|
seccomp_release(ctx);
|
|
return false;
|
|
}
|
|
|
|
/* Load rules */
|
|
for (int i = 0; i < (int)(sizeof(filter)/sizeof(int)); i++) {
|
|
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, filter[i], 0);
|
|
if (rc != 0) {
|
|
//LogPrint(eLogError, "Sandbox: Could not add seccomp rule ", i, ": ", strerror(rc));
|
|
std::cerr << "Sandbox: Could not add seccomp rule " << i << ": " << strerror(rc) << std::endl;
|
|
seccomp_release(ctx);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* Load filter */
|
|
rc = seccomp_load(ctx);
|
|
if (rc != 0) {
|
|
//LogPrint(eLogError, "Sandbox: Could not load seccomp filter: ", strerror(rc));
|
|
std::cerr << "Sandbox: Could not load seccomp filter: " << strerror(rc) << std::endl;
|
|
seccomp_release(ctx);
|
|
return false;
|
|
}
|
|
|
|
/* Success */
|
|
LogPrint(eLogNone, "Sandbox: Loaded seccomp filter");
|
|
seccomp_release(ctx);
|
|
return true;
|
|
}
|
|
|
|
int addrule(const char *path, unsigned long long rules, int ruleset_fd) {
|
|
struct landlock_path_beneath_attr temp;
|
|
temp.allowed_access = rules;
|
|
temp.parent_fd = 0;
|
|
|
|
/* Open path file descriptor */
|
|
temp.parent_fd = open(path, O_PATH | O_CLOEXEC);
|
|
if (temp.parent_fd < 0) {
|
|
//LogPrint(eLogError, "Sandbox: Failed to open ", path, ": ", strerror(errno));
|
|
std::cerr << "Sandbox: Failed to open " << path << ": " << strerror(errno) << std::endl;
|
|
close(temp.parent_fd);
|
|
close(ruleset_fd);
|
|
return false;
|
|
}
|
|
|
|
/* Add rule */
|
|
int rc = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, &temp, 0);
|
|
if (rc != 0) {
|
|
//LogPrint(eLogError, "Sandbox: Failed to add Landlock rule for ", path, ": ", strerror(rc));
|
|
std::cerr << "Sandbox: Failed to add Landlock rule for " << path << ": " << strerror(rc) << std::endl;
|
|
close(temp.parent_fd);
|
|
close(ruleset_fd);
|
|
return false;
|
|
}
|
|
close(temp.parent_fd);
|
|
return true;
|
|
}
|
|
|
|
int loadLandlock() {
|
|
/* Deny everything by default */
|
|
struct landlock_ruleset_attr ruleset_attr = {
|
|
{LANDLOCK_ACCESS_FS_EXECUTE |
|
|
LANDLOCK_ACCESS_FS_WRITE_FILE |
|
|
LANDLOCK_ACCESS_FS_READ_FILE |
|
|
LANDLOCK_ACCESS_FS_READ_DIR |
|
|
LANDLOCK_ACCESS_FS_REMOVE_DIR |
|
|
LANDLOCK_ACCESS_FS_REMOVE_FILE |
|
|
LANDLOCK_ACCESS_FS_MAKE_CHAR |
|
|
LANDLOCK_ACCESS_FS_MAKE_DIR |
|
|
LANDLOCK_ACCESS_FS_MAKE_REG |
|
|
LANDLOCK_ACCESS_FS_MAKE_SOCK |
|
|
LANDLOCK_ACCESS_FS_MAKE_FIFO |
|
|
LANDLOCK_ACCESS_FS_MAKE_BLOCK |
|
|
LANDLOCK_ACCESS_FS_MAKE_SYM |
|
|
LANDLOCK_ACCESS_FS_REFER},
|
|
};
|
|
|
|
/* Check kernel compatibility */
|
|
int abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
|
|
if (abi < 2) {
|
|
//LogPrint(eLogError, "Sandbox: Landlock ABI 2 is not supported by this kernel.");
|
|
std::cerr << "Sandbox: Landlock ABI 2 is not supported by this kernel." << std::endl;
|
|
return false;
|
|
}
|
|
|
|
/* Create default ruleset */
|
|
int ruleset_fd = landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
|
|
if (ruleset_fd < 0) {
|
|
//LogPrint(eLogError, "Sandbox: Failed to create Landlock ruleset: ", strerror(ruleset_fd));
|
|
std::cerr << "Sandbox: Failed to create Landlock ruleset: " << strerror(ruleset_fd) << std::endl;
|
|
close(ruleset_fd);
|
|
return false;
|
|
}
|
|
|
|
/* Add rules */
|
|
if(!addrule(i2p::fs::GetDataDir().c_str(), LANDLOCK_ACCESS_FS_READ_FILE|LANDLOCK_ACCESS_FS_READ_DIR|LANDLOCK_ACCESS_FS_WRITE_FILE|LANDLOCK_ACCESS_FS_MAKE_REG|LANDLOCK_ACCESS_FS_MAKE_DIR|LANDLOCK_ACCESS_FS_REMOVE_FILE, ruleset_fd))
|
|
return false;
|
|
if(!addrule(i2p::fs::GetCertsDir().c_str(), LANDLOCK_ACCESS_FS_READ_FILE|LANDLOCK_ACCESS_FS_READ_DIR, ruleset_fd))
|
|
return false;
|
|
if(!addrule("/var/log/", LANDLOCK_ACCESS_FS_WRITE_FILE|LANDLOCK_ACCESS_FS_MAKE_REG|LANDLOCK_ACCESS_FS_MAKE_DIR, ruleset_fd))
|
|
return false;
|
|
if(!addrule("/lib/", LANDLOCK_ACCESS_FS_READ_FILE|LANDLOCK_ACCESS_FS_READ_DIR, ruleset_fd))
|
|
return false;
|
|
if(!addrule("/usr/lib/", LANDLOCK_ACCESS_FS_READ_FILE|LANDLOCK_ACCESS_FS_READ_DIR, ruleset_fd))
|
|
return false;
|
|
if(!addrule("/usr/share/", LANDLOCK_ACCESS_FS_READ_FILE|LANDLOCK_ACCESS_FS_READ_DIR, ruleset_fd))
|
|
return false;
|
|
if(!addrule("/proc/sys/", LANDLOCK_ACCESS_FS_READ_FILE|LANDLOCK_ACCESS_FS_READ_DIR, ruleset_fd))
|
|
return false;
|
|
if(!addrule("/sys/devices/system/cpu/", LANDLOCK_ACCESS_FS_READ_FILE|LANDLOCK_ACCESS_FS_READ_DIR, ruleset_fd))
|
|
return false;
|
|
if(!addrule("/dev/urandom", LANDLOCK_ACCESS_FS_READ_FILE, ruleset_fd))
|
|
return false;
|
|
if(!addrule("/etc/", LANDLOCK_ACCESS_FS_READ_FILE|LANDLOCK_ACCESS_FS_READ_DIR, ruleset_fd))
|
|
return false;
|
|
|
|
/* Load ruleset */
|
|
int rc = landlock_restrict_self(ruleset_fd, 0);
|
|
if (rc != 0) {
|
|
//LogPrint(eLogError, "Sandbox: Failed to load Landlock ruleset: ", strerror(rc));
|
|
std::cerr << "Sandbox: Failed to load Landlock ruleset: " << strerror(rc) << std::endl;
|
|
close(ruleset_fd);
|
|
return false;
|
|
}
|
|
|
|
/* Success */
|
|
LogPrint(eLogNone, "Sandbox: Loaded Landlock filter");
|
|
close(ruleset_fd);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
#endif
|