Skip to content

Commit d0ca394

Browse files
committed
Merge #20476: contrib: Add test for ELF symbol-check
ed1bbce contrib: add MACHO tests to symbol-check tests (fanquake) 5bab08d contrib: Add test for ELF symbol-check (Wladimir J. van der Laan) Pull request description: Check both failure cases: - Use a glibc symbol from a version that is too new - Use a symbol from a library that is not in the allowlist And also check a conforming binary. Adding a similar check for Windows PE can be done in a separate PR. ACKs for top commit: fanquake: ACK ed1bbce Tree-SHA512: fd437612e003922465fe1396efa1fa3a64bd1c7b0a514d2a0a7a0caaaa9fb5cb43e0ed7caec15eb0a3508692c9eb3212d7ba3c7e8180b942dd3e50616ad6e557
2 parents cef2efa + ed1bbce commit d0ca394

File tree

3 files changed

+129
-0
lines changed

3 files changed

+129
-0
lines changed

Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,10 +353,12 @@ clean-local: clean-docs
353353
test-security-check:
354354
if TARGET_DARWIN
355355
$(AM_V_at) $(PYTHON) $(top_srcdir)/contrib/devtools/test-security-check.py TestSecurityChecks.test_MACHO
356+
$(AM_V_at) $(PYTHON) $(top_srcdir)/contrib/devtools/test-symbol-check.py TestSymbolChecks.test_MACHO
356357
endif
357358
if TARGET_WINDOWS
358359
$(AM_V_at) $(PYTHON) $(top_srcdir)/contrib/devtools/test-security-check.py TestSecurityChecks.test_PE
359360
endif
360361
if TARGET_LINUX
361362
$(AM_V_at) $(PYTHON) $(top_srcdir)/contrib/devtools/test-security-check.py TestSecurityChecks.test_ELF
363+
$(AM_V_at) $(PYTHON) $(top_srcdir)/contrib/devtools/test-symbol-check.py TestSymbolChecks.test_ELF
362364
endif

configure.ac

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1698,7 +1698,9 @@ AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile share/setup.nsi share/qt
16981698
AC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/split-debug.sh])
16991699
AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([doc/Doxyfile])])
17001700
AC_CONFIG_LINKS([contrib/devtools/security-check.py:contrib/devtools/security-check.py])
1701+
AC_CONFIG_LINKS([contrib/devtools/symbol-check.py:contrib/devtools/symbol-check.py])
17011702
AC_CONFIG_LINKS([contrib/devtools/test-security-check.py:contrib/devtools/test-security-check.py])
1703+
AC_CONFIG_LINKS([contrib/devtools/test-symbol-check.py:contrib/devtools/test-symbol-check.py])
17021704
AC_CONFIG_LINKS([contrib/filter-lcov.py:contrib/filter-lcov.py])
17031705
AC_CONFIG_LINKS([test/functional/test_runner.py:test/functional/test_runner.py])
17041706
AC_CONFIG_LINKS([test/fuzz/test_runner.py:test/fuzz/test_runner.py])

contrib/devtools/test-symbol-check.py

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2020 The Bitcoin Core developers
3+
# Distributed under the MIT software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
'''
6+
Test script for symbol-check.py
7+
'''
8+
import subprocess
9+
import unittest
10+
11+
def call_symbol_check(cc, source, executable, options):
12+
subprocess.run([cc,source,'-o',executable] + options, check=True)
13+
p = subprocess.run(['./contrib/devtools/symbol-check.py',executable], stdout=subprocess.PIPE, universal_newlines=True)
14+
return (p.returncode, p.stdout.rstrip())
15+
16+
def get_machine(cc):
17+
p = subprocess.run([cc,'-dumpmachine'], stdout=subprocess.PIPE, universal_newlines=True)
18+
return p.stdout.rstrip()
19+
20+
class TestSymbolChecks(unittest.TestCase):
21+
def test_ELF(self):
22+
source = 'test1.c'
23+
executable = 'test1'
24+
cc = 'gcc'
25+
26+
# there's no way to do this test for RISC-V at the moment; bionic's libc is 2.27
27+
# and we allow all symbols from 2.27.
28+
if 'riscv' in get_machine(cc):
29+
self.skipTest("test not available for RISC-V")
30+
31+
# memfd_create was introduced in GLIBC 2.27, so is newer than the upper limit of
32+
# all but RISC-V but still available on bionic
33+
with open(source, 'w', encoding="utf8") as f:
34+
f.write('''
35+
#define _GNU_SOURCE
36+
#include <sys/mman.h>
37+
38+
int memfd_create(const char *name, unsigned int flags);
39+
40+
int main()
41+
{
42+
memfd_create("test", 0);
43+
return 0;
44+
}
45+
''')
46+
47+
self.assertEqual(call_symbol_check(cc, source, executable, []),
48+
(1, executable + ': symbol memfd_create from unsupported version GLIBC_2.27\n' +
49+
executable + ': failed IMPORTED_SYMBOLS'))
50+
51+
# -lutil is part of the libc6 package so a safe bet that it's installed
52+
# it's also out of context enough that it's unlikely to ever become a real dependency
53+
source = 'test2.c'
54+
executable = 'test2'
55+
with open(source, 'w', encoding="utf8") as f:
56+
f.write('''
57+
#include <utmp.h>
58+
59+
int main()
60+
{
61+
login(0);
62+
return 0;
63+
}
64+
''')
65+
66+
self.assertEqual(call_symbol_check(cc, source, executable, ['-lutil']),
67+
(1, executable + ': NEEDED library libutil.so.1 is not allowed\n' +
68+
executable + ': failed LIBRARY_DEPENDENCIES'))
69+
70+
# finally, check a conforming file that simply uses a math function
71+
source = 'test3.c'
72+
executable = 'test3'
73+
with open(source, 'w', encoding="utf8") as f:
74+
f.write('''
75+
#include <math.h>
76+
77+
int main()
78+
{
79+
return (int)pow(2.0, 4.0);
80+
}
81+
''')
82+
83+
self.assertEqual(call_symbol_check(cc, source, executable, ['-lm']),
84+
(0, ''))
85+
86+
def test_MACHO(self):
87+
source = 'test1.c'
88+
executable = 'test1'
89+
cc = 'clang'
90+
91+
with open(source, 'w', encoding="utf8") as f:
92+
f.write('''
93+
#include <expat.h>
94+
95+
int main()
96+
{
97+
XML_ExpatVersion();
98+
return 0;
99+
}
100+
101+
''')
102+
103+
self.assertEqual(call_symbol_check(cc, source, executable, ['-lexpat']),
104+
(1, 'libexpat.1.dylib is not in ALLOWED_LIBRARIES!\n' +
105+
executable + ': failed DYNAMIC_LIBRARIES'))
106+
107+
source = 'test2.c'
108+
executable = 'test2'
109+
with open(source, 'w', encoding="utf8") as f:
110+
f.write('''
111+
#include <CoreGraphics/CoreGraphics.h>
112+
113+
int main()
114+
{
115+
CGMainDisplayID();
116+
return 0;
117+
}
118+
''')
119+
120+
self.assertEqual(call_symbol_check(cc, source, executable, ['-framework', 'CoreGraphics']),
121+
(0, ''))
122+
123+
if __name__ == '__main__':
124+
unittest.main()
125+

0 commit comments

Comments
 (0)