mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-04-25 22:39:13 +02:00
Add syscall sandboxing (seccomp-bpf)
This commit is contained in:
@@ -24,3 +24,4 @@ RPCAUTH=@abs_top_srcdir@/share/rpcauth/rpcauth.py
|
||||
@ENABLE_FUZZ_TRUE@ENABLE_FUZZ=true
|
||||
@ENABLE_ZMQ_TRUE@ENABLE_ZMQ=true
|
||||
@ENABLE_EXTERNAL_SIGNER_TRUE@ENABLE_EXTERNAL_SIGNER=true
|
||||
@ENABLE_SYSCALL_SANDBOX_TRUE@ENABLE_SYSCALL_SANDBOX=true
|
||||
|
||||
@@ -27,6 +27,9 @@ class NotificationsTest(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 2
|
||||
self.setup_clean_chain = True
|
||||
# The experimental syscall sandbox feature (-sandbox) is not compatible with -alertnotify,
|
||||
# -blocknotify or -walletnotify (which all invoke execve).
|
||||
self.disable_syscall_sandbox = True
|
||||
|
||||
def setup_network(self):
|
||||
self.wallet = ''.join(chr(i) for i in range(FILE_CHAR_START, FILE_CHAR_END) if chr(i) not in FILE_CHARS_DISALLOWED)
|
||||
|
||||
34
test/functional/feature_syscall_sandbox.py
Executable file
34
test/functional/feature_syscall_sandbox.py
Executable file
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2021 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
"""Test bitcoind aborts if a disallowed syscall is used when compiled with the syscall sandbox."""
|
||||
|
||||
from test_framework.test_framework import BitcoinTestFramework, SkipTest
|
||||
|
||||
|
||||
class SyscallSandboxTest(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 1
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
if not self.is_syscall_sandbox_compiled():
|
||||
raise SkipTest("bitcoind has not been built with syscall sandbox enabled.")
|
||||
if self.options.nosandbox:
|
||||
raise SkipTest("--nosandbox passed to test runner.")
|
||||
|
||||
def run_test(self):
|
||||
disallowed_syscall_terminated_bitcoind = False
|
||||
expected_log_entry = 'ERROR: The syscall "getgroups" (syscall number 115) is not allowed by the syscall sandbox'
|
||||
with self.nodes[0].assert_debug_log([expected_log_entry]):
|
||||
self.log.info("Invoking disallowed syscall")
|
||||
try:
|
||||
self.nodes[0].invokedisallowedsyscall()
|
||||
except ConnectionError:
|
||||
disallowed_syscall_terminated_bitcoind = True
|
||||
assert disallowed_syscall_terminated_bitcoind
|
||||
self.nodes = []
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
SyscallSandboxTest().main()
|
||||
@@ -28,6 +28,9 @@ class VersionBitsWarningTest(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.setup_clean_chain = True
|
||||
self.num_nodes = 1
|
||||
# The experimental syscall sandbox feature (-sandbox) is not compatible with -alertnotify
|
||||
# (which invokes execve).
|
||||
self.disable_syscall_sandbox = True
|
||||
|
||||
def setup_network(self):
|
||||
self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt")
|
||||
|
||||
@@ -57,7 +57,7 @@ class RpcMiscTest(BitcoinTestFramework):
|
||||
self.log.info("test logging rpc and help")
|
||||
|
||||
# Test logging RPC returns the expected number of logging categories.
|
||||
assert_equal(len(node.logging()), 25)
|
||||
assert_equal(len(node.logging()), 26)
|
||||
|
||||
# Test toggling a logging category on/off/on with the logging RPC.
|
||||
assert_equal(node.logging()['qt'], True)
|
||||
|
||||
@@ -27,6 +27,9 @@ class RPCSignerTest(BitcoinTestFramework):
|
||||
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 4
|
||||
# The experimental syscall sandbox feature (-sandbox) is not compatible with -signer (which
|
||||
# invokes execve).
|
||||
self.disable_syscall_sandbox = True
|
||||
|
||||
self.extra_args = [
|
||||
[],
|
||||
|
||||
@@ -101,6 +101,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
||||
self.supports_cli = True
|
||||
self.bind_to_localhost_only = True
|
||||
self.parse_args()
|
||||
self.disable_syscall_sandbox = self.options.nosandbox
|
||||
self.default_wallet_name = "default_wallet" if self.options.descriptors else ""
|
||||
self.wallet_data_filename = "wallet.dat"
|
||||
# Optional list of wallet names that can be set in set_test_params to
|
||||
@@ -159,6 +160,8 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
||||
parser = argparse.ArgumentParser(usage="%(prog)s [options]")
|
||||
parser.add_argument("--nocleanup", dest="nocleanup", default=False, action="store_true",
|
||||
help="Leave bitcoinds and test.* datadir on exit or error")
|
||||
parser.add_argument("--nosandbox", dest="nosandbox", default=False, action="store_true",
|
||||
help="Don't use the syscall sandbox")
|
||||
parser.add_argument("--noshutdown", dest="noshutdown", default=False, action="store_true",
|
||||
help="Don't stop bitcoinds after the test execution")
|
||||
parser.add_argument("--cachedir", dest="cachedir", default=os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + "/../../cache"),
|
||||
@@ -468,6 +471,10 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
||||
extra_args = [[]] * num_nodes
|
||||
if versions is None:
|
||||
versions = [None] * num_nodes
|
||||
if self.is_syscall_sandbox_compiled() and not self.disable_syscall_sandbox:
|
||||
for i in range(len(extra_args)):
|
||||
if versions[i] is None or versions[i] >= 219900:
|
||||
extra_args[i] = extra_args[i] + ["-sandbox=log-and-abort"]
|
||||
if binary is None:
|
||||
binary = [get_bin_from_version(v, 'bitcoind', self.options.bitcoind) for v in versions]
|
||||
if binary_cli is None:
|
||||
@@ -886,3 +893,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
||||
def is_bdb_compiled(self):
|
||||
"""Checks whether the wallet module was compiled with BDB support."""
|
||||
return self.config["components"].getboolean("USE_BDB")
|
||||
|
||||
def is_syscall_sandbox_compiled(self):
|
||||
"""Checks whether the syscall sandbox was compiled."""
|
||||
return self.config["components"].getboolean("ENABLE_SYSCALL_SANDBOX")
|
||||
|
||||
@@ -170,6 +170,7 @@ BASE_SCRIPTS = [
|
||||
'rpc_users.py',
|
||||
'rpc_whitelist.py',
|
||||
'feature_proxy.py',
|
||||
'feature_syscall_sandbox.py',
|
||||
'rpc_signrawtransaction.py --legacy-wallet',
|
||||
'rpc_signrawtransaction.py --descriptors',
|
||||
'rpc_rawtransaction.py --legacy-wallet',
|
||||
|
||||
@@ -27,6 +27,9 @@ class WalletSignerTest(BitcoinTestFramework):
|
||||
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 2
|
||||
# The experimental syscall sandbox feature (-sandbox) is not compatible with -signer (which
|
||||
# invokes execve).
|
||||
self.disable_syscall_sandbox = True
|
||||
|
||||
self.extra_args = [
|
||||
[],
|
||||
|
||||
Reference in New Issue
Block a user