aboutsummaryrefslogtreecommitdiff
path: root/contrib/devtools
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/devtools')
-rw-r--r--contrib/devtools/bitcoin-tidy/CMakeLists.txt4
-rw-r--r--contrib/devtools/bitcoin-tidy/bitcoin-tidy.cpp2
-rw-r--r--contrib/devtools/bitcoin-tidy/example_nontrivial-threadlocal.cpp2
-rw-r--r--contrib/devtools/bitcoin-tidy/nontrivial-threadlocal.cpp44
-rw-r--r--contrib/devtools/bitcoin-tidy/nontrivial-threadlocal.h29
-rwxr-xr-xcontrib/devtools/copyright_header.py1
-rwxr-xr-x[-rw-r--r--]contrib/devtools/headerssync-params.py4
-rwxr-xr-xcontrib/devtools/security-check.py69
-rwxr-xr-xcontrib/devtools/symbol-check.py28
-rwxr-xr-xcontrib/devtools/test-security-check.py127
-rwxr-xr-xcontrib/devtools/test-symbol-check.py50
-rwxr-xr-xcontrib/devtools/test_utxo_snapshots.sh2
12 files changed, 196 insertions, 166 deletions
diff --git a/contrib/devtools/bitcoin-tidy/CMakeLists.txt b/contrib/devtools/bitcoin-tidy/CMakeLists.txt
index 1260c71423..95345b4782 100644
--- a/contrib/devtools/bitcoin-tidy/CMakeLists.txt
+++ b/contrib/devtools/bitcoin-tidy/CMakeLists.txt
@@ -25,7 +25,7 @@ find_program(CLANG_TIDY_EXE NAMES "clang-tidy-${LLVM_VERSION_MAJOR}" "clang-tidy
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Found clang-tidy: ${CLANG_TIDY_EXE}")
-add_library(bitcoin-tidy MODULE bitcoin-tidy.cpp logprintf.cpp)
+add_library(bitcoin-tidy MODULE bitcoin-tidy.cpp logprintf.cpp nontrivial-threadlocal.cpp)
target_include_directories(bitcoin-tidy SYSTEM PRIVATE ${LLVM_INCLUDE_DIRS})
# Disable RTTI and exceptions as necessary
@@ -58,7 +58,7 @@ else()
endif()
# Create a dummy library that runs clang-tidy tests as a side-effect of building
-add_library(bitcoin-tidy-tests OBJECT EXCLUDE_FROM_ALL example_logprintf.cpp)
+add_library(bitcoin-tidy-tests OBJECT EXCLUDE_FROM_ALL example_logprintf.cpp example_nontrivial-threadlocal.cpp)
add_dependencies(bitcoin-tidy-tests bitcoin-tidy)
set_target_properties(bitcoin-tidy-tests PROPERTIES CXX_CLANG_TIDY "${CLANG_TIDY_COMMAND}")
diff --git a/contrib/devtools/bitcoin-tidy/bitcoin-tidy.cpp b/contrib/devtools/bitcoin-tidy/bitcoin-tidy.cpp
index 0f34d37793..1ef4494973 100644
--- a/contrib/devtools/bitcoin-tidy/bitcoin-tidy.cpp
+++ b/contrib/devtools/bitcoin-tidy/bitcoin-tidy.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "logprintf.h"
+#include "nontrivial-threadlocal.h"
#include <clang-tidy/ClangTidyModule.h>
#include <clang-tidy/ClangTidyModuleRegistry.h>
@@ -13,6 +14,7 @@ public:
void addCheckFactories(clang::tidy::ClangTidyCheckFactories& CheckFactories) override
{
CheckFactories.registerCheck<bitcoin::LogPrintfCheck>("bitcoin-unterminated-logprintf");
+ CheckFactories.registerCheck<bitcoin::NonTrivialThreadLocal>("bitcoin-nontrivial-threadlocal");
}
};
diff --git a/contrib/devtools/bitcoin-tidy/example_nontrivial-threadlocal.cpp b/contrib/devtools/bitcoin-tidy/example_nontrivial-threadlocal.cpp
new file mode 100644
index 0000000000..2b74df5d0e
--- /dev/null
+++ b/contrib/devtools/bitcoin-tidy/example_nontrivial-threadlocal.cpp
@@ -0,0 +1,2 @@
+#include <string>
+thread_local std::string foo;
diff --git a/contrib/devtools/bitcoin-tidy/nontrivial-threadlocal.cpp b/contrib/devtools/bitcoin-tidy/nontrivial-threadlocal.cpp
new file mode 100644
index 0000000000..d2bc78a31b
--- /dev/null
+++ b/contrib/devtools/bitcoin-tidy/nontrivial-threadlocal.cpp
@@ -0,0 +1,44 @@
+// Copyright (c) 2023 Bitcoin Developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "nontrivial-threadlocal.h"
+
+#include <clang/AST/ASTContext.h>
+#include <clang/ASTMatchers/ASTMatchFinder.h>
+
+
+// Copied from clang-tidy's UnusedRaiiCheck
+namespace {
+AST_MATCHER(clang::CXXRecordDecl, hasNonTrivialDestructor) {
+ // TODO: If the dtor is there but empty we don't want to warn either.
+ return Node.hasDefinition() && Node.hasNonTrivialDestructor();
+}
+} // namespace
+
+namespace bitcoin {
+
+void NonTrivialThreadLocal::registerMatchers(clang::ast_matchers::MatchFinder* finder)
+{
+ using namespace clang::ast_matchers;
+
+ /*
+ thread_local std::string foo;
+ */
+
+ finder->addMatcher(
+ varDecl(
+ hasThreadStorageDuration(),
+ hasType(hasCanonicalType(recordType(hasDeclaration(cxxRecordDecl(hasNonTrivialDestructor())))))
+ ).bind("nontrivial_threadlocal"),
+ this);
+}
+
+void NonTrivialThreadLocal::check(const clang::ast_matchers::MatchFinder::MatchResult& Result)
+{
+ if (const clang::VarDecl* var = Result.Nodes.getNodeAs<clang::VarDecl>("nontrivial_threadlocal")) {
+ const auto user_diag = diag(var->getBeginLoc(), "Variable with non-trivial destructor cannot be thread_local.");
+ }
+}
+
+} // namespace bitcoin
diff --git a/contrib/devtools/bitcoin-tidy/nontrivial-threadlocal.h b/contrib/devtools/bitcoin-tidy/nontrivial-threadlocal.h
new file mode 100644
index 0000000000..c853073467
--- /dev/null
+++ b/contrib/devtools/bitcoin-tidy/nontrivial-threadlocal.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2023 Bitcoin Developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef NONTRIVIAL_THREADLOCAL_CHECK_H
+#define NONTRIVIAL_THREADLOCAL_CHECK_H
+
+#include <clang-tidy/ClangTidyCheck.h>
+
+namespace bitcoin {
+
+// Warn about any thread_local variable with a non-trivial destructor.
+class NonTrivialThreadLocal final : public clang::tidy::ClangTidyCheck
+{
+public:
+ NonTrivialThreadLocal(clang::StringRef Name, clang::tidy::ClangTidyContext* Context)
+ : clang::tidy::ClangTidyCheck(Name, Context) {}
+
+ bool isLanguageVersionSupported(const clang::LangOptions& LangOpts) const override
+ {
+ return LangOpts.CPlusPlus;
+ }
+ void registerMatchers(clang::ast_matchers::MatchFinder* Finder) override;
+ void check(const clang::ast_matchers::MatchFinder::MatchResult& Result) override;
+};
+
+} // namespace bitcoin
+
+#endif // NONTRIVIAL_THREADLOCAL_CHECK_H
diff --git a/contrib/devtools/copyright_header.py b/contrib/devtools/copyright_header.py
index 3dddffe324..3c98ee7b20 100755
--- a/contrib/devtools/copyright_header.py
+++ b/contrib/devtools/copyright_header.py
@@ -19,7 +19,6 @@ EXCLUDE = [
'src/qt/bitcoinstrings.cpp',
'src/chainparamsseeds.h',
# other external copyrights:
- 'src/reverse_iterator.h',
'src/test/fuzz/FuzzedDataProvider.h',
'src/tinyformat.h',
'src/bench/nanobench.h',
diff --git a/contrib/devtools/headerssync-params.py b/contrib/devtools/headerssync-params.py
index 0198f5db99..f8e415532a 100644..100755
--- a/contrib/devtools/headerssync-params.py
+++ b/contrib/devtools/headerssync-params.py
@@ -12,13 +12,13 @@ import random
# Parameters:
# Aim for still working fine at some point in the future. [datetime]
-TIME = datetime(2026, 10, 5)
+TIME = datetime(2027, 4, 1)
# Expected block interval. [timedelta]
BLOCK_INTERVAL = timedelta(seconds=600)
# The number of headers corresponding to the minchainwork parameter. [headers]
-MINCHAINWORK_HEADERS = 804000
+MINCHAINWORK_HEADERS = 856760
# Combined processing bandwidth from all attackers to one victim. [bit/s]
# 6 Gbit/s is approximately the speed at which a single thread of a Ryzen 5950X CPU thread can hash
diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py
index f57e9abfec..46f9ee915f 100755
--- a/contrib/devtools/security-check.py
+++ b/contrib/devtools/security-check.py
@@ -38,13 +38,13 @@ def check_ELF_RELRO(binary) -> bool:
return have_gnu_relro and have_bindnow
-def check_ELF_Canary(binary) -> bool:
+def check_ELF_CANARY(binary) -> bool:
'''
Check for use of stack canary
'''
return binary.has_symbol('__stack_chk_fail')
-def check_ELF_separate_code(binary):
+def check_ELF_SEPARATE_CODE(binary):
'''
Check that sections are appropriately separated in virtual memory,
based on their permissions. This checks for missing -Wl,-z,separate-code
@@ -105,7 +105,7 @@ def check_ELF_separate_code(binary):
return False
return True
-def check_ELF_control_flow(binary) -> bool:
+def check_ELF_CONTROL_FLOW(binary) -> bool:
'''
Check for control flow instrumentation
'''
@@ -130,7 +130,7 @@ def check_PE_RELOC_SECTION(binary) -> bool:
'''Check for a reloc section. This is required for functional ASLR.'''
return binary.has_relocations
-def check_PE_control_flow(binary) -> bool:
+def check_PE_CONTROL_FLOW(binary) -> bool:
'''
Check for control flow instrumentation
'''
@@ -145,7 +145,7 @@ def check_PE_control_flow(binary) -> bool:
return True
return False
-def check_PE_Canary(binary) -> bool:
+def check_PE_CANARY(binary) -> bool:
'''
Check for use of stack canary
'''
@@ -163,7 +163,7 @@ def check_MACHO_FIXUP_CHAINS(binary) -> bool:
'''
return binary.has_dyld_chained_fixups
-def check_MACHO_Canary(binary) -> bool:
+def check_MACHO_CANARY(binary) -> bool:
'''
Check for use of stack canary
'''
@@ -182,7 +182,7 @@ def check_NX(binary) -> bool:
'''
return binary.has_nx
-def check_MACHO_control_flow(binary) -> bool:
+def check_MACHO_CONTROL_FLOW(binary) -> bool:
'''
Check for control flow instrumentation
'''
@@ -192,7 +192,7 @@ def check_MACHO_control_flow(binary) -> bool:
return True
return False
-def check_MACHO_branch_protection(binary) -> bool:
+def check_MACHO_BRANCH_PROTECTION(binary) -> bool:
'''
Check for branch protection instrumentation
'''
@@ -206,8 +206,8 @@ BASE_ELF = [
('PIE', check_PIE),
('NX', check_NX),
('RELRO', check_ELF_RELRO),
- ('Canary', check_ELF_Canary),
- ('separate_code', check_ELF_separate_code),
+ ('CANARY', check_ELF_CANARY),
+ ('SEPARATE_CODE', check_ELF_SEPARATE_CODE),
]
BASE_PE = [
@@ -216,19 +216,19 @@ BASE_PE = [
('HIGH_ENTROPY_VA', check_PE_HIGH_ENTROPY_VA),
('NX', check_NX),
('RELOC_SECTION', check_PE_RELOC_SECTION),
- ('CONTROL_FLOW', check_PE_control_flow),
- ('Canary', check_PE_Canary),
+ ('CONTROL_FLOW', check_PE_CONTROL_FLOW),
+ ('CANARY', check_PE_CANARY),
]
BASE_MACHO = [
('NOUNDEFS', check_MACHO_NOUNDEFS),
- ('Canary', check_MACHO_Canary),
+ ('CANARY', check_MACHO_CANARY),
('FIXUP_CHAINS', check_MACHO_FIXUP_CHAINS),
]
CHECKS = {
lief.EXE_FORMATS.ELF: {
- lief.ARCHITECTURES.X86: BASE_ELF + [('CONTROL_FLOW', check_ELF_control_flow)],
+ lief.ARCHITECTURES.X86: BASE_ELF + [('CONTROL_FLOW', check_ELF_CONTROL_FLOW)],
lief.ARCHITECTURES.ARM: BASE_ELF,
lief.ARCHITECTURES.ARM64: BASE_ELF,
lief.ARCHITECTURES.PPC: BASE_ELF,
@@ -240,39 +240,24 @@ CHECKS = {
lief.EXE_FORMATS.MACHO: {
lief.ARCHITECTURES.X86: BASE_MACHO + [('PIE', check_PIE),
('NX', check_NX),
- ('CONTROL_FLOW', check_MACHO_control_flow)],
- lief.ARCHITECTURES.ARM64: BASE_MACHO + [('BRANCH_PROTECTION', check_MACHO_branch_protection)],
+ ('CONTROL_FLOW', check_MACHO_CONTROL_FLOW)],
+ lief.ARCHITECTURES.ARM64: BASE_MACHO + [('BRANCH_PROTECTION', check_MACHO_BRANCH_PROTECTION)],
}
}
if __name__ == '__main__':
retval: int = 0
for filename in sys.argv[1:]:
- try:
- binary = lief.parse(filename)
- etype = binary.format
- arch = binary.abstract.header.architecture
- binary.concrete
-
- if etype == lief.EXE_FORMATS.UNKNOWN:
- print(f'{filename}: unknown executable format')
- retval = 1
- continue
-
- if arch == lief.ARCHITECTURES.NONE:
- print(f'{filename}: unknown architecture')
- retval = 1
- continue
-
- failed: list[str] = []
- for (name, func) in CHECKS[etype][arch]:
- if not func(binary):
- failed.append(name)
- if failed:
- print(f'{filename}: failed {" ".join(failed)}')
- retval = 1
- except IOError:
- print(f'{filename}: cannot open')
+ binary = lief.parse(filename)
+ etype = binary.format
+ arch = binary.abstract.header.architecture
+ binary.concrete
+
+ failed: list[str] = []
+ for (name, func) in CHECKS[etype][arch]:
+ if not func(binary):
+ failed.append(name)
+ if failed:
+ print(f'{filename}: failed {" ".join(failed)}')
retval = 1
sys.exit(retval)
-
diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py
index c4e6bc81e1..1722c7d290 100755
--- a/contrib/devtools/symbol-check.py
+++ b/contrib/devtools/symbol-check.py
@@ -245,7 +245,7 @@ def check_MACHO_sdk(binary) -> bool:
return False
def check_MACHO_lld(binary) -> bool:
- if binary.build_version.tools[0].version == [18, 1, 6]:
+ if binary.build_version.tools[0].version == [18, 1, 8]:
return True
return False
@@ -299,22 +299,14 @@ lief.EXE_FORMATS.PE: [
if __name__ == '__main__':
retval: int = 0
for filename in sys.argv[1:]:
- try:
- binary = lief.parse(filename)
- etype = binary.format
- if etype == lief.EXE_FORMATS.UNKNOWN:
- print(f'{filename}: unknown executable format')
- retval = 1
- continue
-
- failed: list[str] = []
- for (name, func) in CHECKS[etype]:
- if not func(binary):
- failed.append(name)
- if failed:
- print(f'{filename}: failed {" ".join(failed)}')
- retval = 1
- except IOError:
- print(f'{filename}: cannot open')
+ binary = lief.parse(filename)
+ etype = binary.format
+
+ failed: list[str] = []
+ for (name, func) in CHECKS[etype]:
+ if not func(binary):
+ failed.append(name)
+ if failed:
+ print(f'{filename}: failed {" ".join(failed)}')
retval = 1
sys.exit(retval)
diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py
index 7bfd4d98da..4bec6bfe7c 100755
--- a/contrib/devtools/test-security-check.py
+++ b/contrib/devtools/test-security-check.py
@@ -15,10 +15,10 @@ from utils import determine_wellknown_cmd
def write_testcode(filename):
with open(filename, 'w', encoding="utf8") as f:
f.write('''
- #include <stdio.h>
+ #include <cstdio>
int main()
{
- printf("the quick brown fox jumps over the lazy god\\n");
+ std::printf("the quick brown fox jumps over the lazy god\\n");
return 0;
}
''')
@@ -34,17 +34,17 @@ def env_flags() -> list[str]:
# See the definitions for ac_link in autoconf's lib/autoconf/c.m4 file for
# reference.
flags: list[str] = []
- for var in ['CFLAGS', 'CPPFLAGS', 'LDFLAGS']:
+ for var in ['CXXFLAGS', 'CPPFLAGS', 'LDFLAGS']:
flags += filter(None, os.environ.get(var, '').split(' '))
return flags
-def call_security_check(cc: str, source: str, executable: str, options) -> tuple:
- subprocess.run([*cc,source,'-o',executable] + env_flags() + options, check=True)
+def call_security_check(cxx: str, source: str, executable: str, options) -> tuple:
+ subprocess.run([*cxx,source,'-o',executable] + env_flags() + options, check=True)
p = subprocess.run([os.path.join(os.path.dirname(__file__), 'security-check.py'), executable], stdout=subprocess.PIPE, text=True)
return (p.returncode, p.stdout.rstrip())
-def get_arch(cc, source, executable):
- subprocess.run([*cc, source, '-o', executable] + env_flags(), check=True)
+def get_arch(cxx, source, executable):
+ subprocess.run([*cxx, source, '-o', executable] + env_flags(), check=True)
binary = lief.parse(executable)
arch = binary.abstract.header.architecture
os.remove(executable)
@@ -52,95 +52,72 @@ def get_arch(cc, source, executable):
class TestSecurityChecks(unittest.TestCase):
def test_ELF(self):
- source = 'test1.c'
+ source = 'test1.cpp'
executable = 'test1'
- cc = determine_wellknown_cmd('CC', 'gcc')
+ cxx = determine_wellknown_cmd('CXX', 'g++')
write_testcode(source)
- arch = get_arch(cc, source, executable)
+ arch = get_arch(cxx, source, executable)
if arch == lief.ARCHITECTURES.X86:
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-zexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']),
- (1, executable+': failed PIE NX RELRO CONTROL_FLOW'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']),
- (1, executable+': failed PIE RELRO CONTROL_FLOW'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']),
- (1, executable+': failed PIE RELRO CONTROL_FLOW'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-pie','-fPIE', '-Wl,-z,separate-code']),
- (1, executable+': failed RELRO CONTROL_FLOW'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,noseparate-code']),
- (1, executable+': failed separate_code CONTROL_FLOW'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,separate-code']),
- (1, executable+': failed CONTROL_FLOW'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,separate-code', '-fcf-protection=full']),
- (0, ''))
+ pass_flags = ['-Wl,-znoexecstack', '-Wl,-zrelro', '-Wl,-z,now', '-pie', '-fPIE', '-Wl,-z,separate-code', '-fcf-protection=full']
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-zexecstack']), (1, executable + ': failed NX'))
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-no-pie','-fno-PIE']), (1, executable + ': failed PIE'))
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-znorelro']), (1, executable + ': failed RELRO'))
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-z,noseparate-code']), (1, executable + ': failed SEPARATE_CODE'))
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-fcf-protection=none']), (1, executable + ': failed CONTROL_FLOW'))
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags), (0, ''))
else:
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-zexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']),
- (1, executable+': failed PIE NX RELRO'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']),
- (1, executable+': failed PIE RELRO'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']),
- (1, executable+': failed PIE RELRO'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-pie','-fPIE', '-Wl,-z,separate-code']),
- (1, executable+': failed RELRO'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,noseparate-code']),
- (1, executable+': failed separate_code'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,separate-code']),
- (0, ''))
+ pass_flags = ['-Wl,-znoexecstack', '-Wl,-zrelro', '-Wl,-z,now', '-pie', '-fPIE', '-Wl,-z,separate-code']
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-zexecstack']), (1, executable + ': failed NX'))
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-no-pie','-fno-PIE']), (1, executable + ': failed PIE'))
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-znorelro']), (1, executable + ': failed RELRO'))
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-z,noseparate-code']), (1, executable + ': failed SEPARATE_CODE'))
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags), (0, ''))
clean_files(source, executable)
def test_PE(self):
- source = 'test1.c'
+ source = 'test1.cpp'
executable = 'test1.exe'
- cc = determine_wellknown_cmd('CC', 'x86_64-w64-mingw32-gcc')
+ cxx = determine_wellknown_cmd('CXX', 'x86_64-w64-mingw32-g++')
write_testcode(source)
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--disable-nxcompat','-Wl,--disable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-no-pie','-fno-PIE','-fno-stack-protector']),
- (1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA NX RELOC_SECTION CONTROL_FLOW Canary'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--disable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-no-pie','-fno-PIE','-fstack-protector-all', '-lssp']),
- (1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA RELOC_SECTION CONTROL_FLOW'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-no-pie','-fno-PIE','-fstack-protector-all', '-lssp']),
- (1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA CONTROL_FLOW'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-pie','-fPIE','-fstack-protector-all', '-lssp']),
- (1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA CONTROL_FLOW')) # -pie -fPIE does nothing unless --dynamicbase is also supplied
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--dynamicbase','-Wl,--disable-high-entropy-va','-pie','-fPIE','-fstack-protector-all', '-lssp']),
- (1, executable+': failed HIGH_ENTROPY_VA CONTROL_FLOW'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--dynamicbase','-Wl,--high-entropy-va','-pie','-fPIE','-fstack-protector-all', '-lssp']),
- (1, executable+': failed CONTROL_FLOW'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--dynamicbase','-Wl,--high-entropy-va','-pie','-fPIE', '-fcf-protection=full','-fstack-protector-all', '-lssp']),
- (0, ''))
+ pass_flags = ['-Wl,--nxcompat', '-Wl,--enable-reloc-section', '-Wl,--dynamicbase', '-Wl,--high-entropy-va', '-pie', '-fPIE', '-fcf-protection=full', '-fstack-protector-all', '-lssp']
+
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-fno-stack-protector']), (1, executable + ': failed CANARY'))
+ # https://github.com/lief-project/LIEF/issues/1076 - in future, we could test this individually.
+ # self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,--disable-reloc-section']), (1, executable + ': failed RELOC_SECTION'))
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,--disable-nxcompat']), (1, executable + ': failed NX'))
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,--disable-dynamicbase']), (1, executable + ': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA')) # -pie -fPIE does nothing without --dynamicbase
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,--disable-high-entropy-va']), (1, executable + ': failed HIGH_ENTROPY_VA'))
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-fcf-protection=none']), (1, executable + ': failed CONTROL_FLOW'))
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags), (0, ''))
clean_files(source, executable)
def test_MACHO(self):
- source = 'test1.c'
+ source = 'test1.cpp'
executable = 'test1'
- cc = determine_wellknown_cmd('CC', 'clang')
+ cxx = determine_wellknown_cmd('CXX', 'clang++')
write_testcode(source)
- arch = get_arch(cc, source, executable)
+ arch = get_arch(cxx, source, executable)
if arch == lief.ARCHITECTURES.X86:
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-no_pie','-Wl,-flat_namespace','-fno-stack-protector', '-Wl,-no_fixup_chains']),
- (1, executable+': failed NOUNDEFS Canary FIXUP_CHAINS PIE CONTROL_FLOW'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-flat_namespace','-fno-stack-protector', '-Wl,-fixup_chains']),
- (1, executable+': failed NOUNDEFS Canary CONTROL_FLOW'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-flat_namespace','-fstack-protector-all', '-Wl,-fixup_chains']),
- (1, executable+': failed NOUNDEFS CONTROL_FLOW'))
- self.assertEqual(call_security_check(cc, source, executable, ['-fstack-protector-all', '-Wl,-fixup_chains']),
- (1, executable+': failed CONTROL_FLOW'))
- self.assertEqual(call_security_check(cc, source, executable, ['-fstack-protector-all', '-fcf-protection=full', '-Wl,-fixup_chains']),
- (0, ''))
+ pass_flags = ['-Wl,-pie', '-fstack-protector-all', '-fcf-protection=full', '-Wl,-fixup_chains']
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-no_pie', '-Wl,-no_fixup_chains']), (1, executable+': failed FIXUP_CHAINS PIE')) # -fixup_chains is incompatible with -no_pie
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-no_fixup_chains']), (1, executable + ': failed FIXUP_CHAINS'))
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-fno-stack-protector']), (1, executable + ': failed CANARY'))
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-flat_namespace']), (1, executable + ': failed NOUNDEFS'))
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-fcf-protection=none']), (1, executable + ': failed CONTROL_FLOW'))
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags), (0, ''))
else:
- # arm64 darwin doesn't support non-PIE binaries, control flow or executable stacks
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-flat_namespace','-fno-stack-protector', '-Wl,-no_fixup_chains']),
- (1, executable+': failed NOUNDEFS Canary FIXUP_CHAINS BRANCH_PROTECTION'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-flat_namespace','-fno-stack-protector', '-Wl,-fixup_chains', '-mbranch-protection=bti']),
- (1, executable+': failed NOUNDEFS Canary'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-flat_namespace','-fstack-protector-all', '-Wl,-fixup_chains', '-mbranch-protection=bti']),
- (1, executable+': failed NOUNDEFS'))
- self.assertEqual(call_security_check(cc, source, executable, ['-fstack-protector-all', '-Wl,-fixup_chains', '-mbranch-protection=bti']),
- (0, ''))
-
+ # arm64 darwin doesn't support non-PIE binaries or executable stacks
+ pass_flags = ['-fstack-protector-all', '-Wl,-fixup_chains', '-mbranch-protection=bti']
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-mbranch-protection=none']), (1, executable + ': failed BRANCH_PROTECTION'))
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-no_fixup_chains']), (1, executable + ': failed FIXUP_CHAINS'))
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-fno-stack-protector']), (1, executable + ': failed CANARY'))
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-flat_namespace']), (1, executable + ': failed NOUNDEFS'))
+ self.assertEqual(call_security_check(cxx, source, executable, pass_flags), (0, ''))
clean_files(source, executable)
diff --git a/contrib/devtools/test-symbol-check.py b/contrib/devtools/test-symbol-check.py
index b00004586c..454dbc6bd2 100755
--- a/contrib/devtools/test-symbol-check.py
+++ b/contrib/devtools/test-symbol-check.py
@@ -11,17 +11,17 @@ import unittest
from utils import determine_wellknown_cmd
-def call_symbol_check(cc: list[str], source, executable, options):
+def call_symbol_check(cxx: list[str], source, executable, options):
# This should behave the same as AC_TRY_LINK, so arrange well-known flags
# in the same order as autoconf would.
#
# See the definitions for ac_link in autoconf's lib/autoconf/c.m4 file for
# reference.
env_flags: list[str] = []
- for var in ['CFLAGS', 'CPPFLAGS', 'LDFLAGS']:
+ for var in ['CXXFLAGS', 'CPPFLAGS', 'LDFLAGS']:
env_flags += filter(None, os.environ.get(var, '').split(' '))
- subprocess.run([*cc,source,'-o',executable] + env_flags + options, check=True)
+ subprocess.run([*cxx,source,'-o',executable] + env_flags + options, check=True)
p = subprocess.run([os.path.join(os.path.dirname(__file__), 'symbol-check.py'), executable], stdout=subprocess.PIPE, text=True)
os.remove(source)
os.remove(executable)
@@ -29,13 +29,13 @@ def call_symbol_check(cc: list[str], source, executable, options):
class TestSymbolChecks(unittest.TestCase):
def test_ELF(self):
- source = 'test1.c'
+ source = 'test1.cpp'
executable = 'test1'
- cc = determine_wellknown_cmd('CC', 'gcc')
+ cxx = determine_wellknown_cmd('CXX', 'g++')
# -lutil is part of the libc6 package so a safe bet that it's installed
# it's also out of context enough that it's unlikely to ever become a real dependency
- source = 'test2.c'
+ source = 'test2.cpp'
executable = 'test2'
with open(source, 'w', encoding="utf8") as f:
f.write('''
@@ -48,31 +48,31 @@ class TestSymbolChecks(unittest.TestCase):
}
''')
- self.assertEqual(call_symbol_check(cc, source, executable, ['-lutil']),
+ self.assertEqual(call_symbol_check(cxx, source, executable, ['-lutil']),
(1, executable + ': libutil.so.1 is not in ALLOWED_LIBRARIES!\n' +
executable + ': failed LIBRARY_DEPENDENCIES'))
# finally, check a simple conforming binary
- source = 'test3.c'
+ source = 'test3.cpp'
executable = 'test3'
with open(source, 'w', encoding="utf8") as f:
f.write('''
- #include <stdio.h>
+ #include <cstdio>
int main()
{
- printf("42");
+ std::printf("42");
return 0;
}
''')
- self.assertEqual(call_symbol_check(cc, source, executable, []),
+ self.assertEqual(call_symbol_check(cxx, source, executable, []),
(0, ''))
def test_MACHO(self):
- source = 'test1.c'
+ source = 'test1.cpp'
executable = 'test1'
- cc = determine_wellknown_cmd('CC', 'clang')
+ cxx = determine_wellknown_cmd('CXX', 'clang++')
with open(source, 'w', encoding="utf8") as f:
f.write('''
@@ -86,11 +86,11 @@ class TestSymbolChecks(unittest.TestCase):
''')
- self.assertEqual(call_symbol_check(cc, source, executable, ['-lexpat', '-Wl,-platform_version','-Wl,macos', '-Wl,11.4', '-Wl,11.4']),
+ self.assertEqual(call_symbol_check(cxx, source, executable, ['-lexpat', '-Wl,-platform_version','-Wl,macos', '-Wl,11.4', '-Wl,11.4']),
(1, 'libexpat.1.dylib is not in ALLOWED_LIBRARIES!\n' +
f'{executable}: failed DYNAMIC_LIBRARIES MIN_OS SDK'))
- source = 'test2.c'
+ source = 'test2.cpp'
executable = 'test2'
with open(source, 'w', encoding="utf8") as f:
f.write('''
@@ -103,10 +103,10 @@ class TestSymbolChecks(unittest.TestCase):
}
''')
- self.assertEqual(call_symbol_check(cc, source, executable, ['-framework', 'CoreGraphics', '-Wl,-platform_version','-Wl,macos', '-Wl,11.4', '-Wl,11.4']),
+ self.assertEqual(call_symbol_check(cxx, source, executable, ['-framework', 'CoreGraphics', '-Wl,-platform_version','-Wl,macos', '-Wl,11.4', '-Wl,11.4']),
(1, f'{executable}: failed MIN_OS SDK'))
- source = 'test3.c'
+ source = 'test3.cpp'
executable = 'test3'
with open(source, 'w', encoding="utf8") as f:
f.write('''
@@ -116,13 +116,13 @@ class TestSymbolChecks(unittest.TestCase):
}
''')
- self.assertEqual(call_symbol_check(cc, source, executable, ['-Wl,-platform_version','-Wl,macos', '-Wl,11.0', '-Wl,11.4']),
+ self.assertEqual(call_symbol_check(cxx, source, executable, ['-Wl,-platform_version','-Wl,macos', '-Wl,11.0', '-Wl,11.4']),
(1, f'{executable}: failed SDK'))
def test_PE(self):
- source = 'test1.c'
+ source = 'test1.cpp'
executable = 'test1.exe'
- cc = determine_wellknown_cmd('CC', 'x86_64-w64-mingw32-gcc')
+ cxx = determine_wellknown_cmd('CXX', 'x86_64-w64-mingw32-g++')
with open(source, 'w', encoding="utf8") as f:
f.write('''
@@ -135,11 +135,11 @@ class TestSymbolChecks(unittest.TestCase):
}
''')
- self.assertEqual(call_symbol_check(cc, source, executable, ['-lpdh', '-Wl,--major-subsystem-version', '-Wl,6', '-Wl,--minor-subsystem-version', '-Wl,1']),
+ self.assertEqual(call_symbol_check(cxx, source, executable, ['-lpdh', '-Wl,--major-subsystem-version', '-Wl,6', '-Wl,--minor-subsystem-version', '-Wl,1']),
(1, 'pdh.dll is not in ALLOWED_LIBRARIES!\n' +
executable + ': failed DYNAMIC_LIBRARIES'))
- source = 'test2.c'
+ source = 'test2.cpp'
executable = 'test2.exe'
with open(source, 'w', encoding="utf8") as f:
@@ -150,10 +150,10 @@ class TestSymbolChecks(unittest.TestCase):
}
''')
- self.assertEqual(call_symbol_check(cc, source, executable, ['-Wl,--major-subsystem-version', '-Wl,9', '-Wl,--minor-subsystem-version', '-Wl,9']),
+ self.assertEqual(call_symbol_check(cxx, source, executable, ['-Wl,--major-subsystem-version', '-Wl,9', '-Wl,--minor-subsystem-version', '-Wl,9']),
(1, executable + ': failed SUBSYSTEM_VERSION'))
- source = 'test3.c'
+ source = 'test3.cpp'
executable = 'test3.exe'
with open(source, 'w', encoding="utf8") as f:
f.write('''
@@ -166,7 +166,7 @@ class TestSymbolChecks(unittest.TestCase):
}
''')
- self.assertEqual(call_symbol_check(cc, source, executable, ['-lole32', '-Wl,--major-subsystem-version', '-Wl,6', '-Wl,--minor-subsystem-version', '-Wl,1']),
+ self.assertEqual(call_symbol_check(cxx, source, executable, ['-lole32', '-Wl,--major-subsystem-version', '-Wl,6', '-Wl,--minor-subsystem-version', '-Wl,1']),
(0, ''))
diff --git a/contrib/devtools/test_utxo_snapshots.sh b/contrib/devtools/test_utxo_snapshots.sh
index d7c019f4a6..ad948d4a14 100755
--- a/contrib/devtools/test_utxo_snapshots.sh
+++ b/contrib/devtools/test_utxo_snapshots.sh
@@ -138,7 +138,7 @@ echo
echo "-- Now: add the following to CMainParams::m_assumeutxo_data"
echo " in src/kernel/chainparams.cpp, and recompile:"
echo
-echo " {${RPC_BASE_HEIGHT}, AssumeutxoHash{uint256S(\"0x${RPC_AU}\")}, ${RPC_NCHAINTX}, uint256S(\"0x${RPC_BLOCKHASH}\")},"
+echo " {.height = ${RPC_BASE_HEIGHT}, .hash_serialized = AssumeutxoHash{uint256{\"${RPC_AU}\"}}, .m_chain_tx_count = ${RPC_NCHAINTX}, .blockhash = consteval_ctor(uint256{\"${RPC_BLOCKHASH}\"})},"
echo
echo
echo "-- IBDing more blocks to the server node (height=$FINAL_HEIGHT) so there is a diff between snapshot and tip..."