Skip to content

Commit 5bab08d

Browse files
committed
contrib: Add test for ELF symbol-check
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.
1 parent 0918eb4 commit 5bab08d

File tree

3 files changed

+91
-0
lines changed

3 files changed

+91
-0
lines changed

Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,4 +359,5 @@ if TARGET_WINDOWS
359359
endif
360360
if TARGET_LINUX
361361
$(AM_V_at) $(PYTHON) $(top_srcdir)/contrib/devtools/test-security-check.py TestSecurityChecks.test_ELF
362+
$(AM_V_at) $(PYTHON) $(top_srcdir)/contrib/devtools/test-symbol-check.py TestSymbolChecks.test_ELF
362363
endif

configure.ac

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1695,7 +1695,9 @@ AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile share/setup.nsi share/qt
16951695
AC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/split-debug.sh])
16961696
AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([doc/Doxyfile])])
16971697
AC_CONFIG_LINKS([contrib/devtools/security-check.py:contrib/devtools/security-check.py])
1698+
AC_CONFIG_LINKS([contrib/devtools/symbol-check.py:contrib/devtools/symbol-check.py])
16981699
AC_CONFIG_LINKS([contrib/devtools/test-security-check.py:contrib/devtools/test-security-check.py])
1700+
AC_CONFIG_LINKS([contrib/devtools/test-symbol-check.py:contrib/devtools/test-symbol-check.py])
16991701
AC_CONFIG_LINKS([contrib/filter-lcov.py:contrib/filter-lcov.py])
17001702
AC_CONFIG_LINKS([test/functional/test_runner.py:test/functional/test_runner.py])
17011703
AC_CONFIG_LINKS([test/fuzz/test_runner.py:test/fuzz/test_runner.py])

contrib/devtools/test-symbol-check.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
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+
if __name__ == '__main__':
87+
unittest.main()
88+

0 commit comments

Comments
 (0)