Blame scripts/check-wx-segment.py

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