mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-02 09:46:52 -05:00
Merge #18629: scripts: add PE .reloc section check to security-check.py
3e38023af7
scripts: add PE .reloc section check to security-check.py (fanquake) Pull request description: The `ld` in binutils has historically had a few issues with PE binaries, there's a good summary in this [thread](https://sourceware.org/bugzilla/show_bug.cgi?id=19011). One issue in particular was `ld` stripping the `.reloc` section out of PE binaries, even though it's required for functioning ASLR. This was [reported by a Tor developer in 2014](https://sourceware.org/bugzilla/show_bug.cgi?id=17321) and they have been patching their [own binutils](https://gitweb.torproject.org/builders/tor-browser-build.git/tree/projects/binutils) ever since. However their patch only made it into binutils at the [start of this year](https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commit;h=dc9bd8c92af67947db44b3cb428c050259b15cd0). It adds an `--enable-reloc-section` flag, which is turned on by default if you are using `--dynamic-base`. In the mean time this issue has also been worked around by other projects, such as FFmpeg, see [this commit](91b668acd6
). I have checked our recent supported Windows release binaries, and they do contain a `.reloc` section. From what I understand, we are using all the right compile/linker flags, including `-pie` & `-fPIE`, and have never run into the crashing/entrypoint issues that other projects might have seen. One other thing worth noting here, it how Debian/Ubuntu patch the binutils that they distribute, because that's what we end up using in our gitian builds. In the binutils-mingw-w64 in Bionic (18.04), which we currently use in gitian, PE hardening options/security flags are enabled by default. See the [changelog](https://changelogs.ubuntu.com/changelogs/pool/universe/b/binutils-mingw-w64/binutils-mingw-w64_8ubuntu1/changelog) and the [relevant commit](452b3013b8
). However in Focal (20.04), this has now been reversed. PE hardening options are no-longer the default. See the [changelog](https://changelogs.ubuntu.com/changelogs/pool/universe/b/binutils-mingw-w64/binutils-mingw-w64_8.8/changelog) and [relevant commit](7bd8b2fbc2
), which cites same .reloc issue mentioned here. Given that we explicitly specify/opt-in to everything that we want to use, the defaults aren't necessarily an issue for us. However I think it highlights the importance of continuing to be explicit about what we want, and not falling-back or relying on upstream. This was also prompted by the possibility of us doing link time garbage collection, see #18579 & #18605. It seemed some sanity checks would be worthwhile in-case the linker goes haywire while garbage collecting. I think Guix is going to bring great benefits when dealing with these kinds of issues. Carl you might have something to say in that regard. ACKs for top commit: dongcarl: ACK3e38023af7
Tree-SHA512: af14d63bdb334bde548dd7de3e0946556b7e2598d817b56eb4e75b3f56c705c26aa85dd9783134c4b6a7aeb7cb4de567eed996e94d533d31511f57ed332287da
This commit is contained in:
commit
ac21090f20
2 changed files with 22 additions and 8 deletions
|
@ -158,6 +158,17 @@ def check_PE_HIGH_ENTROPY_VA(executable):
|
||||||
reqbits = 0
|
reqbits = 0
|
||||||
return (bits & reqbits) == reqbits
|
return (bits & reqbits) == reqbits
|
||||||
|
|
||||||
|
def check_PE_RELOC_SECTION(executable) -> bool:
|
||||||
|
'''Check for a reloc section. This is required for functional ASLR.'''
|
||||||
|
p = subprocess.Popen([OBJDUMP_CMD, '-h', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
|
||||||
|
(stdout, stderr) = p.communicate()
|
||||||
|
if p.returncode:
|
||||||
|
raise IOError('Error opening file')
|
||||||
|
for line in stdout.splitlines():
|
||||||
|
if '.reloc' in line:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def check_PE_NX(executable):
|
def check_PE_NX(executable):
|
||||||
'''NX: DllCharacteristics bit 0x100 signifies nxcompat (DEP)'''
|
'''NX: DllCharacteristics bit 0x100 signifies nxcompat (DEP)'''
|
||||||
(arch,bits) = get_PE_dll_characteristics(executable)
|
(arch,bits) = get_PE_dll_characteristics(executable)
|
||||||
|
@ -247,7 +258,8 @@ CHECKS = {
|
||||||
'PE': [
|
'PE': [
|
||||||
('DYNAMIC_BASE', check_PE_DYNAMIC_BASE),
|
('DYNAMIC_BASE', check_PE_DYNAMIC_BASE),
|
||||||
('HIGH_ENTROPY_VA', check_PE_HIGH_ENTROPY_VA),
|
('HIGH_ENTROPY_VA', check_PE_HIGH_ENTROPY_VA),
|
||||||
('NX', check_PE_NX)
|
('NX', check_PE_NX),
|
||||||
|
('RELOC_SECTION', check_PE_RELOC_SECTION)
|
||||||
],
|
],
|
||||||
'MACHO': [
|
'MACHO': [
|
||||||
('PIE', check_MACHO_PIE),
|
('PIE', check_MACHO_PIE),
|
||||||
|
|
|
@ -49,13 +49,15 @@ class TestSecurityChecks(unittest.TestCase):
|
||||||
cc = 'x86_64-w64-mingw32-gcc'
|
cc = 'x86_64-w64-mingw32-gcc'
|
||||||
write_testcode(source)
|
write_testcode(source)
|
||||||
|
|
||||||
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--no-nxcompat','-Wl,--no-dynamicbase','-Wl,--no-high-entropy-va']),
|
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--no-nxcompat','-Wl,--no-dynamicbase','-Wl,--no-high-entropy-va','-no-pie','-fno-PIE']),
|
||||||
(1, executable+': failed DYNAMIC_BASE HIGH_ENTROPY_VA NX'))
|
(1, executable+': failed DYNAMIC_BASE HIGH_ENTROPY_VA NX RELOC_SECTION'))
|
||||||
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--no-dynamicbase','-Wl,--no-high-entropy-va']),
|
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--no-dynamicbase','-Wl,--no-high-entropy-va','-no-pie','-fno-PIE']),
|
||||||
(1, executable+': failed DYNAMIC_BASE HIGH_ENTROPY_VA'))
|
(1, executable+': failed DYNAMIC_BASE HIGH_ENTROPY_VA RELOC_SECTION'))
|
||||||
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase','-Wl,--no-high-entropy-va']),
|
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase','-Wl,--no-high-entropy-va','-no-pie','-fno-PIE']),
|
||||||
(1, executable+': failed HIGH_ENTROPY_VA'))
|
(1, executable+': failed HIGH_ENTROPY_VA RELOC_SECTION'))
|
||||||
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase','-Wl,--high-entropy-va']),
|
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase','-Wl,--high-entropy-va','-no-pie','-fno-PIE']),
|
||||||
|
(1, executable+': failed RELOC_SECTION'))
|
||||||
|
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase','-Wl,--high-entropy-va','-pie','-fPIE']),
|
||||||
(0, ''))
|
(0, ''))
|
||||||
|
|
||||||
def test_MACHO(self):
|
def test_MACHO(self):
|
||||||
|
|
Loading…
Add table
Reference in a new issue