mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-28 20:17:29 -03:00
792d0d8d51
5a8f907c93
scripts: add CONTROL_FLOW to ELF security checks (fanquake)e13f8f775d
build: build x86_64 Linux Boost with -fcf-protection=full (fanquake)6ca5efa8ed
script rename control flow check to MACHO specific (fanquake) Pull request description: Closes #21888. TODO: * Duplication in security-check-tests Guix build: ```bash bash-5.1# find guix-build-$(git rev-parse --short=12 HEAD)/output/ -type f -print0 | env LC_ALL=C sort -z | xargs -r0 sha256sum 8025e2e6859247eaf865a4a5009d0a39570ec5e8ab51739fa4da0d8ee4ab2117 guix-build-5a8f907c93f1/output/aarch64-linux-gnu/SHA256SUMS.part 75576482994493262dbf7d3567b0450c0804bdc75c186d6b4c6a856bd0d8f0a3 guix-build-5a8f907c93f1/output/aarch64-linux-gnu/bitcoin-5a8f907c93f1-aarch64-linux-gnu-debug.tar.gz 7cb89c9327cc540859334b597c041a2250156e3e83ce2aa7d16177376056302f guix-build-5a8f907c93f1/output/aarch64-linux-gnu/bitcoin-5a8f907c93f1-aarch64-linux-gnu.tar.gz e264053e4c7a5d65340dd7bbd2c664bcd596292ab80f00a0bf0026bfe0c480bc guix-build-5a8f907c93f1/output/arm-linux-gnueabihf/SHA256SUMS.part 6c3ee9b3c0c4583620301b183226678f1618605dd07dbed0bbdf7d06d3591314 guix-build-5a8f907c93f1/output/arm-linux-gnueabihf/bitcoin-5a8f907c93f1-arm-linux-gnueabihf-debug.tar.gz f217cb8d8e233a8dbdbfde7dabf12c5d867d7de53e8c652b8ed1d4a55da82fd9 guix-build-5a8f907c93f1/output/arm-linux-gnueabihf/bitcoin-5a8f907c93f1-arm-linux-gnueabihf.tar.gz 48b4b2a1b52b3098f4e92c11cb60f1e5e9696a2a960560cd6adea72277eaa4a4 guix-build-5a8f907c93f1/output/dist-archive/bitcoin-5a8f907c93f1.tar.gz 40832db2446e129879caa9fbc9d682c53069876dbb2e0d4d76592e5dcb40bb12 guix-build-5a8f907c93f1/output/powerpc64-linux-gnu/SHA256SUMS.part 26fdfa9b7b77d5db415ef34054cf6f6d020a5dab73239db6dd05539f654bc5d5 guix-build-5a8f907c93f1/output/powerpc64-linux-gnu/bitcoin-5a8f907c93f1-powerpc64-linux-gnu-debug.tar.gz 3adbdb9d3eb1cb5f9adc38b29450054f286bd6d74cef8619adaee89494853605 guix-build-5a8f907c93f1/output/powerpc64-linux-gnu/bitcoin-5a8f907c93f1-powerpc64-linux-gnu.tar.gz 8ec2baf82483a698350bfdabf530cd9b5241690c916f597c746210e95ac451de guix-build-5a8f907c93f1/output/powerpc64le-linux-gnu/SHA256SUMS.part 1797e75e1f66ec9068fa4e57e0108960475e863f8f054fbe854358b1f995c4df guix-build-5a8f907c93f1/output/powerpc64le-linux-gnu/bitcoin-5a8f907c93f1-powerpc64le-linux-gnu-debug.tar.gz 448bd289ef26c777a1fc4498e7ba7fb17d0f6a932dcac91b2f89cbba63704bb8 guix-build-5a8f907c93f1/output/powerpc64le-linux-gnu/bitcoin-5a8f907c93f1-powerpc64le-linux-gnu.tar.gz a23ee91eeae515c2a6a31eb25d659fab833839aaafa4676ccee364bdad2a468c guix-build-5a8f907c93f1/output/riscv64-linux-gnu/SHA256SUMS.part 82df1b6d5020d0af8268ecc8e823f752f20dec308277763b2dd675804dfa4bbd guix-build-5a8f907c93f1/output/riscv64-linux-gnu/bitcoin-5a8f907c93f1-riscv64-linux-gnu-debug.tar.gz 09a6098ce83896a6ee6d5c8aff12eaca51595bd724c8e0b2a6f90b6410dc168c guix-build-5a8f907c93f1/output/riscv64-linux-gnu/bitcoin-5a8f907c93f1-riscv64-linux-gnu.tar.gz 4fac2951f80eaa2bd1747a263be6be1b76282cac5062f7d86db631a2fb80f8db guix-build-5a8f907c93f1/output/x86_64-apple-darwin/SHA256SUMS.part 3392f417b09efca5916c384f0b2d0c177a72ec4921399c62e84484f0054cc8c4 guix-build-5a8f907c93f1/output/x86_64-apple-darwin/bitcoin-5a8f907c93f1-osx-unsigned.dmg bfb4f8ade6107996ec4bc9efdb53959151b8fb19b6790c34472fe218dd02383d guix-build-5a8f907c93f1/output/x86_64-apple-darwin/bitcoin-5a8f907c93f1-osx-unsigned.tar.gz 4de92e149bad46fc863efb3b650753d194aad96be991d020e0b859452cf27457 guix-build-5a8f907c93f1/output/x86_64-apple-darwin/bitcoin-5a8f907c93f1-osx64.tar.gz 9329549a2f275a59e329afc8744ff8cbc297f3042e0ad03b47626805c7aae2e8 guix-build-5a8f907c93f1/output/x86_64-linux-gnu/SHA256SUMS.part d87deb1eca8a1d3780f02edde78350d27f700e13c7ff444be0bfb34e7369904a guix-build-5a8f907c93f1/output/x86_64-linux-gnu/bitcoin-5a8f907c93f1-x86_64-linux-gnu-debug.tar.gz 76f3bc2fad010d9373e854d941e8205b68fa6c9a8ecaff34c4978ae3ae76c806 guix-build-5a8f907c93f1/output/x86_64-linux-gnu/bitcoin-5a8f907c93f1-x86_64-linux-gnu.tar.gz 2948631081c4bd475529da2b7bc2b32b5aa2e44de46dfdaa6cf9432b3c9fe869 guix-build-5a8f907c93f1/output/x86_64-w64-mingw32/SHA256SUMS.part c5d56fac163b73c00e9745aa7b0f9a0bd9fcac7517e39b677869b6e76faf7218 guix-build-5a8f907c93f1/output/x86_64-w64-mingw32/bitcoin-5a8f907c93f1-win-unsigned.tar.gz f12c7cd72511544c67f4934981c090cee0d9c17e931c059edbbbef6e843dd651 guix-build-5a8f907c93f1/output/x86_64-w64-mingw32/bitcoin-5a8f907c93f1-win64-debug.zip eb952cc4554f92ba6787353f4305d7cbcb1c6dafc4a3867b3088106252a573b8 guix-build-5a8f907c93f1/output/x86_64-w64-mingw32/bitcoin-5a8f907c93f1-win64-setup-unsigned.exe 7bd2b071f1cdf9410535e6a10dd1da519f942bd2c1e47ed52c5b8c4f977e8f27 guix-build-5a8f907c93f1/output/x86_64-w64-mingw32/bitcoin-5a8f907c93f1-win64.zip ``` ACKs for top commit: laanwj: Code review ACK5a8f907c93
hebasto: ACK5a8f907c93
, I have reviewed the code and it looks OK, I agree it can be merged. Tree-SHA512: 75702ac01175ccf08e73b5c3bce266cee9dd15ccf8fb38d46108cfada156de9a8c18e27d996f9343ae33f7a75a6904d335cbe25256d90af1f4ccbe72ce1788bb
138 lines
8.9 KiB
Python
Executable file
138 lines
8.9 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
# Copyright (c) 2015-2021 The Bitcoin Core developers
|
|
# Distributed under the MIT software license, see the accompanying
|
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
'''
|
|
Test script for security-check.py
|
|
'''
|
|
import lief #type:ignore
|
|
import os
|
|
import subprocess
|
|
from typing import List
|
|
import unittest
|
|
|
|
from utils import determine_wellknown_cmd
|
|
|
|
def write_testcode(filename):
|
|
with open(filename, 'w', encoding="utf8") as f:
|
|
f.write('''
|
|
#include <stdio.h>
|
|
int main()
|
|
{
|
|
printf("the quick brown fox jumps over the lazy god\\n");
|
|
return 0;
|
|
}
|
|
''')
|
|
|
|
def clean_files(source, executable):
|
|
os.remove(source)
|
|
os.remove(executable)
|
|
|
|
def call_security_check(cc, 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']:
|
|
env_flags += filter(None, os.environ.get(var, '').split(' '))
|
|
|
|
subprocess.run([*cc,source,'-o',executable] + env_flags + options, check=True)
|
|
p = subprocess.run(['./contrib/devtools/security-check.py',executable], stdout=subprocess.PIPE, universal_newlines=True)
|
|
return (p.returncode, p.stdout.rstrip())
|
|
|
|
def get_arch(cc, source, executable):
|
|
subprocess.run([*cc, source, '-o', executable], check=True)
|
|
binary = lief.parse(executable)
|
|
arch = binary.abstract.header.architecture
|
|
os.remove(executable)
|
|
return arch
|
|
|
|
class TestSecurityChecks(unittest.TestCase):
|
|
def test_ELF(self):
|
|
source = 'test1.c'
|
|
executable = 'test1'
|
|
cc = determine_wellknown_cmd('CC', 'gcc')
|
|
write_testcode(source)
|
|
arch = get_arch(cc, source, executable)
|
|
|
|
if arch == lief.ARCHITECTURES.X86:
|
|
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-zexecstack','-fno-stack-protector','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']),
|
|
(1, executable+': failed PIE NX RELRO Canary CONTROL_FLOW'))
|
|
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fno-stack-protector','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']),
|
|
(1, executable+': failed PIE RELRO Canary CONTROL_FLOW'))
|
|
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-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','-fstack-protector-all','-Wl,-znorelro','-pie','-fPIE', '-Wl,-z,separate-code']),
|
|
(1, executable+': failed RELRO CONTROL_FLOW'))
|
|
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-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','-fstack-protector-all','-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','-fstack-protector-all','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,separate-code', '-fcf-protection=full']),
|
|
(0, ''))
|
|
else:
|
|
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-zexecstack','-fno-stack-protector','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']),
|
|
(1, executable+': failed PIE NX RELRO Canary'))
|
|
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fno-stack-protector','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']),
|
|
(1, executable+': failed PIE RELRO Canary'))
|
|
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-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','-fstack-protector-all','-Wl,-znorelro','-pie','-fPIE', '-Wl,-z,separate-code']),
|
|
(1, executable+': failed RELRO'))
|
|
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-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','-fstack-protector-all','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,separate-code']),
|
|
(0, ''))
|
|
|
|
clean_files(source, executable)
|
|
|
|
def test_PE(self):
|
|
source = 'test1.c'
|
|
executable = 'test1.exe'
|
|
cc = determine_wellknown_cmd('CC', 'x86_64-w64-mingw32-gcc')
|
|
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']),
|
|
(1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA NX RELOC_SECTION CONTROL_FLOW'))
|
|
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']),
|
|
(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']),
|
|
(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']),
|
|
(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']),
|
|
(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']),
|
|
(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']),
|
|
(0, ''))
|
|
|
|
clean_files(source, executable)
|
|
|
|
def test_MACHO(self):
|
|
source = 'test1.c'
|
|
executable = 'test1'
|
|
cc = determine_wellknown_cmd('CC', 'clang')
|
|
write_testcode(source)
|
|
|
|
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-no_pie','-Wl,-flat_namespace','-Wl,-allow_stack_execute','-fno-stack-protector']),
|
|
(1, executable+': failed PIE NOUNDEFS NX LAZY_BINDINGS Canary CONTROL_FLOW'))
|
|
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-no_pie','-Wl,-flat_namespace','-Wl,-allow_stack_execute','-fstack-protector-all']),
|
|
(1, executable+': failed PIE NOUNDEFS NX LAZY_BINDINGS CONTROL_FLOW'))
|
|
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-no_pie','-Wl,-flat_namespace','-fstack-protector-all']),
|
|
(1, executable+': failed PIE NOUNDEFS LAZY_BINDINGS CONTROL_FLOW'))
|
|
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-no_pie','-fstack-protector-all']),
|
|
(1, executable+': failed PIE LAZY_BINDINGS CONTROL_FLOW'))
|
|
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-no_pie','-Wl,-bind_at_load','-fstack-protector-all']),
|
|
(1, executable+': failed PIE CONTROL_FLOW'))
|
|
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-no_pie','-Wl,-bind_at_load','-fstack-protector-all', '-fcf-protection=full']),
|
|
(1, executable+': failed PIE'))
|
|
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-pie','-Wl,-bind_at_load','-fstack-protector-all', '-fcf-protection=full']),
|
|
(0, ''))
|
|
|
|
clean_files(source, executable)
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|