aboutsummaryrefslogtreecommitdiff
blob: e30c3061bd670ae84243ceaf575724719ae00623 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#!/usr/bin/env python

#
# Note: This alternative way of doing revdep-pax only
# works on Gentoo systems where NEEDED.ELF.2 all the
# information we need generated by scanelf during emerge.
#
# See /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

def get_object_needed():

	var_db_pkg = '/var/db/pkg'

	object_needed = {}
	for cat in os.listdir(var_db_pkg):
		catdir = '%s/%s' % (var_db_pkg, cat)
		for pkg in os.listdir(catdir):
			pkgdir = '%s/%s' % (catdir, pkg)
			need = '%s/%s' % (pkgdir, 'NEEDED.ELF.2')
			try:
				g = open(need, 'r')
				needs = g.readlines()
				for line in needs:
					line = line.strip()
					link = re.split(';', line)
					elf = link[1]
					sonames = re.split(',', link[4])
					object_needed[elf] = sonames
			except IOError:
				continue #File probably doesn't exist, which is okay

	return object_needed


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 [-h]      print out this help')
	print('             : -v                be verbose when migrating')
	print('')


def main():
	try:
		opts, args = getopt.getopt(sys.argv[1:], 'mv')
	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_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 == '-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 opt_count == 0 or do_usage:
		run_usage()
		sys.exit(0)

	uid = os.getuid()
	if uid != 0 and do_migration:
		print('RUN AS ROOT: cannot migrate flags')
		sys.exit(0)

	object_needed = get_object_needed()

	fail = []
	none = []

	for elf in object_needed:
		try:
			if flags:
				if verbose:
					print("%s %s" % (flags, elf))
			else:
				none.append(elf)
				if verbose:
					print("NONE: %s" % elf)
			if do_migration:
				flags = pax.getflags(elf)[0]
				flags = re.sub('-','',flags)
				pax.setstrflags(elf, flags)

		# 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()