-
-
Notifications
You must be signed in to change notification settings - Fork 34.3k
Description
CPython version: 3.15.0a7
Component: Modules/_remote_debugging/_remote_debugging.h
CWE: CWE-125 (Out-of-bounds Read)
Description
The GET_MEMBER and GET_MEMBER_NO_TAG macros in _remote_debugging.h (lines 127-129) perform unchecked pointer arithmetic using offset values read from a target process's _Py_DebugOffsets structure:
#define GET_MEMBER(type, base_ptr, offset) \
(*(type*)((char*)(base_ptr) + (offset)))If the offset values in the target process's _Py_DebugOffsets are corrupted or invalid (e.g., due to memory corruption, a partially-initialized interpreter, or a misbehaving extension), RemoteUnwinder dereferences a pointer far outside the intended struct boundaries and crashes with SIGSEGV.
validate_debug_offsets() only checks the cookie (xdebugpy) and version number — it does not validate that individual offset fields are within reasonable bounds for their respective structs.
Steps to Reproduce
- Build CPython 3.15.0a7 from source
- Start a target Python process
- Corrupt the
_Py_DebugOffsetsstructure in the target (e.g., set offset fields at struct+120, +136, +168, +184, +192 to0x8000) - Attach
RemoteUnwinderand callget_stack_trace() - The debugger process crashes with return code -11 (SIGSEGV)
A clean target with valid offsets works fine — the crash only occurs when offset fields contain out-of-range values.
Expected Behavior
RemoteUnwinder should detect that the offsets are outside valid bounds and raise a Python exception (e.g., RuntimeError) rather than crashing with a segfault. The debugger process should never crash due to invalid data in the target process.
Suggested Fix
Add bounds validation for all offset fields after reading _Py_DebugOffsets from the remote process. For example:
#define GET_MEMBER_SAFE(type, obj, offset, obj_size) \
(assert((offset) + sizeof(type) <= (obj_size)), \
(*(type*)((char*)(obj) + (offset))))Or extend the existing validate_debug_offsets() function to check that each offset is within the known size of its target struct (e.g., PyThreadState, PyInterpreterState, PyCodeObject, etc.).
Impact
Any tool using RemoteUnwinder — debugpy, py-spy, IDE debuggers — will crash instead of gracefully reporting an error when it encounters a process with corrupted debug offsets.