diff options
author | Florian Weimer <fweimer@redhat.com> | 2020-03-02 14:24:27 +0100 |
---|---|---|
committer | Florian Weimer <fweimer@redhat.com> | 2020-03-02 14:25:20 +0100 |
commit | 0499a353a6e196f468e7ec554cb13c82011f0e36 (patch) | |
tree | 581108932370bf01836d379db99bafc4330e3cf7 /scripts/check-wx-segment.py | |
parent | b5b7fb76e15c0db545aa11a3ce88f836e5d01a19 (diff) | |
download | glibc-0499a353a6e196f468e7ec554cb13c82011f0e36.zip glibc-0499a353a6e196f468e7ec554cb13c82011f0e36.tar.gz glibc-0499a353a6e196f468e7ec554cb13c82011f0e36.tar.bz2 |
elf: Add elf/check-wx-segment, a test for the presence of WX segments
Writable, executable segments defeat security hardening. The
existing check for DT_TEXTREL does not catch this.
hppa and SPARC currently keep the PLT in an RWX load segment.
Diffstat (limited to 'scripts/check-wx-segment.py')
-rw-r--r-- | scripts/check-wx-segment.py | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/scripts/check-wx-segment.py b/scripts/check-wx-segment.py new file mode 100644 index 0000000..e1fa793 --- /dev/null +++ b/scripts/check-wx-segment.py @@ -0,0 +1,85 @@ +#!/usr/bin/python3 +# Check ELF program headers for WX segments. +# Copyright (C) 2020 Free Software Foundation, Inc. +# This file is part of the GNU C Library. +# +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# <https://www.gnu.org/licenses/>. + +"""Check that the program headers do not contain write-exec segments.""" + +import argparse +import os.path +import re +import sys + +# Regular expression to extract the RWE flags field. The +# address/offset columns have varying width. +RE_LOAD = re.compile( + r'^ LOAD +(?:0x[0-9a-fA-F]+ +){5}([R ][W ][ E]) +0x[0-9a-fA-F]+\n\Z') + +def process_file(path, inp, xfail): + """Analyze one input file.""" + + errors = 0 + for line in inp: + error = None + if line.startswith(' LOAD '): + match = RE_LOAD.match(line) + if match is None: + error = 'Invalid LOAD line' + else: + flags, = match.groups() + if 'W' in flags and 'E' in flags: + if xfail: + print('{}: warning: WX segment (as expected)'.format( + path)) + else: + error = 'WX segment' + + if error is not None: + print('{}: error: {}: {!r}'.format(path, error, line.strip())) + errors += 1 + + if xfail and errors == 0: + print('{}: warning: missing expected WX segment'.format(path)) + return errors + + +def main(): + """The main entry point.""" + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--xfail', + help='Mark input files as XFAILed ("*" for all)', + type=str, default='') + parser.add_argument('phdrs', + help='Files containing readelf -Wl output', + nargs='*') + opts = parser.parse_args(sys.argv) + + xfails = set(opts.xfail.split(' ')) + xfails_all = opts.xfail.strip() == '*' + + errors = 0 + for path in opts.phdrs: + xfail = ((os.path.basename(path) + '.phdrs') in xfails + or xfails_all) + with open(path) as inp: + errors += process_file(path, inp, xfail) + if errors > 0: + sys.exit(1) + + +if __name__ == '__main__': + main() |