aboutsummaryrefslogtreecommitdiff
blob: 09a41e2f75217da14f1c51cad254fe5ea28b1459 (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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#!/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 -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)

	object_needed = get_object_needed()

	fail = []
	none = []

	for elf in object_needed:
		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)
				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()