#!/usr/bin/env python # # migrate-pax: this file is part of the elfix package # Copyright (C) 2012 Anthony G. Basile # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # We use portage's NEEDED.ELF.2 file. The format is in # /usr/lib/portage/bin/misc-functions.sh ~line 520 # echo "${arch:3};${obj};${soname};${rpath};${needed}" \ # >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED.ELF.2 import os import re import getopt import sys import pax import portage def get_objects(): vardb = portage.db[portage.root]["vartree"].dbapi objects = [] for pkg in vardb.cpv_all(): needed = vardb.aux_get(pkg, ['NEEDED.ELF.2'])[0].strip() if not needed: # Some packages have no NEEDED.ELF.2 continue for line in re.split('\n', needed): link = re.split(';', line) objects.append(link[1]) # link[1] is the ELF object return objects def run_usage(): print('Package Name : elfix') print('Bug Reports : http://bugs.gentoo.org/') print('Program Name : migrate') print('Description : Migrate PT_PAX to XATTR_PAX Flags on all system ELF objects') print('') print('Usage : migrate -v print out all system ELF objects') print(' : migrate -m [-v] migrate flags on all system ELF objects') print(' : migrate -d [-v] delete XATTR_PAX on all system ELF objects') print(' : migrate [-h] print out this help') print(' : -v be verbose when migrating') print('') def main(): # Are we root? uid = os.getuid() if uid != 0: print('This program must be run as root') sys.exit(1) try: opts, args = getopt.getopt(sys.argv[1:], 'vmdh') except getopt.GetoptError as err: print(str(err)) # will print something like 'option -a not recognized' run_usage() sys.exit(1) verbose = False do_migration = False do_deleteall = False do_usage = False opt_count = 0 for o, a in opts: if o == '-v': verbose = True opt_count += 1 elif o == '-m': do_migration = True opt_count += 1 elif o == '-d': do_deleteall = True opt_count += 1 elif o == '-h': do_usage = True opt_count += 1 else: print('Option included in getopt but not handled here!') print('Please file a bug') sys.exit(1) if do_usage: run_usage() sys.exit(0) if opt_count == 0 or opt_count > 2 or (do_migration and do_deleteall): run_usage() sys.exit(1) # Do we have XATTR_PAX support? if do_migration or do_deleteall: try: from pax import deletextpax except ImportError: print('ERROR: Python module pax.so was compiled without XATTR_PAX support, ' 'cannot migrate or delete XATTR_PAX') sys.exit(1) objects = get_objects() fail = [] none = [] for elf in objects: try: flags = pax.getflags(elf)[0] if flags: if verbose: print("%s %s" % (flags, elf)) else: none.append(elf) if verbose: print("NONE: %s" % elf) if do_migration: flags = re.sub('-', '', flags) if flags == 'e': continue # Don't create XATTR_PAX for default pax.setstrflags(elf, flags) if do_deleteall: pax.deletextpax(elf) # We should never get here, because you can # always getflags() via pax.so since you can # read PT_PAX even from a busy text file, and # you can always set the pax flags with pax.so # even on a busy text file because it will skip # setting PT_PAX and only set the XATTR_PAX except pax.PaxError: if uid == 0: fail.append(elf) if verbose: print("FAIL: %s" % elf) if verbose: if fail: print('\n') print("ELF executables for which the migration failed:") for elf in fail: print("\t%s" % elf) if none: print('\n') print("ELF executables lacking PT_PAX:") for elf in none: print("\t%s" % elf) if __name__ == '__main__': main()