public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
From: "Anthony G. Basile" <blueness@gentoo.org>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/elfix:master commit in: misc/
Date: Sun, 23 Dec 2012 02:36:08 +0000 (UTC)	[thread overview]
Message-ID: <1356230114.e14bb283546820ed3bb5174a058af2a30750f97f.blueness@gentoo> (raw)

commit:     e14bb283546820ed3bb5174a058af2a30750f97f
Author:     Anthony G. Basile <blueness <AT> gentoo <DOT> org>
AuthorDate: Sun Dec 23 01:02:47 2012 +0000
Commit:     Anthony G. Basile <blueness <AT> gentoo <DOT> org>
CommitDate: Sun Dec 23 02:35:14 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/elfix.git;a=commit;h=e14bb283

misc/alt-revdep-pax: add old revdep-pax, add printing forward linkings

---
 misc/alt-revdep-pax                |  503 +++++++++++++++++++++++++++++++-----
 misc/{alt-revdep-pax => link_maps} |    0
 2 files changed, 440 insertions(+), 63 deletions(-)

diff --git a/misc/alt-revdep-pax b/misc/alt-revdep-pax
index a6adacd..6c0c7ba 100755
--- a/misc/alt-revdep-pax
+++ b/misc/alt-revdep-pax
@@ -1,4 +1,21 @@
 #!/usr/bin/env python
+#
+#	alt-revdep-pax: this file is part of the elfix package
+#	Copyright (C) 2011  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 <http://www.gnu.org/licenses/>.
+#
 
 #
 # Note: This alternative way of doing revdep-pax only
@@ -9,12 +26,21 @@
 # echo "${arch:3};${obj};${soname};${rpath};${needed}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED.ELF.2
 #
 
+import getopt
 import os
 import sys
 import re
 import pax
 
 
+""" python2/3 compat input """
+def get_input(prompt):
+	if sys.hexversion > 0x03000000:
+		return input(prompt)
+	else:
+		return raw_input(prompt)
+
+
 """
 Return object_needed dictionary which has structure
 
@@ -132,6 +158,14 @@ def get_soname_linkings( soname_needed, soname2library ):
 	return
 
 
+def get_object_linkings():
+	object_needed = get_object_needed()
+	( library2soname, soname2library ) = get_libraries()
+	soname_needed = get_soname_needed( object_needed, library2soname )
+	get_soname_linkings( soname_needed, soname2library )
+	return ( object_needed, soname2library )
+
+
 def get_object_reverse_linkings( object_linkings ):
 	object_reverse_linkings = {}
 
@@ -142,83 +176,426 @@ def get_object_reverse_linkings( object_linkings ):
 	return object_reverse_linkings
 
 
-def main():
+#XXXXXXXXXXXXXXXX
+def invert_linkings( forward_linkings ):
+	reverse_linkings = {}
+	return reverse_linkings 
+#XXXXXXXXXXXXXXXX
 
-	# Run as root to be able to real all files
-	uid = os.getuid()
-	if uid != 0:
-		print('RUN AS ROOT: cannot read all flags')
-		sys.exit(0)
 
-	object_needed = get_object_needed()
-	( library2soname, soname2library ) = get_libraries()
-	soname_needed = get_soname_needed( object_needed, library2soname )
+def print_object_linkings( object_linkings, soname2library, verbose ):
 
-	# After the appending to needed in get_soname_linkings(), forward_needed
-	# and soname_needed have been extended through the entire chain of linking.
-	# If we want to keep only the object_needed and soname_needed, then do
-	# a copy before calling get_soname_linkings().
-	get_soname_linkings( soname_needed, soname2library )
+	elfs_without_flags = []
+	sonames_without_flags = []
+	sonames_missing_library = []
+
+	for elf in object_linkings:
+		try:
+			( elf_str_flags, elf_bin_flags ) = pax.getflags(elf)
+			sv = '%s ( %s )\n' % ( elf, elf_str_flags )
+			s = sv
+		except pax.PaxError:
+			elf_without_flags.append(elf)
+			continue
+
+		count = 0
+		for soname in object_linkings[elf]:
+			try:
+				library = soname2library[soname]
+				( library_str_flags, library_bin_flags ) = pax.getflags(library)
+				sv = '%s\n\t%s\t%s ( %s )' % ( sv, soname, library, library_str_flags )
+				if elf_str_flags != library_str_flags:
+					s = '%s\n\t%s\t%s ( %s )' % ( s, soname, library, library_str_flags )
+					count = count + 1
+			except KeyError:
+				sonames_missing_library.append(soname)
+			except pax.PaxError:
+				sonames_without_flags.append(soname)
+				
+
+		if verbose:
+			print('%s\n' % sv)
+			if count == 0:
+				print('\tNo mismatches\n\n')
+			else:
+				print('\tMismatches\n\n')
+		else:
+			if count != 0:
+				print('%s\n\n' % s)
 
-	object_linkings = object_needed
-	object_needed = None
+	elfs_without_flags = set(elfs_without_flags)
+	print('\n**** ELF objections without any PAX flags ****')
+	for m in elfs_without_flags:
+		print('\t%s' % m)
 
-	soname_linkings = soname_needed
-	soname_needed = None
+	sonames_without_flags = set(sonames_without_flags)
+	print('\n**** SONAMEs with library files without PAX flags ****')
+	for m in sonames_without_flags:
+		print('\t%s' % m)
 
-	object_reverse_linkings = get_object_reverse_linkings( object_linkings )
+	sonames_missing_library = set(sonames_missing_library)
+	print('\n**** SONAMES without any library files ****')
+	for m in sonames_missing_library:
+		print('\t%s' % m)
 
-	""" Print out all ELF objects and their PaX flags
-	for elf in object_needed:
+
+def run_forward(verbose):
+	( object_linkings, soname2library ) = get_object_linkings()
+	print_object_linkings( object_linkings, soname2library, verbose)
+
+
+def print_reverse_linkings( reverse_linkings, so2library_mappings, verbose, executable_only ):
+	shell_path = path = os.getenv('PATH').split(':')
+	missing_sonames = []
+	missing_links = []
+
+	for soname in reverse_linkings:
 		try:
-			flags = pax.getflags(elf)[0]
-			if flags:
-				print("%s %s" % (flags, elf))
+			library = so2library_mappings[soname]
+			( library_str_flags, library_bin_flags ) = pax.getflags(library)
+			sv = '%s\t%s ( %s )\n' % ( soname, library, library_str_flags )
+			s = sv
+		except pax.PaxError:
+			missing_sonames.append(soname)
+			continue
+
+		count = 0
+		for binary in reverse_linkings[soname]:
+			try:
+				( binary_str_flags, binary_bin_flags ) = pax.getflags(binary)
+				if executable_only:
+					if os.path.dirname(binary) in shell_path:	
+						sv = '%s\n\t%s ( %s )' % ( sv, binary, binary_str_flags )
+						if library_str_flags != binary_str_flags:
+							s = '%s\n\t%s ( %s )' % ( s, binary, binary_str_flags )
+							count = count + 1
+				else:
+					sv = '%s\n\t%s ( %s )' % ( sv, binary, binary_str_flags )
+					if library_str_flags != binary_str_flags:
+						s = '%s\n\t%s ( %s )' % ( s, binary, binary_str_flags )
+						count = count + 1
+			except pax.PaxError:
+				missing_links.append(binary)
+
+		if verbose:
+			print('%s\n' % sv)
+			if count == 0:
+				print('\tNo mismatches\n\n')
 			else:
-				print("NONE: %s" % elf)
-		except pax.error:
-			print("CANT: %s" % elf)
+				print('\tMismatches\n\n')
+		else:
+			if count != 0:
+				print('%s\n\n' % s)
+
+	missing_sonames = set(missing_sonames)
+	print('\n**** Missing sonames ****\n')
+	for m in missing_sonames:
+		print('\t%s\n' % m)
+
+	missing_links = set(missing_links)
+	print('\n**** Missing reverse linkings ****\n')
+	for m in missing_links:
+		print('\t%s\n' % m)
+
+
+def run_reverse(verbose, executable_only):
+	( forward_linkings, so2library_mappings ) = get_object_linkings()
+	reverse_linkings = invert_linkings( forward_linkings )
+	print_reverse_linkings( reverse_linkings, so2library_mappings, verbose, executable_only)
+
+
+def migrate_flags(importer, exporter_str_flags, exporter_bin_flags):
+	# We implement the following logic for setting the pax flags
+	# on the target elf object, the IMPORTER, given that the flags
+	# from the elf object we want it to match to, the EXPORTER.
+	#
+	#	EXPORTER	IMPORTER	RESULT
+	#	   On		   On		   On
+	#	   On		   Off		   On + Warn
+	#	   On		   -		   On
+	#	   Off		   On		   On + Warn
+	#	   Off		   Off		   Off
+	#	   Off		   -		   Off
+	#	   -		   On		   On
+	#	   -		   Off		   Off
+	#	   -		   -		   -
+
+	#See /usr/include/elf.h for these values
+	pf_flags = {
+		'P':1<<4, 'p':1<<5,
+		'S':1<<6, 's':1<<7,
+		'M':1<<8, 'm':1<<9,
+		'X':1<<10, 'x':1<<11,
+		'E':1<<12, 'e':1<<13,
+		'R':1<<14, 'r':1<<15
+	}
+
+	( importer_str_flags, importer_bin_flags ) = pax.getflags(importer)
+
+	# Start with the exporter's flags
+	result_bin_flags = exporter_bin_flags
+
+	for i in range(len(importer_str_flags)):
+
+		# The exporter's flag contradicts the importer's flag, so do nothing
+		if (exporter_str_flags[i].isupper() and importer_str_flags[i].islower()) or \
+		   (exporter_str_flags[i].islower() and importer_str_flags[i].isupper()):
+
+			# Revert the exporter's flag, use the importer's flag and warn
+			result_bin_flags = result_bin_flags ^ pf_flags[exporter_str_flags[i]]
+			result_bin_flags = result_bin_flags | pf_flags[importer_str_flags[i]]
+			print('\t\tWarning: %s has %s, refusing to set to %s' % (
+				importer, importer_str_flags[i], exporter_str_flags[i] )),
+
+		# The exporter's flags is off, so use the importer's flag
+		if (exporter_str_flags[i] == '-' and importer_str_flags[i] != '-'):
+			result_bin_flags = result_bin_flags | pf_flags[importer_str_flags[i]]
+
+	pax.setbinflags(importer, result_bin_flags)
+
+
+def run_binary(binary, verbose, mark, allyes):
+	if not os.path.exists(binary):
+		print('%s\tNo such OBJECT' % binary)
+		return
+	( linkings, mappings ) = get_ldd_linkings(binary)
+	( binary_str_flags, binary_bin_flags ) = pax.getflags(binary)
+	print('%s (%s)\n' % ( binary, binary_str_flags ))
+
+	mismatched_libraries = []
+
+	for soname in linkings:
+		try:
+			library = mappings[soname]
+			( library_str_flags, library_bin_flags ) = pax.getflags(library)
+			if verbose:
+				print('\t%s\t%s ( %s )' % ( soname, library, library_str_flags ))
+			if binary_str_flags != library_str_flags:
+				mismatched_libraries.append(library)
+				if not verbose:
+					print('\t%s\t%s ( %s )' % ( soname, library, library_str_flags ))
+		except pax.PaxError:
+			print('file for soname %s not found' % soname)
+
+	if len(mismatched_libraries) == 0:
+		if not verbose:
+			print('\tNo mismatches\n')
+	else:
+		print('\n'),
+		if mark:
+			print('\tWill mark libraries with %s\n' % binary_str_flags)
+			for library in mismatched_libraries:
+				do_marking = False
+				while True:
+					if allyes:
+						ans = 'y'
+					else:
+						ans = get_input('\tSet flags for %s (y/n): ' % library)
+					if ans == 'y':
+						do_marking = True
+						break
+					elif ans == 'n':
+						do_marking = False
+						break
+					else:
+						print('\t\tPlease enter y or n')
+
+				if do_marking:
+					try:
+						migrate_flags(library, binary_str_flags, binary_bin_flags)
+					except pax.PaxError:
+						print("\n\tCould not set pax flags on %s, file is probably busy" % library)
+						print("\tShut down all processes that use it and try again")
+					( library_str_flags, library_bin_flags ) = pax.getflags(library)
+					print('\n\t\t%s ( %s )\n' % ( library, library_str_flags ))
+
+
+def invert_so2library_mappings( so2library_mappings ):
+	library2soname_mappings = {}
+	for soname, library in so2library_mappings.items():
+		library2soname_mappings[library] = soname
+	return library2soname_mappings
+
+#XXXXXXXXXXXXXXXXX
+
+def run_soname(name, verbose, use_soname, mark, allyes, executable_only):
+	shell_path = path = os.getenv('PATH').split(':')
+
+	( forward_linkings, so2library_mappings ) = get_object_linkings()
+	reverse_linkings = invert_linkings( forward_linkings )
+
+	if use_soname:
+		soname = name
+	else:
+		library2soname_mappings = invert_so2library_mappings(so2library_mappings)
+		try:
+			soname = library2soname_mappings[name]
+		except KeyError:
+			print('%s\tNo such LIBRARY' % name)
+			return
 
-	"""
+	try:
+		linkings = reverse_linkings[soname]
+	except KeyError:
+		print('%s\tNo such SONAME' % soname)
+		return
 
-	""" Print out all sonames and their library paths
-	for soname in sorted(soname2library):
-		elf = soname2library[soname]
-		print("%s : %s" % ( soname, elf ))
-	"""
+	library = so2library_mappings[soname]
 
+	( library_str_flags, library_bin_flags ) = pax.getflags(library)
+	print('%s\t%s (%s)\n' % ( soname, library, library_str_flags ))
 
-	""" Print out all ELF objects and the NEEDED sonames and full library paths
-	for elf in object_needed:
-		sonames = object_needed[elf]
-		print("%s" % elf)
-		for soname in sorted(object_needed[elf]):
-			try:
-				print("\t%s\t=> %s" % (soname, soname2library[soname]))
-			except KeyError:
-				print("\t%s\t=> ****" % soname)
-		print("\n\n")
-	"""
+	mismatched_binaries = []
+	for binary in linkings:
+		try:
+			( binary_str_flags, binary_bin_flags ) = pax.getflags(binary)
+			if verbose:
+				if executable_only:
+					if os.path.dirname(binary) in shell_path:	
+						print('\t%s ( %s )' % ( binary, binary_str_flags ))
+				else:
+					print('\t%s ( %s )' % ( binary, binary_str_flags ))
+			if library_str_flags != binary_str_flags:
+				if executable_only:
+					if os.path.dirname(binary) in shell_path:	
+						mismatched_binaries.append(binary)
+						if not verbose:
+							print('\t%s ( %s )' % ( binary, binary_str_flags ))
+				else:
+					mismatched_binaries.append(binary)
+					if not verbose:
+						print('\t%s ( %s )' % ( binary, binary_str_flags ))
+		except pax.PaxError:
+			print('cannot obtain pax flags for %s' % binary)
+
+	if len(mismatched_binaries) == 0:
+		if not verbose:
+			print('\tNo mismatches\n')
+	else:
+		print('\n'),
+		if mark:
+			print('\tWill mark binaries with %s\n' % library_str_flags)
+			for binary in mismatched_binaries:
+				if executable_only:
+					if not os.path.dirname(binary) in shell_path:
+						continue
+				do_marking = False
+				while True:
+					if allyes:
+						ans = 'y'
+					else:
+						ans = get_input('\tSet flags for %s (y/n): ' % binary)
+					if ans == 'y':
+						do_marking = True
+						break
+					elif ans == 'n':
+						do_marking = False
+						break
+					else:
+						print('\t\tPlease enter y or n')
+				if do_marking:
+					try:
+						migrate_flags(binary, library_str_flags, library_bin_flags)
+					except pax.PaxError:
+						print('\n\tCould not set pax flags on %s, file is probably busy' % binary)
+						print('\tShut down all processes that use it and try again')
+					( binary_str_flags, binary_bin_flags ) = pax.getflags(binary)
+					print('\n\t\t%s ( %s )\n' % ( binary, binary_str_flags ))
+
+
+def run_usage():
+	print('Package Name : elfix')
+	print('Bug Reports  : http://bugs.gentoo.org/')
+	print('Program Name : revdep-pax')
+	print('Description  : Get or set pax flags on an ELF object')
+	print('')
+	print('Usage        : revdep-pax -f [-v]             print out all forward mappings for all system binaries')
+	print('             : revdep-pax -r [-ve]            print out all reverse mappings for all system sonames')
+	print('             : revdep-pax -b OBJECT  [-myv]   print all forward mappings only for OBJECT')
+	print('             : revdep-pax -s SONAME  [-myve]  print all reverse mappings only for SONAME')
+	print('             : revdep-pax -l LIBRARY [-myve]  print all reverse mappings only for LIBRARY file')
+	print('             : revdep-pax [-h]                print out this help')
+	print('             : -v                             verbose, otherwise just print mismatching objects')
+	print('             : -e                             only print out executables in shell $PATH')
+	print('             : -m                             don\'t just report, but mark the mismatching objects')
+	print('             : -y                             assume "yes" to all prompts for marking (USE CAREFULLY!)')
+	print('')
+
+
+def main():
+	try:
+		opts, args = getopt.getopt(sys.argv[1:], 'hfrb:s:l:vemy')
+	except getopt.GetoptError as err:
+		print(str(err)) # will print something like 'option -a not recognized'
+		run_usage()
+		sys.exit(1)
+
+	if len(opts) == 0:
+		run_usage()
+		sys.exit(1)
+
+	do_usage   = False
+	do_forward = False
+	do_reverse = False
+
+	binary = None
+	soname = None
+	library = None
+
+	verbose = False
+	executable_only = False
+	mark = False
+	allyes = False
+
+	opt_count = 0
+
+	for o, a in opts:
+		if o == '-h':
+			do_usage = True
+			opt_count += 1
+		elif o == '-f':
+			do_forward = True
+			opt_count += 1
+		elif o == '-r':
+			do_reverse = True
+			opt_count += 1
+		elif o == '-b':
+			binary = a
+			opt_count += 1
+		elif o == '-s':
+			soname = a
+			opt_count += 1
+		elif o == '-l':
+			library = a
+			opt_count += 1
+		elif o == '-v':
+			verbose = True
+		elif o == '-e':
+			executable_only = True
+		elif o == '-m':
+			mark = True
+		elif o == '-y':
+			allyes = True
+		else:
+			print('Option included in getopt but not handled here!')
+			print('Please file a bug')
+			sys.exit(1)
+
+	# Only allow one of -h, -f -r -b -s
+	if opt_count > 1 or do_usage:
+		run_usage()
+	elif do_forward:
+		run_forward(verbose)
+	elif do_reverse:
+		run_reverse(verbose, executable_only)
+	elif binary != None:
+		run_binary(binary, verbose, mark, allyes)
+	elif soname != None:
+		run_soname(soname, verbose, True, mark, allyes, executable_only)
+	elif library != None:
+		library = os.path.realpath(library)
+		run_soname(library, verbose, False, mark, allyes, executable_only)
 
-	""" Print out all the soname to soname NEEDED
-	for soname in soname_needed:
-		print("%s" % soname)
-		for s in soname_needed[soname]:
-			print("\t%s" % s )
-		print('')
-	"""
-
-
-	""" Print out all the soname to soname linkings
-	for soname in soname_linkings:
-		print("%s => %s" % (soname, soname2library[soname]))
-		for s in soname_linkings[soname]:
-			if s in soname2library:
-				print("\t%s => %s" % (s, soname2library[s]))
-			else:
-				print("\t%s => ****" %s )
-		print('')
-	"""
 
 if __name__ == '__main__':
 	main()

diff --git a/misc/alt-revdep-pax b/misc/link_maps
similarity index 100%
copy from misc/alt-revdep-pax
copy to misc/link_maps


             reply	other threads:[~2012-12-23  2:36 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-12-23  2:36 Anthony G. Basile [this message]
  -- strict thread matches above, loose matches on Subject: below --
2016-02-13 21:38 [gentoo-commits] proj/elfix:master commit in: misc/ Anthony G. Basile
2014-02-13 19:07 Anthony G. Basile
2013-05-21 15:21 Anthony G. Basile
2013-02-09 21:50 Anthony G. Basile
2012-12-27  3:11 Anthony G. Basile
2012-12-26 21:43 Anthony G. Basile
2012-12-26 21:23 Anthony G. Basile
2012-12-26  3:42 Anthony G. Basile
2012-12-25 14:22 Anthony G. Basile
2012-12-24 23:26 Anthony G. Basile
2012-12-24 21:44 Anthony G. Basile
2012-12-24 21:08 Anthony G. Basile
2012-12-24  2:18 Anthony G. Basile
2012-12-24  1:54 Anthony G. Basile
2012-12-23 11:51 Anthony G. Basile
2012-12-23  4:53 Anthony G. Basile
2012-12-23  3:49 Anthony G. Basile
2012-12-23  3:49 Anthony G. Basile
2012-12-23  3:49 Anthony G. Basile
2012-12-23  3:47 Anthony G. Basile
2012-12-23  2:36 Anthony G. Basile
2012-12-23  2:34 Anthony G. Basile
2012-12-23  1:02 Anthony G. Basile
2012-12-22 14:44 Anthony G. Basile
2012-12-22  4:21 Anthony G. Basile
2012-12-22  3:58 Anthony G. Basile
2012-12-22  1:06 Anthony G. Basile
2012-12-19  3:52 Anthony G. Basile
2011-07-08  1:32 Anthony G. Basile

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1356230114.e14bb283546820ed3bb5174a058af2a30750f97f.blueness@gentoo \
    --to=blueness@gentoo.org \
    --cc=gentoo-commits@lists.gentoo.org \
    --cc=gentoo-dev@lists.gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox