diff options
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/any.h | 26 | ||||
-rw-r--r-- | src/util/batchpriority.cpp | 26 | ||||
-rw-r--r-- | src/util/batchpriority.h | 15 | ||||
-rw-r--r-- | src/util/bip32.cpp | 8 | ||||
-rw-r--r-- | src/util/bip32.h | 4 | ||||
-rw-r--r-- | src/util/bytevectorhash.cpp | 2 | ||||
-rw-r--r-- | src/util/chaintype.cpp | 39 | ||||
-rw-r--r-- | src/util/chaintype.h | 22 | ||||
-rw-r--r-- | src/util/fs.h | 2 | ||||
-rw-r--r-- | src/util/hasher.cpp | 2 | ||||
-rw-r--r-- | src/util/insert.h | 24 | ||||
-rw-r--r-- | src/util/result.h | 5 | ||||
-rw-r--r-- | src/util/settings.cpp | 258 | ||||
-rw-r--r-- | src/util/settings.h | 114 | ||||
-rw-r--r-- | src/util/signalinterrupt.cpp | 74 | ||||
-rw-r--r-- | src/util/signalinterrupt.h | 52 | ||||
-rw-r--r-- | src/util/sock.cpp | 2 | ||||
-rw-r--r-- | src/util/strencodings.h | 4 | ||||
-rw-r--r-- | src/util/string.h | 4 | ||||
-rw-r--r-- | src/util/syscall_sandbox.cpp | 927 | ||||
-rw-r--r-- | src/util/syscall_sandbox.h | 54 | ||||
-rw-r--r-- | src/util/system.cpp | 125 | ||||
-rw-r--r-- | src/util/system.h | 72 | ||||
-rw-r--r-- | src/util/threadinterrupt.h | 16 | ||||
-rw-r--r-- | src/util/time.cpp | 13 | ||||
-rw-r--r-- | src/util/time.h | 3 | ||||
-rw-r--r-- | src/util/translation.h | 22 |
27 files changed, 316 insertions, 1599 deletions
diff --git a/src/util/any.h b/src/util/any.h new file mode 100644 index 0000000000..4562c5bd8a --- /dev/null +++ b/src/util/any.h @@ -0,0 +1,26 @@ +// Copyright (c) 2023 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_UTIL_ANY_H +#define BITCOIN_UTIL_ANY_H + +#include <any> + +namespace util { + +/** + * Helper function to access the contained object of a std::any instance. + * Returns a pointer to the object if passed instance has a value and the type + * matches, nullptr otherwise. + */ +template<typename T> +T* AnyPtr(const std::any& any) noexcept +{ + T* const* ptr = std::any_cast<T*>(&any); + return ptr ? *ptr : nullptr; +} + +} // namespace util + +#endif // BITCOIN_UTIL_ANY_H diff --git a/src/util/batchpriority.cpp b/src/util/batchpriority.cpp new file mode 100644 index 0000000000..c73aef1eb4 --- /dev/null +++ b/src/util/batchpriority.cpp @@ -0,0 +1,26 @@ +// Copyright (c) 2023 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <logging.h> +#include <util/syserror.h> + +#if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)) +#include <pthread.h> +#include <pthread_np.h> +#endif + +#ifndef WIN32 +#include <sched.h> +#endif + +void ScheduleBatchPriority() +{ +#ifdef SCHED_BATCH + const static sched_param param{}; + const int rc = pthread_setschedparam(pthread_self(), SCHED_BATCH, ¶m); + if (rc != 0) { + LogPrintf("Failed to pthread_setschedparam: %s\n", SysErrorString(rc)); + } +#endif +} diff --git a/src/util/batchpriority.h b/src/util/batchpriority.h new file mode 100644 index 0000000000..5ffc8dd684 --- /dev/null +++ b/src/util/batchpriority.h @@ -0,0 +1,15 @@ +// Copyright (c) 2023 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_UTIL_BATCHPRIORITY_H +#define BITCOIN_UTIL_BATCHPRIORITY_H + +/** + * On platforms that support it, tell the kernel the calling thread is + * CPU-intensive and non-interactive. See SCHED_BATCH in sched(7) for details. + * + */ +void ScheduleBatchPriority(); + +#endif // BITCOIN_UTIL_BATCHPRIORITY_H diff --git a/src/util/bip32.cpp b/src/util/bip32.cpp index c0ad9257ce..4ab14bd704 100644 --- a/src/util/bip32.cpp +++ b/src/util/bip32.cpp @@ -51,17 +51,17 @@ bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypa return true; } -std::string FormatHDKeypath(const std::vector<uint32_t>& path) +std::string FormatHDKeypath(const std::vector<uint32_t>& path, bool apostrophe) { std::string ret; for (auto i : path) { ret += strprintf("/%i", (i << 1) >> 1); - if (i >> 31) ret += '\''; + if (i >> 31) ret += apostrophe ? '\'' : 'h'; } return ret; } -std::string WriteHDKeypath(const std::vector<uint32_t>& keypath) +std::string WriteHDKeypath(const std::vector<uint32_t>& keypath, bool apostrophe) { - return "m" + FormatHDKeypath(keypath); + return "m" + FormatHDKeypath(keypath, apostrophe); } diff --git a/src/util/bip32.h b/src/util/bip32.h index b720cb5638..ea5f192c07 100644 --- a/src/util/bip32.h +++ b/src/util/bip32.h @@ -13,7 +13,7 @@ [[nodiscard]] bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath); /** Write HD keypaths as strings */ -std::string WriteHDKeypath(const std::vector<uint32_t>& keypath); -std::string FormatHDKeypath(const std::vector<uint32_t>& path); +std::string WriteHDKeypath(const std::vector<uint32_t>& keypath, bool apostrophe = false); +std::string FormatHDKeypath(const std::vector<uint32_t>& path, bool apostrophe = false); #endif // BITCOIN_UTIL_BIP32_H diff --git a/src/util/bytevectorhash.cpp b/src/util/bytevectorhash.cpp index 29be138eeb..92f1dbd5d8 100644 --- a/src/util/bytevectorhash.cpp +++ b/src/util/bytevectorhash.cpp @@ -16,5 +16,5 @@ ByteVectorHash::ByteVectorHash() : size_t ByteVectorHash::operator()(const std::vector<unsigned char>& input) const { - return CSipHasher(m_k0, m_k1).Write(input.data(), input.size()).Finalize(); + return CSipHasher(m_k0, m_k1).Write(input).Finalize(); } diff --git a/src/util/chaintype.cpp b/src/util/chaintype.cpp new file mode 100644 index 0000000000..8a199e352a --- /dev/null +++ b/src/util/chaintype.cpp @@ -0,0 +1,39 @@ +// Copyright (c) 2023 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <util/chaintype.h> + +#include <cassert> +#include <optional> +#include <string> + +std::string ChainTypeToString(ChainType chain) +{ + switch (chain) { + case ChainType::MAIN: + return "main"; + case ChainType::TESTNET: + return "test"; + case ChainType::SIGNET: + return "signet"; + case ChainType::REGTEST: + return "regtest"; + } + assert(false); +} + +std::optional<ChainType> ChainTypeFromString(std::string_view chain) +{ + if (chain == "main") { + return ChainType::MAIN; + } else if (chain == "test") { + return ChainType::TESTNET; + } else if (chain == "signet") { + return ChainType::SIGNET; + } else if (chain == "regtest") { + return ChainType::REGTEST; + } else { + return std::nullopt; + } +} diff --git a/src/util/chaintype.h b/src/util/chaintype.h new file mode 100644 index 0000000000..c73985df57 --- /dev/null +++ b/src/util/chaintype.h @@ -0,0 +1,22 @@ +// Copyright (c) 2023 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_UTIL_CHAINTYPE_H +#define BITCOIN_UTIL_CHAINTYPE_H + +#include <optional> +#include <string> + +enum class ChainType { + MAIN, + TESTNET, + SIGNET, + REGTEST, +}; + +std::string ChainTypeToString(ChainType chain); + +std::optional<ChainType> ChainTypeFromString(std::string_view chain); + +#endif // BITCOIN_UTIL_CHAINTYPE_H diff --git a/src/util/fs.h b/src/util/fs.h index 886a30394e..8f79f6cba6 100644 --- a/src/util/fs.h +++ b/src/util/fs.h @@ -8,7 +8,7 @@ #include <tinyformat.h> #include <cstdio> -#include <filesystem> +#include <filesystem> // IWYU pragma: export #include <functional> #include <iomanip> #include <ios> diff --git a/src/util/hasher.cpp b/src/util/hasher.cpp index 81e9b990e1..f571725786 100644 --- a/src/util/hasher.cpp +++ b/src/util/hasher.cpp @@ -18,5 +18,5 @@ SaltedSipHasher::SaltedSipHasher() : m_k0(GetRand<uint64_t>()), m_k1(GetRand<uin size_t SaltedSipHasher::operator()(const Span<const unsigned char>& script) const { - return CSipHasher(m_k0, m_k1).Write(script.data(), script.size()).Finalize(); + return CSipHasher(m_k0, m_k1).Write(script).Finalize(); } diff --git a/src/util/insert.h b/src/util/insert.h new file mode 100644 index 0000000000..5332eca60a --- /dev/null +++ b/src/util/insert.h @@ -0,0 +1,24 @@ +// Copyright (c) 2023 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_UTIL_INSERT_H +#define BITCOIN_UTIL_INSERT_H + +#include <set> + +namespace util { + +//! Simplification of std insertion +template <typename Tdst, typename Tsrc> +inline void insert(Tdst& dst, const Tsrc& src) { + dst.insert(dst.begin(), src.begin(), src.end()); +} +template <typename TsetT, typename Tsrc> +inline void insert(std::set<TsetT>& dst, const Tsrc& src) { + dst.insert(src.begin(), src.end()); +} + +} // namespace util + +#endif // BITCOIN_UTIL_INSERT_H diff --git a/src/util/result.h b/src/util/result.h index 972b1aada0..b99995c7e5 100644 --- a/src/util/result.h +++ b/src/util/result.h @@ -31,16 +31,19 @@ struct Error { //! `std::optional<T>` can be updated to return `util::Result<T>` and return //! error strings usually just replacing `return std::nullopt;` with `return //! util::Error{error_string};`. -template <class T> +template <class M> class Result { private: + using T = std::conditional_t<std::is_same_v<M, void>, std::monostate, M>; + std::variant<bilingual_str, T> m_variant; template <typename FT> friend bilingual_str ErrorString(const Result<FT>& result); public: + Result() : m_variant{std::in_place_index_t<1>{}, std::monostate{}} {} // constructor for void Result(T obj) : m_variant{std::in_place_index_t<1>{}, std::move(obj)} {} Result(Error error) : m_variant{std::in_place_index_t<0>{}, std::move(error.message)} {} diff --git a/src/util/settings.cpp b/src/util/settings.cpp deleted file mode 100644 index bb257c0584..0000000000 --- a/src/util/settings.cpp +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright (c) 2019-2022 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include <util/fs.h> -#include <util/settings.h> - -#include <tinyformat.h> -#include <univalue.h> - -#include <fstream> -#include <map> -#include <string> -#include <vector> - -namespace util { -namespace { - -enum class Source { - FORCED, - COMMAND_LINE, - RW_SETTINGS, - CONFIG_FILE_NETWORK_SECTION, - CONFIG_FILE_DEFAULT_SECTION -}; - -//! Merge settings from multiple sources in precedence order: -//! Forced config > command line > read-write settings file > config file network-specific section > config file default section -//! -//! This function is provided with a callback function fn that contains -//! specific logic for how to merge the sources. -template <typename Fn> -static void MergeSettings(const Settings& settings, const std::string& section, const std::string& name, Fn&& fn) -{ - // Merge in the forced settings - if (auto* value = FindKey(settings.forced_settings, name)) { - fn(SettingsSpan(*value), Source::FORCED); - } - // Merge in the command-line options - if (auto* values = FindKey(settings.command_line_options, name)) { - fn(SettingsSpan(*values), Source::COMMAND_LINE); - } - // Merge in the read-write settings - if (const SettingsValue* value = FindKey(settings.rw_settings, name)) { - fn(SettingsSpan(*value), Source::RW_SETTINGS); - } - // Merge in the network-specific section of the config file - if (!section.empty()) { - if (auto* map = FindKey(settings.ro_config, section)) { - if (auto* values = FindKey(*map, name)) { - fn(SettingsSpan(*values), Source::CONFIG_FILE_NETWORK_SECTION); - } - } - } - // Merge in the default section of the config file - if (auto* map = FindKey(settings.ro_config, "")) { - if (auto* values = FindKey(*map, name)) { - fn(SettingsSpan(*values), Source::CONFIG_FILE_DEFAULT_SECTION); - } - } -} -} // namespace - -bool ReadSettings(const fs::path& path, std::map<std::string, SettingsValue>& values, std::vector<std::string>& errors) -{ - values.clear(); - errors.clear(); - - // Ok for file to not exist - if (!fs::exists(path)) return true; - - std::ifstream file; - file.open(path); - if (!file.is_open()) { - errors.emplace_back(strprintf("%s. Please check permissions.", fs::PathToString(path))); - return false; - } - - SettingsValue in; - if (!in.read(std::string{std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()})) { - errors.emplace_back(strprintf("Unable to parse settings file %s", fs::PathToString(path))); - return false; - } - - if (file.fail()) { - errors.emplace_back(strprintf("Failed reading settings file %s", fs::PathToString(path))); - return false; - } - file.close(); // Done with file descriptor. Release while copying data. - - if (!in.isObject()) { - errors.emplace_back(strprintf("Found non-object value %s in settings file %s", in.write(), fs::PathToString(path))); - return false; - } - - const std::vector<std::string>& in_keys = in.getKeys(); - const std::vector<SettingsValue>& in_values = in.getValues(); - for (size_t i = 0; i < in_keys.size(); ++i) { - auto inserted = values.emplace(in_keys[i], in_values[i]); - if (!inserted.second) { - errors.emplace_back(strprintf("Found duplicate key %s in settings file %s", in_keys[i], fs::PathToString(path))); - values.clear(); - break; - } - } - return errors.empty(); -} - -bool WriteSettings(const fs::path& path, - const std::map<std::string, SettingsValue>& values, - std::vector<std::string>& errors) -{ - SettingsValue out(SettingsValue::VOBJ); - for (const auto& value : values) { - out.__pushKV(value.first, value.second); - } - std::ofstream file; - file.open(path); - if (file.fail()) { - errors.emplace_back(strprintf("Error: Unable to open settings file %s for writing", fs::PathToString(path))); - return false; - } - file << out.write(/* prettyIndent= */ 4, /* indentLevel= */ 1) << std::endl; - file.close(); - return true; -} - -SettingsValue GetSetting(const Settings& settings, - const std::string& section, - const std::string& name, - bool ignore_default_section_config, - bool ignore_nonpersistent, - bool get_chain_name) -{ - SettingsValue result; - bool done = false; // Done merging any more settings sources. - MergeSettings(settings, section, name, [&](SettingsSpan span, Source source) { - // Weird behavior preserved for backwards compatibility: Apply negated - // setting even if non-negated setting would be ignored. A negated - // value in the default section is applied to network specific options, - // even though normal non-negated values there would be ignored. - const bool never_ignore_negated_setting = span.last_negated(); - - // Weird behavior preserved for backwards compatibility: Take first - // assigned value instead of last. In general, later settings take - // precedence over early settings, but for backwards compatibility in - // the config file the precedence is reversed for all settings except - // chain name settings. - const bool reverse_precedence = - (source == Source::CONFIG_FILE_NETWORK_SECTION || source == Source::CONFIG_FILE_DEFAULT_SECTION) && - !get_chain_name; - - // Weird behavior preserved for backwards compatibility: Negated - // -regtest and -testnet arguments which you would expect to override - // values set in the configuration file are currently accepted but - // silently ignored. It would be better to apply these just like other - // negated values, or at least warn they are ignored. - const bool skip_negated_command_line = get_chain_name; - - if (done) return; - - // Ignore settings in default config section if requested. - if (ignore_default_section_config && source == Source::CONFIG_FILE_DEFAULT_SECTION && - !never_ignore_negated_setting) { - return; - } - - // Ignore nonpersistent settings if requested. - if (ignore_nonpersistent && (source == Source::COMMAND_LINE || source == Source::FORCED)) return; - - // Skip negated command line settings. - if (skip_negated_command_line && span.last_negated()) return; - - if (!span.empty()) { - result = reverse_precedence ? span.begin()[0] : span.end()[-1]; - done = true; - } else if (span.last_negated()) { - result = false; - done = true; - } - }); - return result; -} - -std::vector<SettingsValue> GetSettingsList(const Settings& settings, - const std::string& section, - const std::string& name, - bool ignore_default_section_config) -{ - std::vector<SettingsValue> result; - bool done = false; // Done merging any more settings sources. - bool prev_negated_empty = false; - MergeSettings(settings, section, name, [&](SettingsSpan span, Source source) { - // Weird behavior preserved for backwards compatibility: Apply config - // file settings even if negated on command line. Negating a setting on - // command line will ignore earlier settings on the command line and - // ignore settings in the config file, unless the negated command line - // value is followed by non-negated value, in which case config file - // settings will be brought back from the dead (but earlier command - // line settings will still be ignored). - const bool add_zombie_config_values = - (source == Source::CONFIG_FILE_NETWORK_SECTION || source == Source::CONFIG_FILE_DEFAULT_SECTION) && - !prev_negated_empty; - - // Ignore settings in default config section if requested. - if (ignore_default_section_config && source == Source::CONFIG_FILE_DEFAULT_SECTION) return; - - // Add new settings to the result if isn't already complete, or if the - // values are zombies. - if (!done || add_zombie_config_values) { - for (const auto& value : span) { - if (value.isArray()) { - result.insert(result.end(), value.getValues().begin(), value.getValues().end()); - } else { - result.push_back(value); - } - } - } - - // If a setting was negated, or if a setting was forced, set - // done to true to ignore any later lower priority settings. - done |= span.negated() > 0 || source == Source::FORCED; - - // Update the negated and empty state used for the zombie values check. - prev_negated_empty |= span.last_negated() && result.empty(); - }); - return result; -} - -bool OnlyHasDefaultSectionSetting(const Settings& settings, const std::string& section, const std::string& name) -{ - bool has_default_section_setting = false; - bool has_other_setting = false; - MergeSettings(settings, section, name, [&](SettingsSpan span, Source source) { - if (span.empty()) return; - else if (source == Source::CONFIG_FILE_DEFAULT_SECTION) has_default_section_setting = true; - else has_other_setting = true; - }); - // If a value is set in the default section and not explicitly overwritten by the - // user on the command line or in a different section, then we want to enable - // warnings about the value being ignored. - return has_default_section_setting && !has_other_setting; -} - -SettingsSpan::SettingsSpan(const std::vector<SettingsValue>& vec) noexcept : SettingsSpan(vec.data(), vec.size()) {} -const SettingsValue* SettingsSpan::begin() const { return data + negated(); } -const SettingsValue* SettingsSpan::end() const { return data + size; } -bool SettingsSpan::empty() const { return size == 0 || last_negated(); } -bool SettingsSpan::last_negated() const { return size > 0 && data[size - 1].isFalse(); } -size_t SettingsSpan::negated() const -{ - for (size_t i = size; i > 0; --i) { - if (data[i - 1].isFalse()) return i; // Return number of negated values (position of last false value) - } - return 0; -} - -} // namespace util diff --git a/src/util/settings.h b/src/util/settings.h deleted file mode 100644 index 27e87a4751..0000000000 --- a/src/util/settings.h +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) 2019-2022 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_UTIL_SETTINGS_H -#define BITCOIN_UTIL_SETTINGS_H - -#include <util/fs.h> - -#include <map> -#include <string> -#include <vector> - -class UniValue; - -namespace util { - -//! Settings value type (string/integer/boolean/null variant). -//! -//! @note UniValue is used here for convenience and because it can be easily -//! serialized in a readable format. But any other variant type that can -//! be assigned strings, int64_t, and bool values and has get_str(), -//! getInt<int64_t>(), get_bool(), isNum(), isBool(), isFalse(), isTrue() and -//! isNull() methods can be substituted if there's a need to move away -//! from UniValue. (An implementation with boost::variant was posted at -//! https://github.com/bitcoin/bitcoin/pull/15934/files#r337691812) -using SettingsValue = UniValue; - -//! Stored settings. This struct combines settings from the command line, a -//! read-only configuration file, and a read-write runtime settings file. -struct Settings { - //! Map of setting name to forced setting value. - std::map<std::string, SettingsValue> forced_settings; - //! Map of setting name to list of command line values. - std::map<std::string, std::vector<SettingsValue>> command_line_options; - //! Map of setting name to read-write file setting value. - std::map<std::string, SettingsValue> rw_settings; - //! Map of config section name and setting name to list of config file values. - std::map<std::string, std::map<std::string, std::vector<SettingsValue>>> ro_config; -}; - -//! Read settings file. -bool ReadSettings(const fs::path& path, - std::map<std::string, SettingsValue>& values, - std::vector<std::string>& errors); - -//! Write settings file. -bool WriteSettings(const fs::path& path, - const std::map<std::string, SettingsValue>& values, - std::vector<std::string>& errors); - -//! Get settings value from combined sources: forced settings, command line -//! arguments, runtime read-write settings, and the read-only config file. -//! -//! @param ignore_default_section_config - ignore values in the default section -//! of the config file (part before any -//! [section] keywords) -//! @param ignore_nonpersistent - ignore non-persistent settings values (forced -//! settings values and values specified on the -//! command line). Only return settings in the -//! read-only config and read-write settings -//! files. -//! @param get_chain_name - enable special backwards compatible behavior -//! for GetChainName -SettingsValue GetSetting(const Settings& settings, - const std::string& section, - const std::string& name, - bool ignore_default_section_config, - bool ignore_nonpersistent, - bool get_chain_name); - -//! Get combined setting value similar to GetSetting(), except if setting was -//! specified multiple times, return a list of all the values specified. -std::vector<SettingsValue> GetSettingsList(const Settings& settings, - const std::string& section, - const std::string& name, - bool ignore_default_section_config); - -//! Return true if a setting is set in the default config file section, and not -//! overridden by a higher priority command-line or network section value. -//! -//! This is used to provide user warnings about values that might be getting -//! ignored unintentionally. -bool OnlyHasDefaultSectionSetting(const Settings& settings, const std::string& section, const std::string& name); - -//! Accessor for list of settings that skips negated values when iterated over. -//! The last boolean `false` value in the list and all earlier values are -//! considered negated. -struct SettingsSpan { - explicit SettingsSpan() = default; - explicit SettingsSpan(const SettingsValue& value) noexcept : SettingsSpan(&value, 1) {} - explicit SettingsSpan(const SettingsValue* data, size_t size) noexcept : data(data), size(size) {} - explicit SettingsSpan(const std::vector<SettingsValue>& vec) noexcept; - const SettingsValue* begin() const; //!< Pointer to first non-negated value. - const SettingsValue* end() const; //!< Pointer to end of values. - bool empty() const; //!< True if there are any non-negated values. - bool last_negated() const; //!< True if the last value is negated. - size_t negated() const; //!< Number of negated values. - - const SettingsValue* data = nullptr; - size_t size = 0; -}; - -//! Map lookup helper. -template <typename Map, typename Key> -auto FindKey(Map&& map, Key&& key) -> decltype(&map.at(key)) -{ - auto it = map.find(key); - return it == map.end() ? nullptr : &it->second; -} - -} // namespace util - -#endif // BITCOIN_UTIL_SETTINGS_H diff --git a/src/util/signalinterrupt.cpp b/src/util/signalinterrupt.cpp new file mode 100644 index 0000000000..c551ba8044 --- /dev/null +++ b/src/util/signalinterrupt.cpp @@ -0,0 +1,74 @@ +// Copyright (c) 2022 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <util/signalinterrupt.h> + +#ifdef WIN32 +#include <mutex> +#else +#include <util/tokenpipe.h> +#endif + +#include <ios> +#include <optional> + +namespace util { + +SignalInterrupt::SignalInterrupt() : m_flag{false} +{ +#ifndef WIN32 + std::optional<TokenPipe> pipe = TokenPipe::Make(); + if (!pipe) throw std::ios_base::failure("Could not create TokenPipe"); + m_pipe_r = pipe->TakeReadEnd(); + m_pipe_w = pipe->TakeWriteEnd(); +#endif +} + +SignalInterrupt::operator bool() const +{ + return m_flag; +} + +void SignalInterrupt::reset() +{ + // Cancel existing interrupt by waiting for it, this will reset condition flags and remove + // the token from the pipe. + if (*this) wait(); + m_flag = false; +} + +void SignalInterrupt::operator()() +{ +#ifdef WIN32 + std::unique_lock<std::mutex> lk(m_mutex); + m_flag = true; + m_cv.notify_one(); +#else + // This must be reentrant and safe for calling in a signal handler, so using a condition variable is not safe. + // Make sure that the token is only written once even if multiple threads call this concurrently or in + // case of a reentrant signal. + if (!m_flag.exchange(true)) { + // Write an arbitrary byte to the write end of the pipe. + int res = m_pipe_w.TokenWrite('x'); + if (res != 0) { + throw std::ios_base::failure("Could not write interrupt token"); + } + } +#endif +} + +void SignalInterrupt::wait() +{ +#ifdef WIN32 + std::unique_lock<std::mutex> lk(m_mutex); + m_cv.wait(lk, [this] { return m_flag.load(); }); +#else + int res = m_pipe_r.TokenRead(); + if (res != 'x') { + throw std::ios_base::failure("Did not read expected interrupt token"); + } +#endif +} + +} // namespace util diff --git a/src/util/signalinterrupt.h b/src/util/signalinterrupt.h new file mode 100644 index 0000000000..ca02feda91 --- /dev/null +++ b/src/util/signalinterrupt.h @@ -0,0 +1,52 @@ +// Copyright (c) 2023 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_UTIL_SIGNALINTERRUPT_H +#define BITCOIN_UTIL_SIGNALINTERRUPT_H + +#ifdef WIN32 +#include <condition_variable> +#include <mutex> +#else +#include <util/tokenpipe.h> +#endif + +#include <atomic> +#include <cstdlib> + +namespace util { +/** + * Helper class that manages an interrupt flag, and allows a thread or + * signal to interrupt another thread. + * + * This class is safe to be used in a signal handler. If sending an interrupt + * from a signal handler is not necessary, the more lightweight \ref + * CThreadInterrupt class can be used instead. + */ + +class SignalInterrupt +{ +public: + SignalInterrupt(); + explicit operator bool() const; + void operator()(); + void reset(); + void wait(); + +private: + std::atomic<bool> m_flag; + +#ifndef WIN32 + // On UNIX-like operating systems use the self-pipe trick. + TokenPipeEnd m_pipe_r; + TokenPipeEnd m_pipe_w; +#else + // On windows use a condition variable, since we don't have any signals there + std::mutex m_mutex; + std::condition_variable m_cv; +#endif +}; +} // namespace util + +#endif // BITCOIN_UTIL_SIGNALINTERRUPT_H diff --git a/src/util/sock.cpp b/src/util/sock.cpp index f244f38f3f..fd64cae404 100644 --- a/src/util/sock.cpp +++ b/src/util/sock.cpp @@ -2,12 +2,12 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <common/system.h> #include <compat/compat.h> #include <logging.h> #include <tinyformat.h> #include <util/sock.h> #include <util/syserror.h> -#include <util/system.h> #include <util/threadinterrupt.h> #include <util/time.h> diff --git a/src/util/strencodings.h b/src/util/strencodings.h index 05e7b957c4..d792562735 100644 --- a/src/util/strencodings.h +++ b/src/util/strencodings.h @@ -17,8 +17,8 @@ #include <cstdint> #include <limits> #include <optional> -#include <string> -#include <string_view> +#include <string> // IWYU pragma: export +#include <string_view> // IWYU pragma: export #include <system_error> #include <type_traits> #include <vector> diff --git a/src/util/string.h b/src/util/string.h index fb93d2a80e..8b69d6ccae 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -12,8 +12,8 @@ #include <cstring> #include <locale> #include <sstream> -#include <string> -#include <string_view> +#include <string> // IWYU pragma: export +#include <string_view> // IWYU pragma: export #include <vector> void ReplaceAll(std::string& in_out, const std::string& search, const std::string& substitute); diff --git a/src/util/syscall_sandbox.cpp b/src/util/syscall_sandbox.cpp deleted file mode 100644 index b1579bdb9c..0000000000 --- a/src/util/syscall_sandbox.cpp +++ /dev/null @@ -1,927 +0,0 @@ -// Copyright (c) 2020-2022 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#if defined(HAVE_CONFIG_H) -#include <config/bitcoin-config.h> -#endif // defined(HAVE_CONFIG_H) - -#include <util/syscall_sandbox.h> - -#if defined(USE_SYSCALL_SANDBOX) -#include <array> -#include <cassert> -#include <cstdint> -#include <exception> -#include <map> -#include <new> -#include <set> -#include <string> -#include <vector> - -#include <logging.h> -#include <tinyformat.h> -#include <util/threadnames.h> - -#include <linux/audit.h> -#include <linux/filter.h> -#include <linux/seccomp.h> -#include <linux/unistd.h> -#include <signal.h> -#include <sys/prctl.h> -#include <sys/types.h> -#include <unistd.h> - -namespace { -bool g_syscall_sandbox_enabled{false}; -bool g_syscall_sandbox_log_violation_before_terminating{false}; - -#if !defined(__x86_64__) -#error Syscall sandbox is an experimental feature currently available only under Linux x86-64. -#endif // defined(__x86_64__) - -#ifndef SECCOMP_RET_KILL_PROCESS -#define SECCOMP_RET_KILL_PROCESS 0x80000000U -#endif - -// Define system call numbers for x86_64 that are referenced in the system call profile -// but not provided by the kernel headers used in the GUIX build. -// Usually, they can be found via "grep name /usr/include/x86_64-linux-gnu/asm/unistd_64.h" - -#ifndef __NR_clone3 -#define __NR_clone3 435 -#endif - -#ifndef __NR_statx -#define __NR_statx 332 -#endif - -#ifndef __NR_getrandom -#define __NR_getrandom 318 -#endif - -#ifndef __NR_membarrier -#define __NR_membarrier 324 -#endif - -#ifndef __NR_copy_file_range -#define __NR_copy_file_range 326 -#endif - -#ifndef __NR_rseq -#define __NR_rseq 334 -#endif - -// This list of syscalls in LINUX_SYSCALLS is only used to map syscall numbers to syscall names in -// order to be able to print user friendly error messages which include the syscall name in addition -// to the syscall number. -// -// Example output in case of a syscall violation where the syscall is present in LINUX_SYSCALLS: -// -// ``` -// 2021-06-09T12:34:56Z ERROR: The syscall "execve" (syscall number 59) is not allowed by the syscall sandbox in thread "msghand". Please report. -// ``` -// -// Example output in case of a syscall violation where the syscall is not present in LINUX_SYSCALLS: -// -// ``` -// 2021-06-09T12:34:56Z ERROR: The syscall "*unknown*" (syscall number 314) is not allowed by the syscall sandbox in thread "msghand". Please report. -// `` -// -// LINUX_SYSCALLS contains two types of syscalls: -// 1.) Syscalls that are present under all architectures or relevant Linux kernel versions for which -// we support the syscall sandbox feature (currently only Linux x86-64). Examples include read, -// write, open, close, etc. -// 2.) Syscalls that are present under a subset of architectures or relevant Linux kernel versions -// for which we support the syscall sandbox feature. This type of syscalls should be added to -// LINUX_SYSCALLS conditional on availability like in the following example: -// ... -// #if defined(__NR_arch_dependent_syscall) -// {__NR_arch_dependent_syscall, "arch_dependent_syscall"}, -// #endif // defined(__NR_arch_dependent_syscall) -// ... -const std::map<uint32_t, std::string> LINUX_SYSCALLS{ - {__NR_accept, "accept"}, - {__NR_accept4, "accept4"}, - {__NR_access, "access"}, - {__NR_acct, "acct"}, - {__NR_add_key, "add_key"}, - {__NR_adjtimex, "adjtimex"}, - {__NR_afs_syscall, "afs_syscall"}, - {__NR_alarm, "alarm"}, - {__NR_arch_prctl, "arch_prctl"}, - {__NR_bind, "bind"}, - {__NR_bpf, "bpf"}, - {__NR_brk, "brk"}, - {__NR_capget, "capget"}, - {__NR_capset, "capset"}, - {__NR_chdir, "chdir"}, - {__NR_chmod, "chmod"}, - {__NR_chown, "chown"}, - {__NR_chroot, "chroot"}, - {__NR_clock_adjtime, "clock_adjtime"}, - {__NR_clock_getres, "clock_getres"}, - {__NR_clock_gettime, "clock_gettime"}, - {__NR_clock_nanosleep, "clock_nanosleep"}, - {__NR_clock_settime, "clock_settime"}, - {__NR_clone, "clone"}, - {__NR_clone3, "clone3"}, - {__NR_close, "close"}, - {__NR_connect, "connect"}, - {__NR_copy_file_range, "copy_file_range"}, - {__NR_creat, "creat"}, - {__NR_create_module, "create_module"}, - {__NR_delete_module, "delete_module"}, - {__NR_dup, "dup"}, - {__NR_dup2, "dup2"}, - {__NR_dup3, "dup3"}, - {__NR_epoll_create, "epoll_create"}, - {__NR_epoll_create1, "epoll_create1"}, - {__NR_epoll_ctl, "epoll_ctl"}, - {__NR_epoll_ctl_old, "epoll_ctl_old"}, - {__NR_epoll_pwait, "epoll_pwait"}, - {__NR_epoll_wait, "epoll_wait"}, - {__NR_epoll_wait_old, "epoll_wait_old"}, - {__NR_eventfd, "eventfd"}, - {__NR_eventfd2, "eventfd2"}, - {__NR_execve, "execve"}, - {__NR_execveat, "execveat"}, - {__NR_exit, "exit"}, - {__NR_exit_group, "exit_group"}, - {__NR_faccessat, "faccessat"}, - {__NR_fadvise64, "fadvise64"}, - {__NR_fallocate, "fallocate"}, - {__NR_fanotify_init, "fanotify_init"}, - {__NR_fanotify_mark, "fanotify_mark"}, - {__NR_fchdir, "fchdir"}, - {__NR_fchmod, "fchmod"}, - {__NR_fchmodat, "fchmodat"}, - {__NR_fchown, "fchown"}, - {__NR_fchownat, "fchownat"}, - {__NR_fcntl, "fcntl"}, - {__NR_fdatasync, "fdatasync"}, - {__NR_fgetxattr, "fgetxattr"}, - {__NR_finit_module, "finit_module"}, - {__NR_flistxattr, "flistxattr"}, - {__NR_flock, "flock"}, - {__NR_fork, "fork"}, - {__NR_fremovexattr, "fremovexattr"}, - {__NR_fsetxattr, "fsetxattr"}, - {__NR_fstat, "fstat"}, - {__NR_fstatfs, "fstatfs"}, - {__NR_fsync, "fsync"}, - {__NR_ftruncate, "ftruncate"}, - {__NR_futex, "futex"}, - {__NR_futimesat, "futimesat"}, - {__NR_get_kernel_syms, "get_kernel_syms"}, - {__NR_get_mempolicy, "get_mempolicy"}, - {__NR_get_robust_list, "get_robust_list"}, - {__NR_get_thread_area, "get_thread_area"}, - {__NR_getcpu, "getcpu"}, - {__NR_getcwd, "getcwd"}, - {__NR_getdents, "getdents"}, - {__NR_getdents64, "getdents64"}, - {__NR_getegid, "getegid"}, - {__NR_geteuid, "geteuid"}, - {__NR_getgid, "getgid"}, - {__NR_getgroups, "getgroups"}, - {__NR_getitimer, "getitimer"}, - {__NR_getpeername, "getpeername"}, - {__NR_getpgid, "getpgid"}, - {__NR_getpgrp, "getpgrp"}, - {__NR_getpid, "getpid"}, - {__NR_getpmsg, "getpmsg"}, - {__NR_getppid, "getppid"}, - {__NR_getpriority, "getpriority"}, - {__NR_getrandom, "getrandom"}, - {__NR_getresgid, "getresgid"}, - {__NR_getresuid, "getresuid"}, - {__NR_getrlimit, "getrlimit"}, - {__NR_getrusage, "getrusage"}, - {__NR_getsid, "getsid"}, - {__NR_getsockname, "getsockname"}, - {__NR_getsockopt, "getsockopt"}, - {__NR_gettid, "gettid"}, - {__NR_gettimeofday, "gettimeofday"}, - {__NR_getuid, "getuid"}, - {__NR_getxattr, "getxattr"}, - {__NR_init_module, "init_module"}, - {__NR_inotify_add_watch, "inotify_add_watch"}, - {__NR_inotify_init, "inotify_init"}, - {__NR_inotify_init1, "inotify_init1"}, - {__NR_inotify_rm_watch, "inotify_rm_watch"}, - {__NR_io_cancel, "io_cancel"}, - {__NR_io_destroy, "io_destroy"}, - {__NR_io_getevents, "io_getevents"}, - {__NR_io_setup, "io_setup"}, - {__NR_io_submit, "io_submit"}, - {__NR_ioctl, "ioctl"}, - {__NR_ioperm, "ioperm"}, - {__NR_iopl, "iopl"}, - {__NR_ioprio_get, "ioprio_get"}, - {__NR_ioprio_set, "ioprio_set"}, - {__NR_kcmp, "kcmp"}, - {__NR_kexec_file_load, "kexec_file_load"}, - {__NR_kexec_load, "kexec_load"}, - {__NR_keyctl, "keyctl"}, - {__NR_kill, "kill"}, - {__NR_lchown, "lchown"}, - {__NR_lgetxattr, "lgetxattr"}, - {__NR_link, "link"}, - {__NR_linkat, "linkat"}, - {__NR_listen, "listen"}, - {__NR_listxattr, "listxattr"}, - {__NR_llistxattr, "llistxattr"}, - {__NR_lookup_dcookie, "lookup_dcookie"}, - {__NR_lremovexattr, "lremovexattr"}, - {__NR_lseek, "lseek"}, - {__NR_lsetxattr, "lsetxattr"}, - {__NR_lstat, "lstat"}, - {__NR_madvise, "madvise"}, - {__NR_mbind, "mbind"}, - {__NR_membarrier, "membarrier"}, - {__NR_memfd_create, "memfd_create"}, - {__NR_migrate_pages, "migrate_pages"}, - {__NR_mincore, "mincore"}, - {__NR_mkdir, "mkdir"}, - {__NR_mkdirat, "mkdirat"}, - {__NR_mknod, "mknod"}, - {__NR_mknodat, "mknodat"}, - {__NR_mlock, "mlock"}, - {__NR_mlock2, "mlock2"}, - {__NR_mlockall, "mlockall"}, - {__NR_mmap, "mmap"}, - {__NR_modify_ldt, "modify_ldt"}, - {__NR_mount, "mount"}, - {__NR_move_pages, "move_pages"}, - {__NR_mprotect, "mprotect"}, - {__NR_mq_getsetattr, "mq_getsetattr"}, - {__NR_mq_notify, "mq_notify"}, - {__NR_mq_open, "mq_open"}, - {__NR_mq_timedreceive, "mq_timedreceive"}, - {__NR_mq_timedsend, "mq_timedsend"}, - {__NR_mq_unlink, "mq_unlink"}, - {__NR_mremap, "mremap"}, - {__NR_msgctl, "msgctl"}, - {__NR_msgget, "msgget"}, - {__NR_msgrcv, "msgrcv"}, - {__NR_msgsnd, "msgsnd"}, - {__NR_msync, "msync"}, - {__NR_munlock, "munlock"}, - {__NR_munlockall, "munlockall"}, - {__NR_munmap, "munmap"}, - {__NR_name_to_handle_at, "name_to_handle_at"}, - {__NR_nanosleep, "nanosleep"}, - {__NR_newfstatat, "newfstatat"}, - {__NR_nfsservctl, "nfsservctl"}, - {__NR_open, "open"}, - {__NR_open_by_handle_at, "open_by_handle_at"}, - {__NR_openat, "openat"}, - {__NR_pause, "pause"}, - {__NR_perf_event_open, "perf_event_open"}, - {__NR_personality, "personality"}, - {__NR_pipe, "pipe"}, - {__NR_pipe2, "pipe2"}, - {__NR_pivot_root, "pivot_root"}, -#ifdef __NR_pkey_alloc - {__NR_pkey_alloc, "pkey_alloc"}, -#endif -#ifdef __NR_pkey_free - {__NR_pkey_free, "pkey_free"}, -#endif -#ifdef __NR_pkey_mprotect - {__NR_pkey_mprotect, "pkey_mprotect"}, -#endif - {__NR_poll, "poll"}, - {__NR_ppoll, "ppoll"}, - {__NR_prctl, "prctl"}, - {__NR_pread64, "pread64"}, - {__NR_preadv, "preadv"}, -#ifdef __NR_preadv2 - {__NR_preadv2, "preadv2"}, -#endif - {__NR_prlimit64, "prlimit64"}, - {__NR_process_vm_readv, "process_vm_readv"}, - {__NR_process_vm_writev, "process_vm_writev"}, - {__NR_pselect6, "pselect6"}, - {__NR_ptrace, "ptrace"}, - {__NR_putpmsg, "putpmsg"}, - {__NR_pwrite64, "pwrite64"}, - {__NR_pwritev, "pwritev"}, -#ifdef __NR_pwritev2 - {__NR_pwritev2, "pwritev2"}, -#endif - {__NR__sysctl, "_sysctl"}, - {__NR_query_module, "query_module"}, - {__NR_quotactl, "quotactl"}, - {__NR_read, "read"}, - {__NR_readahead, "readahead"}, - {__NR_readlink, "readlink"}, - {__NR_readlinkat, "readlinkat"}, - {__NR_readv, "readv"}, - {__NR_reboot, "reboot"}, - {__NR_recvfrom, "recvfrom"}, - {__NR_recvmmsg, "recvmmsg"}, - {__NR_recvmsg, "recvmsg"}, - {__NR_remap_file_pages, "remap_file_pages"}, - {__NR_removexattr, "removexattr"}, - {__NR_rename, "rename"}, - {__NR_renameat, "renameat"}, - {__NR_renameat2, "renameat2"}, - {__NR_request_key, "request_key"}, - {__NR_restart_syscall, "restart_syscall"}, - {__NR_rmdir, "rmdir"}, - {__NR_rseq, "rseq"}, - {__NR_rt_sigaction, "rt_sigaction"}, - {__NR_rt_sigpending, "rt_sigpending"}, - {__NR_rt_sigprocmask, "rt_sigprocmask"}, - {__NR_rt_sigqueueinfo, "rt_sigqueueinfo"}, - {__NR_rt_sigreturn, "rt_sigreturn"}, - {__NR_rt_sigsuspend, "rt_sigsuspend"}, - {__NR_rt_sigtimedwait, "rt_sigtimedwait"}, - {__NR_rt_tgsigqueueinfo, "rt_tgsigqueueinfo"}, - {__NR_sched_get_priority_max, "sched_get_priority_max"}, - {__NR_sched_get_priority_min, "sched_get_priority_min"}, - {__NR_sched_getaffinity, "sched_getaffinity"}, - {__NR_sched_getattr, "sched_getattr"}, - {__NR_sched_getparam, "sched_getparam"}, - {__NR_sched_getscheduler, "sched_getscheduler"}, - {__NR_sched_rr_get_interval, "sched_rr_get_interval"}, - {__NR_sched_setaffinity, "sched_setaffinity"}, - {__NR_sched_setattr, "sched_setattr"}, - {__NR_sched_setparam, "sched_setparam"}, - {__NR_sched_setscheduler, "sched_setscheduler"}, - {__NR_sched_yield, "sched_yield"}, - {__NR_seccomp, "seccomp"}, - {__NR_security, "security"}, - {__NR_select, "select"}, - {__NR_semctl, "semctl"}, - {__NR_semget, "semget"}, - {__NR_semop, "semop"}, - {__NR_semtimedop, "semtimedop"}, - {__NR_sendfile, "sendfile"}, - {__NR_sendmmsg, "sendmmsg"}, - {__NR_sendmsg, "sendmsg"}, - {__NR_sendto, "sendto"}, - {__NR_set_mempolicy, "set_mempolicy"}, - {__NR_set_robust_list, "set_robust_list"}, - {__NR_set_thread_area, "set_thread_area"}, - {__NR_set_tid_address, "set_tid_address"}, - {__NR_setdomainname, "setdomainname"}, - {__NR_setfsgid, "setfsgid"}, - {__NR_setfsuid, "setfsuid"}, - {__NR_setgid, "setgid"}, - {__NR_setgroups, "setgroups"}, - {__NR_sethostname, "sethostname"}, - {__NR_setitimer, "setitimer"}, - {__NR_setns, "setns"}, - {__NR_setpgid, "setpgid"}, - {__NR_setpriority, "setpriority"}, - {__NR_setregid, "setregid"}, - {__NR_setresgid, "setresgid"}, - {__NR_setresuid, "setresuid"}, - {__NR_setreuid, "setreuid"}, - {__NR_setrlimit, "setrlimit"}, - {__NR_setsid, "setsid"}, - {__NR_setsockopt, "setsockopt"}, - {__NR_settimeofday, "settimeofday"}, - {__NR_setuid, "setuid"}, - {__NR_setxattr, "setxattr"}, - {__NR_shmat, "shmat"}, - {__NR_shmctl, "shmctl"}, - {__NR_shmdt, "shmdt"}, - {__NR_shmget, "shmget"}, - {__NR_shutdown, "shutdown"}, - {__NR_sigaltstack, "sigaltstack"}, - {__NR_signalfd, "signalfd"}, - {__NR_signalfd4, "signalfd4"}, - {__NR_socket, "socket"}, - {__NR_socketpair, "socketpair"}, - {__NR_splice, "splice"}, - {__NR_stat, "stat"}, - {__NR_statfs, "statfs"}, - {__NR_statx, "statx"}, - {__NR_swapoff, "swapoff"}, - {__NR_swapon, "swapon"}, - {__NR_symlink, "symlink"}, - {__NR_symlinkat, "symlinkat"}, - {__NR_sync, "sync"}, - {__NR_sync_file_range, "sync_file_range"}, - {__NR_syncfs, "syncfs"}, - {__NR_sysfs, "sysfs"}, - {__NR_sysinfo, "sysinfo"}, - {__NR_syslog, "syslog"}, - {__NR_tee, "tee"}, - {__NR_tgkill, "tgkill"}, - {__NR_time, "time"}, - {__NR_timer_create, "timer_create"}, - {__NR_timer_delete, "timer_delete"}, - {__NR_timer_getoverrun, "timer_getoverrun"}, - {__NR_timer_gettime, "timer_gettime"}, - {__NR_timer_settime, "timer_settime"}, - {__NR_timerfd_create, "timerfd_create"}, - {__NR_timerfd_gettime, "timerfd_gettime"}, - {__NR_timerfd_settime, "timerfd_settime"}, - {__NR_times, "times"}, - {__NR_tkill, "tkill"}, - {__NR_truncate, "truncate"}, - {__NR_tuxcall, "tuxcall"}, - {__NR_umask, "umask"}, - {__NR_umount2, "umount2"}, - {__NR_uname, "uname"}, - {__NR_unlink, "unlink"}, - {__NR_unlinkat, "unlinkat"}, - {__NR_unshare, "unshare"}, - {__NR_uselib, "uselib"}, - {__NR_userfaultfd, "userfaultfd"}, - {__NR_ustat, "ustat"}, - {__NR_utime, "utime"}, - {__NR_utimensat, "utimensat"}, - {__NR_utimes, "utimes"}, - {__NR_vfork, "vfork"}, - {__NR_vhangup, "vhangup"}, - {__NR_vmsplice, "vmsplice"}, - {__NR_vserver, "vserver"}, - {__NR_wait4, "wait4"}, - {__NR_waitid, "waitid"}, - {__NR_write, "write"}, - {__NR_writev, "writev"}, -}; - -std::string GetLinuxSyscallName(uint32_t syscall_number) -{ - const auto element = LINUX_SYSCALLS.find(syscall_number); - if (element != LINUX_SYSCALLS.end()) { - return element->second; - } - return "*unknown*"; -} - -// See Linux kernel developer Kees Cook's seccomp guide at <https://outflux.net/teach-seccomp/> for -// an accessible introduction to using seccomp. -// -// This function largely follows <https://outflux.net/teach-seccomp/step-3/syscall-reporter.c> and -// <https://outflux.net/teach-seccomp/step-3/seccomp-bpf.h>. -// -// Seccomp BPF resources: -// * Seccomp BPF documentation: <https://www.kernel.org/doc/html/latest/userspace-api/seccomp_filter.html> -// * seccomp(2) manual page: <https://www.kernel.org/doc/man-pages/online/pages/man2/seccomp.2.html> -// * Seccomp BPF demo code samples: <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/samples/seccomp> -void SyscallSandboxDebugSignalHandler(int, siginfo_t* signal_info, void* void_signal_context) -{ - // The si_code field inside the siginfo_t argument that is passed to a SA_SIGINFO signal handler - // is a value indicating why the signal was sent. - // - // The following value can be placed in si_code for a SIGSYS signal: - // * SYS_SECCOMP (since Linux 3.5): Triggered by a seccomp(2) filter rule. - constexpr int32_t SYS_SECCOMP_SI_CODE{1}; - assert(signal_info->si_code == SYS_SECCOMP_SI_CODE); - - // The ucontext_t structure contains signal context information that was saved on the user-space - // stack by the kernel. - const ucontext_t* signal_context = static_cast<ucontext_t*>(void_signal_context); - assert(signal_context != nullptr); - - std::set_new_handler(std::terminate); - // Portability note: REG_RAX is Linux x86_64 specific. - const uint32_t syscall_number = static_cast<uint32_t>(signal_context->uc_mcontext.gregs[REG_RAX]); - const std::string syscall_name = GetLinuxSyscallName(syscall_number); - const std::string thread_name = !util::ThreadGetInternalName().empty() ? util::ThreadGetInternalName() : "*unnamed*"; - const std::string error_message = strprintf("ERROR: The syscall \"%s\" (syscall number %d) is not allowed by the syscall sandbox in thread \"%s\". Please report.", syscall_name, syscall_number, thread_name); - tfm::format(std::cerr, "%s\n", error_message); - LogPrintf("%s\n", error_message); - std::terminate(); -} - -// This function largely follows install_syscall_reporter from Kees Cook's seccomp guide: -// <https://outflux.net/teach-seccomp/step-3/syscall-reporter.c> -bool SetupSyscallSandboxDebugHandler() -{ - struct sigaction action = {}; - sigset_t mask; - sigemptyset(&mask); - sigaddset(&mask, SIGSYS); - action.sa_sigaction = &SyscallSandboxDebugSignalHandler; - action.sa_flags = SA_SIGINFO; - if (sigaction(SIGSYS, &action, nullptr) < 0) { - return false; - } - if (sigprocmask(SIG_UNBLOCK, &mask, nullptr)) { - return false; - } - return true; -} - -enum class SyscallSandboxAction { - KILL_PROCESS, - INVOKE_SIGNAL_HANDLER, -}; - -class SeccompPolicyBuilder -{ - std::set<uint32_t> allowed_syscalls; - -public: - SeccompPolicyBuilder() - { - // Allowed by default. - AllowAddressSpaceAccess(); - AllowEpoll(); - AllowEventFd(); - AllowFutex(); - AllowGeneralIo(); - AllowGetRandom(); - AllowGetSimpleId(); - AllowGetTime(); - AllowGlobalProcessEnvironment(); - AllowGlobalSystemStatus(); - AllowKernelInternalApi(); - AllowNetworkSocketInformation(); - AllowOperationOnExistingFileDescriptor(); - AllowPipe(); - AllowPrctl(); - AllowProcessStartOrDeath(); - AllowScheduling(); - AllowSignalHandling(); - AllowSleep(); - AllowUmask(); - } - - void AllowAddressSpaceAccess() - { - allowed_syscalls.insert(__NR_brk); // change data segment size - allowed_syscalls.insert(__NR_madvise); // give advice about use of memory - allowed_syscalls.insert(__NR_membarrier); // issue memory barriers on a set of threads - allowed_syscalls.insert(__NR_mincore); // check if virtual memory is in RAM - allowed_syscalls.insert(__NR_mlock); // lock memory - allowed_syscalls.insert(__NR_mmap); // map files or devices into memory - allowed_syscalls.insert(__NR_mprotect); // set protection on a region of memory - allowed_syscalls.insert(__NR_mremap); // remap a file in memory - allowed_syscalls.insert(__NR_munlock); // unlock memory - allowed_syscalls.insert(__NR_munmap); // unmap files or devices into memory - } - - void AllowEpoll() - { - allowed_syscalls.insert(__NR_epoll_create1); // open an epoll file descriptor - allowed_syscalls.insert(__NR_epoll_ctl); // control interface for an epoll file descriptor - allowed_syscalls.insert(__NR_epoll_pwait); // wait for an I/O event on an epoll file descriptor - allowed_syscalls.insert(__NR_epoll_wait); // wait for an I/O event on an epoll file descriptor - } - - void AllowEventFd() - { - allowed_syscalls.insert(__NR_eventfd2); // create a file descriptor for event notification - } - - void AllowFileSystem() - { - allowed_syscalls.insert(__NR_access); // check user's permissions for a file - allowed_syscalls.insert(__NR_chdir); // change working directory - allowed_syscalls.insert(__NR_chmod); // change permissions of a file - allowed_syscalls.insert(__NR_copy_file_range); // copy a range of data from one file to another - allowed_syscalls.insert(__NR_fallocate); // manipulate file space - allowed_syscalls.insert(__NR_fchmod); // change permissions of a file - allowed_syscalls.insert(__NR_fchown); // change ownership of a file - allowed_syscalls.insert(__NR_fdatasync); // synchronize a file's in-core state with storage device - allowed_syscalls.insert(__NR_flock); // apply or remove an advisory lock on an open file - allowed_syscalls.insert(__NR_fstat); // get file status - allowed_syscalls.insert(__NR_fstatfs); // get file system status - allowed_syscalls.insert(__NR_fsync); // synchronize a file's in-core state with storage device - allowed_syscalls.insert(__NR_ftruncate); // truncate a file to a specified length - allowed_syscalls.insert(__NR_getcwd); // get current working directory - allowed_syscalls.insert(__NR_getdents); // get directory entries - allowed_syscalls.insert(__NR_getdents64); // get directory entries - allowed_syscalls.insert(__NR_lstat); // get file status - allowed_syscalls.insert(__NR_mkdir); // create a directory - allowed_syscalls.insert(__NR_newfstatat); // get file status - allowed_syscalls.insert(__NR_open); // open and possibly create a file - allowed_syscalls.insert(__NR_openat); // open and possibly create a file - allowed_syscalls.insert(__NR_readlink); // read value of a symbolic link - allowed_syscalls.insert(__NR_rename); // change the name or location of a file - allowed_syscalls.insert(__NR_rmdir); // delete a directory - allowed_syscalls.insert(__NR_sendfile); // transfer data between file descriptors - allowed_syscalls.insert(__NR_stat); // get file status - allowed_syscalls.insert(__NR_statfs); // get filesystem statistics - allowed_syscalls.insert(__NR_statx); // get file status (extended) - allowed_syscalls.insert(__NR_unlink); // delete a name and possibly the file it refers to - allowed_syscalls.insert(__NR_unlinkat); // delete relative to a directory file descriptor - } - - void AllowFutex() - { - allowed_syscalls.insert(__NR_futex); // fast user-space locking - allowed_syscalls.insert(__NR_set_robust_list); // set list of robust futexes - } - - void AllowGeneralIo() - { - allowed_syscalls.insert(__NR_ioctl); // control device - allowed_syscalls.insert(__NR_lseek); // reposition read/write file offset - allowed_syscalls.insert(__NR_poll); // wait for some event on a file descriptor - allowed_syscalls.insert(__NR_ppoll); // wait for some event on a file descriptor - allowed_syscalls.insert(__NR_pread64); // read from a file descriptor at a given offset - allowed_syscalls.insert(__NR_pwrite64); // write to a file descriptor at a given offset - allowed_syscalls.insert(__NR_read); // read from a file descriptor - allowed_syscalls.insert(__NR_readv); // read data into multiple buffers - allowed_syscalls.insert(__NR_recvfrom); // receive a message from a socket - allowed_syscalls.insert(__NR_recvmsg); // receive a message from a socket - allowed_syscalls.insert(__NR_select); // synchronous I/O multiplexing - allowed_syscalls.insert(__NR_sendmmsg); // send multiple messages on a socket - allowed_syscalls.insert(__NR_sendmsg); // send a message on a socket - allowed_syscalls.insert(__NR_sendto); // send a message on a socket - allowed_syscalls.insert(__NR_write); // write to a file descriptor - allowed_syscalls.insert(__NR_writev); // write data into multiple buffers - } - - void AllowGetRandom() - { - allowed_syscalls.insert(__NR_getrandom); // obtain a series of random bytes - } - - void AllowGetSimpleId() - { - allowed_syscalls.insert(__NR_getegid); // get group identity - allowed_syscalls.insert(__NR_geteuid); // get user identity - allowed_syscalls.insert(__NR_getgid); // get group identity - allowed_syscalls.insert(__NR_getpgid); // get process group - allowed_syscalls.insert(__NR_getpid); // get process identification - allowed_syscalls.insert(__NR_getppid); // get process identification - allowed_syscalls.insert(__NR_getresgid); // get real, effective and saved group IDs - allowed_syscalls.insert(__NR_getresuid); // get real, effective and saved user IDs - allowed_syscalls.insert(__NR_getsid); // get session ID - allowed_syscalls.insert(__NR_gettid); // get thread identification - allowed_syscalls.insert(__NR_getuid); // get user identity - } - - void AllowGetTime() - { - allowed_syscalls.insert(__NR_clock_getres); // find the resolution (precision) of the specified clock - allowed_syscalls.insert(__NR_clock_gettime); // retrieve the time of the specified clock - allowed_syscalls.insert(__NR_gettimeofday); // get timeval - } - - void AllowGlobalProcessEnvironment() - { - allowed_syscalls.insert(__NR_getrlimit); // get resource limits - allowed_syscalls.insert(__NR_getrusage); // get resource usage - allowed_syscalls.insert(__NR_prlimit64); // get/set resource limits - } - - void AllowGlobalSystemStatus() - { - allowed_syscalls.insert(__NR_sysinfo); // return system information - allowed_syscalls.insert(__NR_uname); // get name and information about current kernel - } - - void AllowKernelInternalApi() - { - allowed_syscalls.insert(__NR_restart_syscall); // restart a system call after interruption by a stop signal - } - - void AllowNetwork() - { - allowed_syscalls.insert(__NR_accept); // accept a connection on a socket - allowed_syscalls.insert(__NR_accept4); // accept a connection on a socket - allowed_syscalls.insert(__NR_bind); // bind a name to a socket - allowed_syscalls.insert(__NR_connect); // initiate a connection on a socket - allowed_syscalls.insert(__NR_listen); // listen for connections on a socket - allowed_syscalls.insert(__NR_setsockopt); // set options on sockets - allowed_syscalls.insert(__NR_socket); // create an endpoint for communication - allowed_syscalls.insert(__NR_socketpair); // create a pair of connected sockets - } - - void AllowNetworkSocketInformation() - { - allowed_syscalls.insert(__NR_getpeername); // get name of connected peer socket - allowed_syscalls.insert(__NR_getsockname); // get socket name - allowed_syscalls.insert(__NR_getsockopt); // get options on sockets - } - - void AllowOperationOnExistingFileDescriptor() - { - allowed_syscalls.insert(__NR_close); // close a file descriptor - allowed_syscalls.insert(__NR_dup); // duplicate a file descriptor - allowed_syscalls.insert(__NR_dup2); // duplicate a file descriptor - allowed_syscalls.insert(__NR_fcntl); // manipulate file descriptor - allowed_syscalls.insert(__NR_shutdown); // shut down part of a full-duplex connection - } - - void AllowPipe() - { - allowed_syscalls.insert(__NR_pipe); // create pipe - allowed_syscalls.insert(__NR_pipe2); // create pipe - } - - void AllowPrctl() - { - allowed_syscalls.insert(__NR_arch_prctl); // set architecture-specific thread state - allowed_syscalls.insert(__NR_prctl); // operations on a process - } - - void AllowProcessStartOrDeath() - { - allowed_syscalls.insert(__NR_clone); // create a child process - allowed_syscalls.insert(__NR_clone3); // create a child process - allowed_syscalls.insert(__NR_exit); // terminate the calling process - allowed_syscalls.insert(__NR_exit_group); // exit all threads in a process - allowed_syscalls.insert(__NR_fork); // create a child process - allowed_syscalls.insert(__NR_tgkill); // send a signal to a thread - allowed_syscalls.insert(__NR_wait4); // wait for process to change state, BSD style - allowed_syscalls.insert(__NR_rseq); // register restartable sequence for thread - } - - void AllowScheduling() - { - allowed_syscalls.insert(__NR_sched_getaffinity); // set a thread's CPU affinity mask - allowed_syscalls.insert(__NR_sched_getparam); // get scheduling parameters - allowed_syscalls.insert(__NR_sched_getscheduler); // get scheduling policy/parameters - allowed_syscalls.insert(__NR_sched_setscheduler); // set scheduling policy/parameters - allowed_syscalls.insert(__NR_sched_yield); // yield the processor - } - - void AllowSignalHandling() - { - allowed_syscalls.insert(__NR_rt_sigaction); // examine and change a signal action - allowed_syscalls.insert(__NR_rt_sigprocmask); // examine and change blocked signals - allowed_syscalls.insert(__NR_rt_sigreturn); // return from signal handler and cleanup stack frame - allowed_syscalls.insert(__NR_sigaltstack); // set and/or get signal stack context - } - - void AllowSleep() - { - allowed_syscalls.insert(__NR_clock_nanosleep); // high-resolution sleep with specifiable clock - allowed_syscalls.insert(__NR_nanosleep); // high-resolution sleep - } - - void AllowUmask() - { - allowed_syscalls.insert(__NR_umask); // set file mode creation mask - } - - // See Linux kernel developer Kees Cook's seccomp guide at <https://outflux.net/teach-seccomp/> - // for an accessible introduction to using seccomp. - // - // This function largely follows <https://outflux.net/teach-seccomp/step-3/seccomp-bpf.h>. - std::vector<sock_filter> BuildFilter(SyscallSandboxAction default_action) - { - std::vector<sock_filter> bpf_policy; - // See VALIDATE_ARCHITECTURE in seccomp-bpf.h referenced above. - bpf_policy.push_back(BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct seccomp_data, arch))); - // Portability note: AUDIT_ARCH_X86_64 is Linux x86_64 specific. - bpf_policy.push_back(BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, AUDIT_ARCH_X86_64, 1, 0)); - bpf_policy.push_back(BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_KILL_PROCESS)); - // See EXAMINE_SYSCALL in seccomp-bpf.h referenced above. - bpf_policy.push_back(BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct seccomp_data, nr))); - for (const uint32_t allowed_syscall : allowed_syscalls) { - // See ALLOW_SYSCALL in seccomp-bpf.h referenced above. - bpf_policy.push_back(BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, allowed_syscall, 0, 1)); - bpf_policy.push_back(BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW)); - } - switch (default_action) { - case SyscallSandboxAction::KILL_PROCESS: - // Disallow syscall and kill the process. - // - // See KILL_PROCESS in seccomp-bpf.h referenced above. - // - // Note that we're using SECCOMP_RET_KILL_PROCESS (kill the process) instead - // of SECCOMP_RET_KILL_THREAD (kill the thread). The SECCOMP_RET_KILL_PROCESS - // action was introduced in Linux 4.14. - // - // SECCOMP_RET_KILL_PROCESS: Results in the entire process exiting immediately without - // executing the system call. - // - // SECCOMP_RET_KILL_PROCESS documentation: - // <https://www.kernel.org/doc/html/latest/userspace-api/seccomp_filter.html> - bpf_policy.push_back(BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_KILL_PROCESS)); - break; - case SyscallSandboxAction::INVOKE_SIGNAL_HANDLER: - // Disallow syscall and force a SIGSYS to trigger syscall debug reporter. - // - // SECCOMP_RET_TRAP: Results in the kernel sending a SIGSYS signal to the triggering - // task without executing the system call. - // - // SECCOMP_RET_TRAP documentation: - // <https://www.kernel.org/doc/html/latest/userspace-api/seccomp_filter.html> - bpf_policy.push_back(BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRAP)); - break; - } - return bpf_policy; - } -}; -} // namespace - -bool SetupSyscallSandbox(bool log_syscall_violation_before_terminating) -{ - assert(!g_syscall_sandbox_enabled && "SetupSyscallSandbox(...) should only be called once."); - g_syscall_sandbox_enabled = true; - g_syscall_sandbox_log_violation_before_terminating = log_syscall_violation_before_terminating; - if (log_syscall_violation_before_terminating) { - if (!SetupSyscallSandboxDebugHandler()) { - return false; - } - } - return true; -} - -void TestDisallowedSandboxCall() -{ - // The getgroups syscall is assumed NOT to be allowed by the syscall sandbox policy. - std::array<gid_t, 1> groups; - [[maybe_unused]] int32_t ignored = getgroups(groups.size(), groups.data()); -} -#endif // defined(USE_SYSCALL_SANDBOX) - -void SetSyscallSandboxPolicy(SyscallSandboxPolicy syscall_policy) -{ -#if defined(USE_SYSCALL_SANDBOX) - if (!g_syscall_sandbox_enabled) { - return; - } - SeccompPolicyBuilder seccomp_policy_builder; - switch (syscall_policy) { - case SyscallSandboxPolicy::INITIALIZATION: // Thread: main thread (state: init) - // SyscallSandboxPolicy::INITIALIZATION is the first policy loaded. - // - // Subsequently loaded policies can reduce the abilities further, but - // abilities can never be regained. - // - // SyscallSandboxPolicy::INITIALIZATION must thus be a superset of all - // other policies. - seccomp_policy_builder.AllowFileSystem(); - seccomp_policy_builder.AllowNetwork(); - break; - case SyscallSandboxPolicy::INITIALIZATION_DNS_SEED: // Thread: dnsseed - seccomp_policy_builder.AllowFileSystem(); - seccomp_policy_builder.AllowNetwork(); - break; - case SyscallSandboxPolicy::INITIALIZATION_LOAD_BLOCKS: // Thread: loadblk - seccomp_policy_builder.AllowFileSystem(); - break; - case SyscallSandboxPolicy::INITIALIZATION_MAP_PORT: // Thread: mapport - seccomp_policy_builder.AllowFileSystem(); - seccomp_policy_builder.AllowNetwork(); - break; - case SyscallSandboxPolicy::MESSAGE_HANDLER: // Thread: msghand - seccomp_policy_builder.AllowFileSystem(); - break; - case SyscallSandboxPolicy::NET: // Thread: net - seccomp_policy_builder.AllowFileSystem(); - seccomp_policy_builder.AllowNetwork(); - break; - case SyscallSandboxPolicy::NET_ADD_CONNECTION: // Thread: addcon - seccomp_policy_builder.AllowFileSystem(); - seccomp_policy_builder.AllowNetwork(); - break; - case SyscallSandboxPolicy::NET_HTTP_SERVER: // Thread: http - seccomp_policy_builder.AllowFileSystem(); - seccomp_policy_builder.AllowNetwork(); - break; - case SyscallSandboxPolicy::NET_HTTP_SERVER_WORKER: // Thread: httpworker.<N> - seccomp_policy_builder.AllowFileSystem(); - seccomp_policy_builder.AllowNetwork(); - break; - case SyscallSandboxPolicy::NET_OPEN_CONNECTION: // Thread: opencon - seccomp_policy_builder.AllowFileSystem(); - seccomp_policy_builder.AllowNetwork(); - break; - case SyscallSandboxPolicy::SCHEDULER: // Thread: scheduler - seccomp_policy_builder.AllowFileSystem(); - break; - case SyscallSandboxPolicy::TOR_CONTROL: // Thread: torcontrol - seccomp_policy_builder.AllowFileSystem(); - seccomp_policy_builder.AllowNetwork(); - break; - case SyscallSandboxPolicy::TX_INDEX: // Thread: txindex - seccomp_policy_builder.AllowFileSystem(); - break; - case SyscallSandboxPolicy::VALIDATION_SCRIPT_CHECK: // Thread: scriptch.<N> - break; - case SyscallSandboxPolicy::SHUTOFF: // Thread: main thread (state: shutoff) - seccomp_policy_builder.AllowFileSystem(); - break; - } - - const SyscallSandboxAction default_action = g_syscall_sandbox_log_violation_before_terminating ? SyscallSandboxAction::INVOKE_SIGNAL_HANDLER : SyscallSandboxAction::KILL_PROCESS; - std::vector<sock_filter> filter = seccomp_policy_builder.BuildFilter(default_action); - const sock_fprog prog = { - .len = static_cast<uint16_t>(filter.size()), - .filter = filter.data(), - }; - // Do not allow abilities to be regained after being dropped. - // - // PR_SET_NO_NEW_PRIVS documentation: <https://www.kernel.org/doc/html/latest/userspace-api/no_new_privs.html> - if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) { - throw std::runtime_error("Syscall sandbox enforcement failed: prctl(PR_SET_NO_NEW_PRIVS)"); - } - // Install seccomp-bpf syscall filter. - // - // PR_SET_SECCOMP documentation: <https://www.kernel.org/doc/html/latest/userspace-api/seccomp_filter.html> - if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) != 0) { - throw std::runtime_error("Syscall sandbox enforcement failed: prctl(PR_SET_SECCOMP)"); - } - - const std::string thread_name = !util::ThreadGetInternalName().empty() ? util::ThreadGetInternalName() : "*unnamed*"; - LogPrint(BCLog::UTIL, "Syscall filter installed for thread \"%s\"\n", thread_name); -#endif // defined(USE_SYSCALL_SANDBOX) -} diff --git a/src/util/syscall_sandbox.h b/src/util/syscall_sandbox.h deleted file mode 100644 index 3e56ebe937..0000000000 --- a/src/util/syscall_sandbox.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2020-2022 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_UTIL_SYSCALL_SANDBOX_H -#define BITCOIN_UTIL_SYSCALL_SANDBOX_H - -enum class SyscallSandboxPolicy { - // 1. Initialization - INITIALIZATION, - INITIALIZATION_DNS_SEED, - INITIALIZATION_LOAD_BLOCKS, - INITIALIZATION_MAP_PORT, - - // 2. Steady state (non-initialization, non-shutdown) - MESSAGE_HANDLER, - NET, - NET_ADD_CONNECTION, - NET_HTTP_SERVER, - NET_HTTP_SERVER_WORKER, - NET_OPEN_CONNECTION, - SCHEDULER, - TOR_CONTROL, - TX_INDEX, - VALIDATION_SCRIPT_CHECK, - - // 3. Shutdown - SHUTOFF, -}; - -//! Force the current thread (and threads created from the current thread) into a restricted-service -//! operating mode where only a subset of all syscalls are available. -//! -//! Subsequent calls to this function can reduce the abilities further, but abilities can never be -//! regained. -//! -//! This function is a no-op unless SetupSyscallSandbox(...) has been called. -//! -//! SetupSyscallSandbox(...) is called during bitcoind initialization if Bitcoin Core was compiled -//! with seccomp-bpf support (--with-seccomp) *and* the parameter -sandbox=<mode> was passed to -//! bitcoind. -//! -//! This experimental feature is available under Linux x86_64 only. -void SetSyscallSandboxPolicy(SyscallSandboxPolicy syscall_policy); - -#if defined(USE_SYSCALL_SANDBOX) -//! Setup and enable the experimental syscall sandbox for the running process. -[[nodiscard]] bool SetupSyscallSandbox(bool log_syscall_violation_before_terminating); - -//! Invoke a disallowed syscall. Use for testing purposes. -void TestDisallowedSandboxCall(); -#endif // defined(USE_SYSCALL_SANDBOX) - -#endif // BITCOIN_UTIL_SYSCALL_SANDBOX_H diff --git a/src/util/system.cpp b/src/util/system.cpp deleted file mode 100644 index 598e6adb88..0000000000 --- a/src/util/system.cpp +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2022 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include <util/system.h> - -#include <logging.h> -#include <util/string.h> -#include <util/syserror.h> -#include <util/time.h> - -#if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)) -#include <pthread.h> -#include <pthread_np.h> -#endif - -#ifndef WIN32 -#include <sched.h> -#include <sys/stat.h> -#else -#include <codecvt> -#endif - -#ifdef HAVE_MALLOPT_ARENA_MAX -#include <malloc.h> -#endif - -#include <cstdlib> -#include <locale> -#include <stdexcept> -#include <string> -#include <thread> - -// Application startup time (used for uptime calculation) -const int64_t nStartupTime = GetTime(); - -#ifndef WIN32 -std::string ShellEscape(const std::string& arg) -{ - std::string escaped = arg; - ReplaceAll(escaped, "'", "'\"'\"'"); - return "'" + escaped + "'"; -} -#endif - -#if HAVE_SYSTEM -void runCommand(const std::string& strCommand) -{ - if (strCommand.empty()) return; -#ifndef WIN32 - int nErr = ::system(strCommand.c_str()); -#else - int nErr = ::_wsystem(std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().from_bytes(strCommand).c_str()); -#endif - if (nErr) - LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr); -} -#endif - -void SetupEnvironment() -{ -#ifdef HAVE_MALLOPT_ARENA_MAX - // glibc-specific: On 32-bit systems set the number of arenas to 1. - // By default, since glibc 2.10, the C library will create up to two heap - // arenas per core. This is known to cause excessive virtual address space - // usage in our usage. Work around it by setting the maximum number of - // arenas to 1. - if (sizeof(void*) == 4) { - mallopt(M_ARENA_MAX, 1); - } -#endif - // On most POSIX systems (e.g. Linux, but not BSD) the environment's locale - // may be invalid, in which case the "C.UTF-8" locale is used as fallback. -#if !defined(WIN32) && !defined(MAC_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) - try { - std::locale(""); // Raises a runtime error if current locale is invalid - } catch (const std::runtime_error&) { - setenv("LC_ALL", "C.UTF-8", 1); - } -#elif defined(WIN32) - // Set the default input/output charset is utf-8 - SetConsoleCP(CP_UTF8); - SetConsoleOutputCP(CP_UTF8); -#endif - -#ifndef WIN32 - constexpr mode_t private_umask = 0077; - umask(private_umask); -#endif -} - -bool SetupNetworking() -{ -#ifdef WIN32 - // Initialize Windows Sockets - WSADATA wsadata; - int ret = WSAStartup(MAKEWORD(2,2), &wsadata); - if (ret != NO_ERROR || LOBYTE(wsadata.wVersion ) != 2 || HIBYTE(wsadata.wVersion) != 2) - return false; -#endif - return true; -} - -int GetNumCores() -{ - return std::thread::hardware_concurrency(); -} - -// Obtain the application startup time (used for uptime calculation) -int64_t GetStartupTime() -{ - return nStartupTime; -} - -void ScheduleBatchPriority() -{ -#ifdef SCHED_BATCH - const static sched_param param{}; - const int rc = pthread_setschedparam(pthread_self(), SCHED_BATCH, ¶m); - if (rc != 0) { - LogPrintf("Failed to pthread_setschedparam: %s\n", SysErrorString(rc)); - } -#endif -} diff --git a/src/util/system.h b/src/util/system.h deleted file mode 100644 index e2fc3450f6..0000000000 --- a/src/util/system.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2022 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_UTIL_SYSTEM_H -#define BITCOIN_UTIL_SYSTEM_H - -#if defined(HAVE_CONFIG_H) -#include <config/bitcoin-config.h> -#endif - -#include <compat/assumptions.h> -#include <compat/compat.h> - -#include <any> -#include <set> -#include <stdint.h> -#include <string> - -// Application startup time (used for uptime calculation) -int64_t GetStartupTime(); - -void SetupEnvironment(); -bool SetupNetworking(); -#ifndef WIN32 -std::string ShellEscape(const std::string& arg); -#endif -#if HAVE_SYSTEM -void runCommand(const std::string& strCommand); -#endif - -/** - * Return the number of cores available on the current system. - * @note This does count virtual cores, such as those provided by HyperThreading. - */ -int GetNumCores(); - -/** - * On platforms that support it, tell the kernel the calling thread is - * CPU-intensive and non-interactive. See SCHED_BATCH in sched(7) for details. - * - */ -void ScheduleBatchPriority(); - -namespace util { - -//! Simplification of std insertion -template <typename Tdst, typename Tsrc> -inline void insert(Tdst& dst, const Tsrc& src) { - dst.insert(dst.begin(), src.begin(), src.end()); -} -template <typename TsetT, typename Tsrc> -inline void insert(std::set<TsetT>& dst, const Tsrc& src) { - dst.insert(src.begin(), src.end()); -} - -/** - * Helper function to access the contained object of a std::any instance. - * Returns a pointer to the object if passed instance has a value and the type - * matches, nullptr otherwise. - */ -template<typename T> -T* AnyPtr(const std::any& any) noexcept -{ - T* const* ptr = std::any_cast<T*>(&any); - return ptr ? *ptr : nullptr; -} - -} // namespace util - -#endif // BITCOIN_UTIL_SYSTEM_H diff --git a/src/util/threadinterrupt.h b/src/util/threadinterrupt.h index ccc053f576..0b79b38276 100644 --- a/src/util/threadinterrupt.h +++ b/src/util/threadinterrupt.h @@ -12,11 +12,17 @@ #include <chrono> #include <condition_variable> -/* - A helper class for interruptible sleeps. Calling operator() will interrupt - any current sleep, and after that point operator bool() will return true - until reset. -*/ +/** + * A helper class for interruptible sleeps. Calling operator() will interrupt + * any current sleep, and after that point operator bool() will return true + * until reset. + * + * This class should not be used in a signal handler. It uses thread + * synchronization primitives that are not safe to use with signals. If sending + * an interrupt from a signal handler is necessary, the \ref SignalInterrupt + * class can be used instead. + */ + class CThreadInterrupt { public: diff --git a/src/util/time.cpp b/src/util/time.cpp index fb9bc34931..5ca9d21f8d 100644 --- a/src/util/time.cpp +++ b/src/util/time.cpp @@ -78,14 +78,6 @@ NodeClock::time_point NodeClock::now() noexcept return time_point{ret}; }; -template <typename T> -static T GetSystemTime() -{ - const auto now = std::chrono::duration_cast<T>(std::chrono::system_clock::now().time_since_epoch()); - assert(now.count() > 0); - return now; -} - void SetMockTime(int64_t nMockTimeIn) { Assert(nMockTimeIn >= 0); @@ -102,11 +94,6 @@ std::chrono::seconds GetMockTime() return std::chrono::seconds(nMockTime.load(std::memory_order_relaxed)); } -int64_t GetTimeMillis() -{ - return int64_t{GetSystemTime<std::chrono::milliseconds>().count()}; -} - int64_t GetTime() { return GetTime<std::chrono::seconds>().count(); } std::string FormatISO8601DateTime(int64_t nTime) { diff --git a/src/util/time.h b/src/util/time.h index 8c6baeb12a..b6aab615ba 100644 --- a/src/util/time.h +++ b/src/util/time.h @@ -71,9 +71,6 @@ using MillisecondsDouble = std::chrono::duration<double, std::chrono::millisecon */ int64_t GetTime(); -/** Returns the system time (not mockable) */ -int64_t GetTimeMillis(); - /** * DEPRECATED * Use SetMockTime with chrono type diff --git a/src/util/translation.h b/src/util/translation.h index d2b49d00b0..d33fd2d0a0 100644 --- a/src/util/translation.h +++ b/src/util/translation.h @@ -49,22 +49,18 @@ inline bilingual_str Untranslated(std::string original) { return {original, orig // Provide an overload of tinyformat::format which can take bilingual_str arguments. namespace tinyformat { -inline std::string TranslateArg(const bilingual_str& arg, bool translated) -{ - return translated ? arg.translated : arg.original; -} - -template <typename T> -inline T const& TranslateArg(const T& arg, bool translated) -{ - return arg; -} - template <typename... Args> bilingual_str format(const bilingual_str& fmt, const Args&... args) { - return bilingual_str{format(fmt.original, TranslateArg(args, false)...), - format(fmt.translated, TranslateArg(args, true)...)}; + const auto translate_arg{[](const auto& arg, bool translated) -> const auto& { + if constexpr (std::is_same_v<decltype(arg), const bilingual_str&>) { + return translated ? arg.translated : arg.original; + } else { + return arg; + } + }}; + return bilingual_str{tfm::format(fmt.original, translate_arg(args, false)...), + tfm::format(fmt.translated, translate_arg(args, true)...)}; } } // namespace tinyformat |