(root)/
glibc-2.38/
scripts/
check-wx-segment.py
       1  #!/usr/bin/python3
       2  # Check ELF program headers for WX segments.
       3  # Copyright (C) 2020-2023 Free Software Foundation, Inc.
       4  # This file is part of the GNU C Library.
       5  #
       6  # The GNU C Library is free software; you can redistribute it and/or
       7  # modify it under the terms of the GNU Lesser General Public
       8  # License as published by the Free Software Foundation; either
       9  # version 2.1 of the License, or (at your option) any later version.
      10  #
      11  # The GNU C Library is distributed in the hope that it will be useful,
      12  # but WITHOUT ANY WARRANTY; without even the implied warranty of
      13  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14  # Lesser General Public License for more details.
      15  #
      16  # You should have received a copy of the GNU Lesser General Public
      17  # License along with the GNU C Library; if not, see
      18  # <https://www.gnu.org/licenses/>.
      19  
      20  """Check that the program headers do not contain write-exec segments."""
      21  
      22  import argparse
      23  import os.path
      24  import re
      25  import sys
      26  
      27  # Regular expression to extract the RWE flags field.  The
      28  # address/offset columns have varying width.
      29  RE_LOAD = re.compile(
      30      r'^  LOAD +(?:0x[0-9a-fA-F]+ +){5}([R ][W ][ E]) +0x[0-9a-fA-F]+\n\Z')
      31  
      32  def process_file(path, inp, xfail):
      33      """Analyze one input file."""
      34  
      35      errors = 0
      36      for line in inp:
      37          error = None
      38          if line.startswith('  LOAD '):
      39              match = RE_LOAD.match(line)
      40              if match is None:
      41                  error = 'Invalid LOAD line'
      42              else:
      43                  flags, = match.groups()
      44                  if 'W' in flags and 'E' in flags:
      45                      if xfail:
      46                          print('{}: warning: WX segment (as expected)'.format(
      47                              path))
      48                      else:
      49                          error = 'WX segment'
      50  
      51          if error is not None:
      52              print('{}: error: {}: {!r}'.format(path, error, line.strip()))
      53              errors += 1
      54  
      55      if xfail and errors == 0:
      56          print('{}: warning: missing expected WX segment'.format(path))
      57      return errors
      58  
      59  
      60  def main():
      61      """The main entry point."""
      62      parser = argparse.ArgumentParser(description=__doc__)
      63      parser.add_argument('--xfail',
      64                          help='Mark input files as XFAILed ("*" for all)',
      65                          type=str, default='')
      66      parser.add_argument('phdrs',
      67                          help='Files containing readelf -Wl output',
      68                          nargs='*')
      69      opts = parser.parse_args(sys.argv)
      70  
      71      xfails = set(opts.xfail.split(' '))
      72      xfails_all = opts.xfail.strip() == '*'
      73  
      74      errors = 0
      75      for path in opts.phdrs:
      76          xfail = ((os.path.basename(path) + '.phdrs') in xfails
      77                   or xfails_all)
      78          with open(path) as inp:
      79              errors += process_file(path, inp, xfail)
      80      if errors > 0:
      81          sys.exit(1)
      82  
      83  
      84  if __name__ == '__main__':
      85      main()