fix #1111 errno command edge case (#1126)

* fix #1111 errno command edge case

This commit fixes the case when errno command causes a binary to
segfault when the `__errno_location` symbol was defined but its .plt.got
entry was not filled yet by the dynamic loader (ld.so), so e.g. when the
glibc library was not loaded yet.

In such a case, us triggering a call to `__errno_location` function
triggered a jump to an unmapped address. Now, we dereference that
.plt.got symbol and see if it lives in mapped memory.

* add tip about errno command

* errno: fix case when __errno_location@got.plt is missing

* fix lint

* fix sh lint

* fix errno test
pull/1119/head
Disconnect3d 3 years ago committed by GitHub
parent cc50024417
commit b7ddf3a070
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -8,4 +8,4 @@ black --diff --check pwndbg tests
flake8 --show-source pwndbg tests
# Indents are four spaces, binary ops can start a line, and indent switch cases
shfmt -i 4 -bn -ci -d .
shfmt -i 4 -bn -ci -d .

@ -35,10 +35,24 @@ def errno_(err):
err = int(gdb.parse_and_eval("errno"))
except gdb.error:
try:
err = int(gdb.parse_and_eval("*((int *(*) (void)) __errno_location) ()"))
# We can't simply call __errno_location because its .plt.got entry may be uninitialized
# (e.g. if the binary was just started with `starti` command)
# So we have to check the got.plt entry first before calling it
errno_loc_gotplt = pwndbg.symbol.address("__errno_location@got.plt")
# If the got.plt entry is not there (is None), it means the symbol is not used by the binary
if errno_loc_gotplt is None or pwndbg.vmmap.find(
pwndbg.memory.pvoid(errno_loc_gotplt)
):
err = int(gdb.parse_and_eval("*((int *(*) (void)) __errno_location) ()"))
else:
print(
"Could not determine error code automatically: the __errno_location@got.plt has no valid address yet (perhaps libc.so hasn't been loaded yet?)"
)
return
except gdb.error:
print(
"Could not determine error code automatically: neither `errno` nor `__errno_location` symbols were provided (was libc.so loaded already?)"
"Could not determine error code automatically: neither `errno` nor `__errno_location` symbols were provided (perhaps libc.so hasn't been not loaded yet?)"
)
return

@ -21,6 +21,7 @@ TIPS = [
"Use the `procinfo` command for better process introspection (than the GDB's `info proc` command)",
"Want to display each context panel in a separate tmux window? See https://github.com/pwndbg/pwndbg/blob/dev/FEATURES.md#splitting--layouting-context",
"The $heap_base GDB variable can be used to refer to the starting address of the heap after running the `heap` command",
"Use the `errno` (or `errno <number>`) command to see the name of the last or provided (libc) error",
]

@ -21,7 +21,7 @@ def test_command_errno(start_binary):
result = "".join(gdb.execute("errno", to_string=True).splitlines())
assert (
result
== "Could not determine error code automatically: neither `errno` nor `__errno_location` symbols were provided (was libc.so loaded already?)"
== "Could not determine error code automatically: neither `errno` nor `__errno_location` symbols were provided (perhaps libc.so hasn't been not loaded yet?)"
)
gdb.execute("break main")

Loading…
Cancel
Save