aboutsummaryrefslogtreecommitdiff
path: root/scripts/check-wx-segment.py
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2020-03-02 14:24:27 +0100
committerFlorian Weimer <fweimer@redhat.com>2020-03-02 14:25:20 +0100
commit0499a353a6e196f468e7ec554cb13c82011f0e36 (patch)
tree581108932370bf01836d379db99bafc4330e3cf7 /scripts/check-wx-segment.py
parentb5b7fb76e15c0db545aa11a3ce88f836e5d01a19 (diff)
downloadglibc-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.py85
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()