pwndbg/pwndbg

Telescope bug when incorrectly detecting Linux + debugging system without memory mappings

Closed

#2806 opened on Mar 28, 2025

View on GitHub
 (11 comments) (1 reaction) (0 assignees)Python (5,820 stars) (776 forks)batch import
buggood first issuehelp wanted

Description

I came across a bug related to the interaction of various parts of the codebase that culminate in telescope printing incorrect values when debugging a system that doesn't expose memory mappings, such as qemu-system, and when we incorrectly detect the process as a Linux process.

Incorrect telescope:

Image

With the mapping explicitely explored with vmmap_explore

Image

Reproduce the bug

For anyone wanting to reproduce - you may want to do this in an Ubuntu docker container (that exposes port 1234 so you can connect to the gdb, as a lot of packages are installed

git clone https://github.com/google/esh.git
cd esh
# this installs a bunch of packages
./manage -s
cd examples/emulation/armv7M-32
# this runs an Arm cortex M program, waits on port 1234 for gdb to connect
make debug

# run telescope / look at stack output, values are incorrect. Read memory directly with `x/wx addr` to see discrepancy
# Run "vmmap_explore 0" to explicitly add the memory mapping

Bugs

  1. is_linux returns True incorrectly.

I was running https://github.com/google/esh, which provides a quick way to run a simple program in various architectures with emulation. I ran it with Arm Cortex M (examples/emulation/armv7M-32).

In this case, pwndbg.dbg.selected_inferior().is_linux() returns True, even when this is not the case.

It internally calls show osabi, and GDB returns GNU/Linux.

  1. Cascading errors in the case memory mappings do not exist:

chain.get() ignores vmmap in case we detect are in Linux, and dereferences pointers until a memory error is thrown.

https://github.com/pwndbg/pwndbg/blob/a82e152f94ad818b7720ed913e53529d8d6296e6/pwndbg/chain.py#L76-L88

The second-to-last pointer that chain.get returns gets passed to pwndbg.enhance.enhance() at the end of chain.format(),

https://github.com/pwndbg/pwndbg/blob/a82e152f94ad818b7720ed913e53529d8d6296e6/pwndbg/chain.py#L169-L176

In chain.get we already dereferenced and know it's a valid pointer. In this call to enhance, we assume that enhance will dereference it.

However, a check in enhance makes it so this value is not dereferenced if the memory mapping doesn't exist.

https://github.com/pwndbg/pwndbg/blob/a82e152f94ad818b7720ed913e53529d8d6296e6/pwndbg/enhance.py#L84

Instead, it returns the value as-is, resulting in an incorrect value return returned from chain.format (value <- value)

An ideal fix introduces some more guardrails so that in the case of linux detection being incorrect, we don't get cascading errors that result in telescope printing incorrect values.

Contributor guide