Blame scripts/check-wx-segment.py

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