Skip to content

Commit 4747da3

Browse files
Add syscall sandboxing (seccomp-bpf)
1 parent e69cbac commit 4747da3

27 files changed

+1125
-1
lines changed

ci/test/00_setup_env_i686_multiprocess.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ export DEP_OPTS="DEBUG=1 MULTIPROCESS=1"
1414
export GOAL="install"
1515
export BITCOIN_CONFIG="--enable-debug CC='clang -m32' CXX='clang++ -m32' LDFLAGS='--rtlib=compiler-rt -lgcc_s'"
1616
export TEST_RUNNER_ENV="BITCOIND=bitcoin-node"
17+
export TEST_RUNNER_EXTRA="--nosandbox"
1718
export PIP_PACKAGES="lief"

configure.ac

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ case $host in
7171
;;
7272
esac
7373

74+
AC_ARG_WITH([seccomp],
75+
[AS_HELP_STRING([--with-seccomp],
76+
[enable experimental syscall sandbox feature (-sandbox), default is yes if seccomp-bpf is detected under Linux x86_64])],
77+
[seccomp_found=$withval],
78+
[seccomp_found=auto])
79+
7480
dnl Require C++17 compiler (no GNU extensions)
7581
AX_CXX_COMPILE_STDCXX([17], [noext], [mandatory])
7682

@@ -1443,6 +1449,36 @@ if test "x$use_external_signer" != xno; then
14431449
fi
14441450
AM_CONDITIONAL([ENABLE_EXTERNAL_SIGNER], [test "x$use_external_signer" = "xyes"])
14451451

1452+
dnl Do not compile with syscall sandbox support when compiling under the sanitizers.
1453+
dnl The sanitizers introduce use of syscalls that are not typically used in bitcoind
1454+
dnl (such as execve when the sanitizers execute llvm-symbolizer).
1455+
if test x$use_sanitizers != x; then
1456+
AC_MSG_WARN(Specifying --with-sanitizers forces --without-seccomp since the sanitizers introduce use of syscalls not allowed by the bitcoind syscall sandbox (-sandbox=<mode>).)
1457+
seccomp_found=no
1458+
fi
1459+
if test "x$seccomp_found" != "xno"; then
1460+
AC_MSG_CHECKING([for seccomp-bpf (Linux x86-64)])
1461+
AC_PREPROC_IFELSE([AC_LANG_PROGRAM([[
1462+
@%:@include <linux/seccomp.h>
1463+
]], [[
1464+
#if !defined(__x86_64__)
1465+
# error Syscall sandbox is an experimental feature currently available only under Linux x86-64.
1466+
#endif
1467+
]])],[
1468+
AC_MSG_RESULT(yes)
1469+
seccomp_found="yes"
1470+
AC_DEFINE(USE_SYSCALL_SANDBOX, 1, [Define this symbol to build with syscall sandbox support.])
1471+
],[
1472+
AC_MSG_RESULT(no)
1473+
seccomp_found="no"
1474+
])
1475+
fi
1476+
dnl Currently only enable -sandbox=<mode> feature if seccomp is found.
1477+
dnl In the future, sandboxing could be also be supported with other
1478+
dnl sandboxing mechanisms besides seccomp.
1479+
use_syscall_sandbox=$seccomp_found
1480+
AM_CONDITIONAL([ENABLE_SYSCALL_SANDBOX], [test "x$use_syscall_sandbox" != "xno"])
1481+
14461482
dnl Check for reduced exports
14471483
if test x$use_reduce_exports = xyes; then
14481484
AX_CHECK_COMPILE_FLAG([-fvisibility=hidden],[CXXFLAGS="$CXXFLAGS -fvisibility=hidden"],
@@ -1933,6 +1969,7 @@ echo
19331969
echo "Options used to compile and link:"
19341970
echo " external signer = $use_external_signer"
19351971
echo " multiprocess = $build_multiprocess"
1972+
echo " with experimental syscall sandbox support = $use_syscall_sandbox"
19361973
echo " with libs = $build_bitcoin_libs"
19371974
echo " with wallet = $enable_wallet"
19381975
if test "x$enable_wallet" != "xno"; then

src/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ BITCOIN_CORE_H = \
261261
util/sock.h \
262262
util/spanparsing.h \
263263
util/string.h \
264+
util/syscall_sandbox.h \
264265
util/system.h \
265266
util/thread.h \
266267
util/threadnames.h \
@@ -611,6 +612,7 @@ libbitcoin_util_a_SOURCES = \
611612
util/spanparsing.cpp \
612613
util/strencodings.cpp \
613614
util/string.cpp \
615+
util/syscall_sandbox.cpp \
614616
util/time.cpp \
615617
util/tokenpipe.cpp \
616618
$(BITCOIN_CORE_H)

src/bitcoind.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <shutdown.h>
2020
#include <util/check.h>
2121
#include <util/strencodings.h>
22+
#include <util/syscall_sandbox.h>
2223
#include <util/system.h>
2324
#include <util/threadnames.h>
2425
#include <util/tokenpipe.h>
@@ -238,6 +239,7 @@ static bool AppInit(NodeContext& node, int argc, char* argv[])
238239
daemon_ep.Close();
239240
}
240241
#endif
242+
SetSyscallSandboxPolicy(SyscallSandboxPolicy::SHUTOFF);
241243
if (fRet) {
242244
WaitForShutdown();
243245
}

src/checkqueue.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <sync.h>
99
#include <tinyformat.h>
10+
#include <util/syscall_sandbox.h>
1011
#include <util/threadnames.h>
1112

1213
#include <algorithm>
@@ -151,6 +152,7 @@ class CCheckQueue
151152
for (int n = 0; n < threads_num; ++n) {
152153
m_worker_threads.emplace_back([this, n]() {
153154
util::ThreadRename(strprintf("scriptch.%i", n));
155+
SetSyscallSandboxPolicy(SyscallSandboxPolicy::VALIDATION_SCRIPT_CHECK);
154156
Loop(false /* worker thread */);
155157
});
156158
}

src/httpserver.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <shutdown.h>
1313
#include <sync.h>
1414
#include <util/strencodings.h>
15+
#include <util/syscall_sandbox.h>
1516
#include <util/system.h>
1617
#include <util/threadnames.h>
1718
#include <util/translation.h>
@@ -279,6 +280,7 @@ static void http_reject_request_cb(struct evhttp_request* req, void*)
279280
static bool ThreadHTTP(struct event_base* base)
280281
{
281282
util::ThreadRename("http");
283+
SetSyscallSandboxPolicy(SyscallSandboxPolicy::NET_HTTP_SERVER);
282284
LogPrint(BCLog::HTTP, "Entering http event loop\n");
283285
event_base_dispatch(base);
284286
// Event loop will be interrupted by InterruptHTTPServer()
@@ -332,6 +334,7 @@ static bool HTTPBindAddresses(struct evhttp* http)
332334
static void HTTPWorkQueueRun(WorkQueue<HTTPClosure>* queue, int worker_num)
333335
{
334336
util::ThreadRename(strprintf("httpworker.%i", worker_num));
337+
SetSyscallSandboxPolicy(SyscallSandboxPolicy::NET_HTTP_SERVER_WORKER);
335338
queue->Run();
336339
}
337340

src/index/base.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <node/ui_interface.h>
99
#include <shutdown.h>
1010
#include <tinyformat.h>
11+
#include <util/syscall_sandbox.h>
1112
#include <util/thread.h>
1213
#include <util/translation.h>
1314
#include <validation.h> // For g_chainman
@@ -123,6 +124,7 @@ static const CBlockIndex* NextSyncBlock(const CBlockIndex* pindex_prev, CChain&
123124

124125
void BaseIndex::ThreadSync()
125126
{
127+
SetSyscallSandboxPolicy(SyscallSandboxPolicy::TX_INDEX);
126128
const CBlockIndex* pindex = m_best_block_index.load();
127129
if (!m_synced) {
128130
auto& consensus_params = Params().GetConsensus();

src/init.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
#include <util/check.h>
6161
#include <util/moneystr.h>
6262
#include <util/string.h>
63+
#include <util/syscall_sandbox.h>
6364
#include <util/system.h>
6465
#include <util/thread.h>
6566
#include <util/threadnames.h>
@@ -562,6 +563,10 @@ void SetupServerArgs(ArgsManager& argsman)
562563
hidden_args.emplace_back("-daemonwait");
563564
#endif
564565

566+
#if defined(USE_SYSCALL_SANDBOX)
567+
argsman.AddArg("-sandbox=<mode>", "Use the experimental syscall sandbox in the specified mode (-sandbox=log-and-abort or -sandbox=abort). Allow only expected syscalls to be used by bitcoind. Note that this is an experimental new feature that may cause bitcoind to exit or crash unexpectedly: use with caution. In the \"log-and-abort\" mode the invocation of an unexpected syscall results in a debug handler being invoked which will log the incident and terminate the program (without executing the unexpected syscall). In the \"abort\" mode the invocation of an unexpected syscall results in the entire process being killed immediately by the kernel without executing the unexpected syscall.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
568+
#endif // USE_SYSCALL_SANDBOX
569+
565570
// Add the hidden options
566571
argsman.AddHiddenArgs(hidden_args);
567572
}
@@ -1018,6 +1023,37 @@ bool AppInitParameterInteraction(const ArgsManager& args)
10181023
return InitError(_("No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>."));
10191024
}
10201025

1026+
#if defined(USE_SYSCALL_SANDBOX)
1027+
if (args.IsArgSet("-sandbox") && !args.IsArgNegated("-sandbox")) {
1028+
const std::string sandbox_arg{args.GetArg("-sandbox", "")};
1029+
bool log_syscall_violation_before_terminating{false};
1030+
if (sandbox_arg == "log-and-abort") {
1031+
log_syscall_violation_before_terminating = true;
1032+
} else if (sandbox_arg == "abort") {
1033+
// log_syscall_violation_before_terminating is false by default.
1034+
} else {
1035+
return InitError(Untranslated("Unknown syscall sandbox mode (-sandbox=<mode>). Available modes are \"log-and-abort\" and \"abort\"."));
1036+
}
1037+
// execve(...) is not allowed by the syscall sandbox.
1038+
const std::vector<std::string> features_using_execve{
1039+
"-alertnotify",
1040+
"-blocknotify",
1041+
"-signer",
1042+
"-startupnotify",
1043+
"-walletnotify",
1044+
};
1045+
for (const std::string& feature_using_execve : features_using_execve) {
1046+
if (!args.GetArg(feature_using_execve, "").empty()) {
1047+
return InitError(Untranslated(strprintf("The experimental syscall sandbox feature (-sandbox=<mode>) is incompatible with %s (which uses execve).", feature_using_execve)));
1048+
}
1049+
}
1050+
if (!SetupSyscallSandbox(log_syscall_violation_before_terminating)) {
1051+
return InitError(Untranslated("Installation of the syscall sandbox failed."));
1052+
}
1053+
LogPrintf("Experimental syscall sandbox enabled (-sandbox=%s): bitcoind will terminate if an unexpected (not allowlisted) syscall is invoked.\n", sandbox_arg);
1054+
}
1055+
#endif // USE_SYSCALL_SANDBOX
1056+
10211057
return true;
10221058
}
10231059

src/logging.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ const CLogCategoryDesc LogCategories[] =
160160
{BCLog::I2P, "i2p"},
161161
{BCLog::IPC, "ipc"},
162162
{BCLog::LOCK, "lock"},
163+
{BCLog::UTIL, "util"},
163164
{BCLog::ALL, "1"},
164165
{BCLog::ALL, "all"},
165166
};

src/logging.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ namespace BCLog {
6060
I2P = (1 << 22),
6161
IPC = (1 << 23),
6262
LOCK = (1 << 24),
63+
UTIL = (1 << 25),
6364
ALL = ~(uint32_t)0,
6465
};
6566

0 commit comments

Comments
 (0)