Skip to content

Commit b8fad78

Browse files
committed
Fix binutils version checking and RWX warnings
Fixes Gallopsled#2140 Closes Gallopsled#2098 Closes Gallopsled#2141
1 parent 8f42bef commit b8fad78

File tree

1 file changed

+40
-25
lines changed

1 file changed

+40
-25
lines changed

pwnlib/asm.py

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,23 @@ def print_binutils_instructions(util, context):
136136
%(instructions)s
137137
""".strip() % locals())
138138

139+
140+
def check_binutils_version(util):
141+
if util_versions[util]:
142+
return util_versions[util]
143+
result = subprocess.check_output([util, '--version','/dev/null'],
144+
stderr=subprocess.STDOUT, universal_newlines=True)
145+
if 'clang' in result:
146+
log.warn_once('Your binutils is clang-based and may not work!\n'
147+
'Try installing with: https://docs.pwntools.com/en/stable/install/binutils.html\n'
148+
'Reported version: %r', result.strip())
149+
version = re.search(r' (\d+\.\d+)', result).group(1)
150+
util_versions[util] = version = tuple(map(int, version.split('.')))
151+
return version
152+
153+
139154
@LocalContext
140-
def which_binutils(util):
155+
def which_binutils(util, check_version=False):
141156
"""
142157
Finds a binutils in the PATH somewhere.
143158
Expects that the utility is prefixed with the architecture name.
@@ -204,17 +219,23 @@ def which_binutils(util):
204219

205220
for pattern in patterns:
206221
for dir in environ['PATH'].split(':'):
207-
res = sorted(glob(path.join(dir, pattern)))
208-
if res:
209-
return res[0]
222+
for res in sorted(glob(path.join(dir, pattern))):
223+
if check_version:
224+
ver = check_binutils_version(res)
225+
return res, ver
226+
return res
210227

211228
# No dice!
212229
print_binutils_instructions(util, context)
213230

214-
checked_assembler_version = defaultdict(lambda: False)
231+
util_versions = defaultdict(tuple)
215232

216233
def _assembler():
217-
gas = which_binutils('as')
234+
gas, version = which_binutils('as', check_version=True)
235+
if version < (2, 19):
236+
log.warn_once('Your binutils version is too old and may not work!\n'
237+
'Try updating with: https://docs.pwntools.com/en/stable/install/binutils.html\n'
238+
'Reported version: %r', version)
218239

219240
E = {
220241
'big': '-EB',
@@ -246,25 +267,10 @@ def _assembler():
246267

247268
assembler = assemblers.get(context.arch, [gas])
248269

249-
if not checked_assembler_version[gas]:
250-
checked_assembler_version[gas] = True
251-
result = subprocess.check_output([gas, '--version','/dev/null'],
252-
stderr=subprocess.STDOUT, universal_newlines=True)
253-
version = re.search(r' (\d+\.\d+)', result).group(1)
254-
if 'clang' in result:
255-
log.warn_once('Your binutils is clang version and may not work!\n'
256-
'Try install with: https://docs.pwntools.com/en/stable/install/binutils.html\n'
257-
'Reported Version: %r', result.strip())
258-
elif version < '2.19':
259-
log.warn_once('Your binutils version is too old and may not work!\n'
260-
'Try updating with: https://docs.pwntools.com/en/stable/install/binutils.html\n'
261-
'Reported Version: %r', result.strip())
262-
263-
264270
return assembler
265271

266272
def _linker():
267-
ld = [which_binutils('ld')]
273+
ld, _ = which_binutils('ld', check_version=True)
268274
bfd = ['--oformat=' + _bfdname()]
269275

270276
E = {
@@ -276,7 +282,16 @@ def _linker():
276282
'i386': ['-m', 'elf_i386'],
277283
}.get(context.arch, [])
278284

279-
return ld + bfd + [E] + arguments
285+
return [ld] + bfd + [E] + arguments
286+
287+
288+
def _execstack(linker):
289+
ldflags = ['-z', 'execstack']
290+
version = util_versions[linker[0]]
291+
if version >= (2, 39):
292+
return ldflags + ['--no-warn-execstack', '--no-warn-rwx-segments']
293+
return ldflags
294+
280295

281296
def _objcopy():
282297
return [which_binutils('objcopy')]
@@ -595,7 +610,7 @@ def make_elf(data,
595610

596611
_run(assembler + ['-o', step2, step1])
597612

598-
linker_options = ['-z', 'execstack']
613+
linker_options = _execstack(linker)
599614
if vma is not None:
600615
linker_options += ['--section-start=.shellcode=%#x' % vma,
601616
'--entry=%#x' % vma]
@@ -689,7 +704,7 @@ def asm(shellcode, vma = 0, extract = True, shared = False):
689704
shutil.copy(step2, step3)
690705

691706
if vma or not extract:
692-
ldflags = ['-z', 'execstack', '-o', step3, step2]
707+
ldflags = _execstack(linker) + ['-o', step3, step2]
693708
if vma:
694709
ldflags += ['--section-start=.shellcode=%#x' % vma,
695710
'--entry=%#x' % vma]

0 commit comments

Comments
 (0)