Blame scripts/check-wx-segment.py

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