mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-11-21 21:20:04 +00:00
Proof-of-concept, default-permit seccomp-bpf sandbox
Can be disabled by adding -DCONFIG_NOSANDBOX to CXXFLAGS.
This commit is contained in:
parent
05d6174351
commit
3c1e08372d
2
Makefile
2
Makefile
@ -48,6 +48,7 @@ CXXSRC=\
|
|||||||
src/db/shard.cpp\
|
src/db/shard.cpp\
|
||||||
src/db/player.cpp\
|
src/db/player.cpp\
|
||||||
src/db/email.cpp\
|
src/db/email.cpp\
|
||||||
|
src/sandbox/seccomp.cpp\
|
||||||
src/Chat.cpp\
|
src/Chat.cpp\
|
||||||
src/CustomCommands.cpp\
|
src/CustomCommands.cpp\
|
||||||
src/Entities.cpp\
|
src/Entities.cpp\
|
||||||
@ -88,6 +89,7 @@ CXXHDR=\
|
|||||||
src/servers/Monitor.hpp\
|
src/servers/Monitor.hpp\
|
||||||
src/db/Database.hpp\
|
src/db/Database.hpp\
|
||||||
src/db/internal.hpp\
|
src/db/internal.hpp\
|
||||||
|
src/sandbox/Sandbox.hpp\
|
||||||
vendor/bcrypt/BCrypt.hpp\
|
vendor/bcrypt/BCrypt.hpp\
|
||||||
vendor/INIReader.hpp\
|
vendor/INIReader.hpp\
|
||||||
vendor/JSON.hpp\
|
vendor/JSON.hpp\
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
# 3 = print all packets
|
# 3 = print all packets
|
||||||
verbosity=1
|
verbosity=1
|
||||||
|
|
||||||
|
# sandbox the process on supported platforms
|
||||||
|
sandbox=true
|
||||||
|
|
||||||
# Login Server configuration
|
# Login Server configuration
|
||||||
[login]
|
[login]
|
||||||
# must be kept in sync with loginInfo.php
|
# must be kept in sync with loginInfo.php
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "Rand.hpp"
|
#include "Rand.hpp"
|
||||||
|
|
||||||
#include "settings.hpp"
|
#include "settings.hpp"
|
||||||
|
#include "sandbox/Sandbox.hpp"
|
||||||
|
|
||||||
#include "../version.h"
|
#include "../version.h"
|
||||||
|
|
||||||
@ -94,11 +95,13 @@ int main() {
|
|||||||
#else
|
#else
|
||||||
initsignals();
|
initsignals();
|
||||||
#endif
|
#endif
|
||||||
Rand::init(getTime());
|
|
||||||
settings::init();
|
settings::init();
|
||||||
|
|
||||||
std::cout << "[INFO] OpenFusion v" GIT_VERSION << std::endl;
|
std::cout << "[INFO] OpenFusion v" GIT_VERSION << std::endl;
|
||||||
std::cout << "[INFO] Protocol version: " << PROTOCOL_VERSION << std::endl;
|
std::cout << "[INFO] Protocol version: " << PROTOCOL_VERSION << std::endl;
|
||||||
std::cout << "[INFO] Intializing Packet Managers..." << std::endl;
|
std::cout << "[INFO] Intializing Packet Managers..." << std::endl;
|
||||||
|
|
||||||
|
Rand::init(getTime());
|
||||||
TableData::init();
|
TableData::init();
|
||||||
PlayerManager::init();
|
PlayerManager::init();
|
||||||
PlayerMovement::init();
|
PlayerMovement::init();
|
||||||
@ -138,6 +141,8 @@ int main() {
|
|||||||
|
|
||||||
shardThread = new std::thread(startShard, (CNShardServer*)shardServer);
|
shardThread = new std::thread(startShard, (CNShardServer*)shardServer);
|
||||||
|
|
||||||
|
sandbox_start();
|
||||||
|
|
||||||
loginServer.start();
|
loginServer.start();
|
||||||
|
|
||||||
shardServer->kill();
|
shardServer->kill();
|
||||||
@ -152,7 +157,7 @@ int main() {
|
|||||||
// helper functions
|
// helper functions
|
||||||
|
|
||||||
std::string U16toU8(char16_t* src, size_t max) {
|
std::string U16toU8(char16_t* src, size_t max) {
|
||||||
src[max-1] = '\0'; // force a NULL terminatorstd::string U16toU8(char16_t* src) {
|
src[max-1] = '\0'; // force a NULL terminator
|
||||||
try {
|
try {
|
||||||
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert;
|
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert;
|
||||||
std::string ret = convert.to_bytes(src);
|
std::string ret = convert.to_bytes(src);
|
||||||
|
21
src/sandbox/Sandbox.hpp
Normal file
21
src/sandbox/Sandbox.hpp
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// use the sandbox on supported platforms, unless disabled
|
||||||
|
#if defined(__linux__) || defined(__OpenBSD__)
|
||||||
|
|
||||||
|
# if !defined(CONFIG_NOSANDBOX)
|
||||||
|
void sandbox_start();
|
||||||
|
# else
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
inline void sandbox_start() {
|
||||||
|
std::cout << "[WARN] Built without a sandbox" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
# endif // CONFIG_NOSANDBOX
|
||||||
|
|
||||||
|
#else
|
||||||
|
// stub for unsupported platforms
|
||||||
|
inline void sandbox_start() {}
|
||||||
|
#endif
|
102
src/sandbox/seccomp.cpp
Normal file
102
src/sandbox/seccomp.cpp
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
#if defined(__linux__) && !defined(CONFIG_NOSANDBOX)
|
||||||
|
|
||||||
|
#include "core/Core.hpp" // mostly for ARRLEN
|
||||||
|
#include "settings.hpp"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
#include <sys/ptrace.h>
|
||||||
|
|
||||||
|
#include <linux/unistd.h>
|
||||||
|
#include <linux/seccomp.h>
|
||||||
|
#include <linux/filter.h>
|
||||||
|
#include <linux/audit.h>
|
||||||
|
|
||||||
|
// our own wrapper for the seccomp() syscall
|
||||||
|
// TODO: should this be conditional on a feature check or something?
|
||||||
|
static inline int seccomp(unsigned int operation, unsigned int flags, void *args) {
|
||||||
|
return syscall(__NR_seccomp, operation, flags, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macros borrowed from from https://outflux.net/teach-seccomp/
|
||||||
|
* Relevant license:
|
||||||
|
* https://source.chromium.org/chromium/chromium/src/+/master:LICENSE
|
||||||
|
*/
|
||||||
|
#define syscall_nr (offsetof(struct seccomp_data, nr))
|
||||||
|
#define arch_nr (offsetof(struct seccomp_data, arch))
|
||||||
|
|
||||||
|
#if defined(__i386__)
|
||||||
|
# define ARCH_NR AUDIT_ARCH_I386
|
||||||
|
#elif defined(__x86_64__)
|
||||||
|
# define ARCH_NR AUDIT_ARCH_X86_64
|
||||||
|
#elif defined(__arm__)
|
||||||
|
# define ARCH_NR AUDIT_ARCH_ARM
|
||||||
|
#else
|
||||||
|
# error "Seccomp-bpf sandbox unsupported on this architecture"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define VALIDATE_ARCHITECTURE \
|
||||||
|
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, arch_nr), \
|
||||||
|
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \
|
||||||
|
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)
|
||||||
|
|
||||||
|
#define EXAMINE_SYSCALL \
|
||||||
|
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_nr)
|
||||||
|
|
||||||
|
#define ALLOW_SYSCALL(name) \
|
||||||
|
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_##name, 0, 1), \
|
||||||
|
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
|
||||||
|
|
||||||
|
#define KILL_PROCESS \
|
||||||
|
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)
|
||||||
|
|
||||||
|
#define DENY_SYSCALL(name) \
|
||||||
|
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_##name, 0, 1), \
|
||||||
|
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL_PROCESS)
|
||||||
|
|
||||||
|
static sock_filter filter[] = {
|
||||||
|
VALIDATE_ARCHITECTURE,
|
||||||
|
EXAMINE_SYSCALL,
|
||||||
|
|
||||||
|
// examples of undesirable syscalls
|
||||||
|
DENY_SYSCALL(execve),
|
||||||
|
DENY_SYSCALL(fork),
|
||||||
|
DENY_SYSCALL(vfork),
|
||||||
|
DENY_SYSCALL(clone),
|
||||||
|
DENY_SYSCALL(connect),
|
||||||
|
DENY_SYSCALL(listen),
|
||||||
|
DENY_SYSCALL(bind),
|
||||||
|
DENY_SYSCALL(kill),
|
||||||
|
DENY_SYSCALL(settimeofday),
|
||||||
|
// etc
|
||||||
|
|
||||||
|
// default-permit mode
|
||||||
|
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
|
||||||
|
};
|
||||||
|
|
||||||
|
static sock_fprog prog = {
|
||||||
|
ARRLEN(filter), filter
|
||||||
|
};
|
||||||
|
|
||||||
|
void sandbox_start() {
|
||||||
|
if (!settings::SANDBOX) {
|
||||||
|
std::cout << "[WARN] Running without a sandbox" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "[INFO] Starting seccomp-bpf sandbox..." << std::endl;
|
||||||
|
|
||||||
|
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 // SANDBOX_SECCOMP
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
// defaults :)
|
// defaults :)
|
||||||
int settings::VERBOSITY = 1;
|
int settings::VERBOSITY = 1;
|
||||||
|
bool settings::SANDBOX = true;
|
||||||
|
|
||||||
int settings::LOGINPORT = 23000;
|
int settings::LOGINPORT = 23000;
|
||||||
bool settings::APPROVEALLNAMES = true;
|
bool settings::APPROVEALLNAMES = true;
|
||||||
@ -77,6 +78,7 @@ void settings::init() {
|
|||||||
|
|
||||||
APPROVEALLNAMES = reader.GetBoolean("", "acceptallcustomnames", APPROVEALLNAMES);
|
APPROVEALLNAMES = reader.GetBoolean("", "acceptallcustomnames", APPROVEALLNAMES);
|
||||||
VERBOSITY = reader.GetInteger("", "verbosity", VERBOSITY);
|
VERBOSITY = reader.GetInteger("", "verbosity", VERBOSITY);
|
||||||
|
SANDBOX = reader.GetBoolean("", "sandbox", SANDBOX);
|
||||||
LOGINPORT = reader.GetInteger("login", "port", LOGINPORT);
|
LOGINPORT = reader.GetInteger("login", "port", LOGINPORT);
|
||||||
SHARDPORT = reader.GetInteger("shard", "port", SHARDPORT);
|
SHARDPORT = reader.GetInteger("shard", "port", SHARDPORT);
|
||||||
DBSAVEINTERVAL = reader.GetInteger("login", "dbsaveinterval", DBSAVEINTERVAL);
|
DBSAVEINTERVAL = reader.GetInteger("login", "dbsaveinterval", DBSAVEINTERVAL);
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace settings {
|
namespace settings {
|
||||||
extern int VERBOSITY;
|
extern int VERBOSITY;
|
||||||
|
extern bool SANDBOX;
|
||||||
extern int LOGINPORT;
|
extern int LOGINPORT;
|
||||||
extern bool APPROVEALLNAMES;
|
extern bool APPROVEALLNAMES;
|
||||||
extern int DBSAVEINTERVAL;
|
extern int DBSAVEINTERVAL;
|
||||||
|
Loading…
Reference in New Issue
Block a user