Blame scripts/check-wx-segment.py

Packit Service bc47e4
#!/usr/bin/python3
Packit Service bc47e4
# Check ELF program headers for WX segments.
Packit Service bc47e4
# Copyright (C) 2020 Free Software Foundation, Inc.
Packit Service bc47e4
# This file is part of the GNU C Library.
Packit Service bc47e4
#
Packit Service bc47e4
# The GNU C Library is free software; you can redistribute it and/or
Packit Service bc47e4
# modify it under the terms of the GNU Lesser General Public
Packit Service bc47e4
# License as published by the Free Software Foundation; either
Packit Service bc47e4
# version 2.1 of the License, or (at your option) any later version.
Packit Service bc47e4
#
Packit Service bc47e4
# The GNU C Library is distributed in the hope that it will be useful,
Packit Service bc47e4
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service bc47e4
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service bc47e4
# Lesser General Public License for more details.
Packit Service bc47e4
#
Packit Service bc47e4
# You should have received a copy of the GNU Lesser General Public
Packit Service bc47e4
# License along with the GNU C Library; if not, see
Packit Service bc47e4
# <https://www.gnu.org/licenses/>.
Packit Service bc47e4
Packit Service bc47e4
"""Check that the program headers do not contain write-exec segments."""
Packit Service bc47e4
Packit Service bc47e4
import argparse
Packit Service bc47e4
import os.path
Packit Service bc47e4
import re
Packit Service bc47e4
import sys
Packit Service bc47e4
Packit Service bc47e4
# Regular expression to extract the RWE flags field.  The
Packit Service bc47e4
# address/offset columns have varying width.
Packit Service bc47e4
RE_LOAD = re.compile(
Packit Service bc47e4
    r'^  LOAD +(?:0x[0-9a-fA-F]+ +){5}([R ][W ][ E]) +0x[0-9a-fA-F]+\n\Z')
Packit Service bc47e4
Packit Service bc47e4
def process_file(path, inp, xfail):
Packit Service bc47e4
    """Analyze one input file."""
Packit Service bc47e4
Packit Service bc47e4
    errors = 0
Packit Service bc47e4
    for line in inp:
Packit Service bc47e4
        error = None
Packit Service bc47e4
        if line.startswith('  LOAD '):
Packit Service bc47e4
            match = RE_LOAD.match(line)
Packit Service bc47e4
            if match is None:
Packit Service bc47e4
                error = 'Invalid LOAD line'
Packit Service bc47e4
            else:
Packit Service bc47e4
                flags, = match.groups()
Packit Service bc47e4
                if 'W' in flags and 'E' in flags:
Packit Service bc47e4
                    if xfail:
Packit Service bc47e4
                        print('{}: warning: WX segment (as expected)'.format(
Packit Service bc47e4
                            path))
Packit Service bc47e4
                    else:
Packit Service bc47e4
                        error = 'WX segment'
Packit Service bc47e4
Packit Service bc47e4
        if error is not None:
Packit Service bc47e4
            print('{}: error: {}: {!r}'.format(path, error, line.strip()))
Packit Service bc47e4
            errors += 1
Packit Service bc47e4
Packit Service bc47e4
    if xfail and errors == 0:
Packit Service bc47e4
        print('{}: warning: missing expected WX segment'.format(path))
Packit Service bc47e4
    return errors
Packit Service bc47e4
Packit Service bc47e4
Packit Service bc47e4
def main():
Packit Service bc47e4
    """The main entry point."""
Packit Service bc47e4
    parser = argparse.ArgumentParser(description=__doc__)
Packit Service bc47e4
    parser.add_argument('--xfail',
Packit Service bc47e4
                        help='Mark input files as XFAILed ("*" for all)',
Packit Service bc47e4
                        type=str, default='')
Packit Service bc47e4
    parser.add_argument('phdrs',
Packit Service bc47e4
                        help='Files containing readelf -Wl output',
Packit Service bc47e4
                        nargs='*')
Packit Service bc47e4
    opts = parser.parse_args(sys.argv)
Packit Service bc47e4
Packit Service bc47e4
    xfails = set(opts.xfail.split(' '))
Packit Service bc47e4
    xfails_all = opts.xfail.strip() == '*'
Packit Service bc47e4
Packit Service bc47e4
    errors = 0
Packit Service bc47e4
    for path in opts.phdrs:
Packit Service bc47e4
        xfail = ((os.path.basename(path) + '.phdrs') in xfails
Packit Service bc47e4
                 or xfails_all)
Packit Service bc47e4
        with open(path) as inp:
Packit Service bc47e4
            errors += process_file(path, inp, xfail)
Packit Service bc47e4
    if errors > 0:
Packit Service bc47e4
        sys.exit(1)
Packit Service bc47e4
Packit Service bc47e4
Packit Service bc47e4
if __name__ == '__main__':
Packit Service bc47e4
    main()