Blame scripts/check-wx-segment.py

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