Skip to content

Commit f6f2faf

Browse files
committed
gh-148178: Validate remote debug offset tables on load
Treat the debug offset tables read from a target process as untrusted input and validate them before the unwinder uses any reported sizes or offsets. Add a shared validator in debug_offsets_validation.h and run it once when _Py_DebugOffsets is loaded and once when AsyncioDebug is loaded. The checks cover section sizes used for fixed local buffers and every offset that is later dereferenced against a local buffer or local object view. This keeps the bounds checks out of the sampling hot path while rejecting malformed tables up front.
1 parent acf5229 commit f6f2faf

File tree

6 files changed

+455
-5
lines changed

6 files changed

+455
-5
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Hardened :mod:`!_remote_debugging` by validating remote debug offset tables
2+
before using them to size memory reads or interpret remote layouts.

Modules/_remote_debugging/_remote_debugging.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,7 @@ extern void cached_code_metadata_destroy(void *ptr);
417417
/* Validation */
418418
extern int is_prerelease_version(uint64_t version);
419419
extern int validate_debug_offsets(struct _Py_DebugOffsets *debug_offsets);
420+
#define PY_REMOTE_DEBUG_INVALID_ASYNC_DEBUG_OFFSETS (-2)
420421

421422
/* ============================================================================
422423
* MEMORY READING FUNCTION DECLARATIONS

Modules/_remote_debugging/asyncio.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
******************************************************************************/
77

88
#include "_remote_debugging.h"
9+
#include "debug_offsets_validation.h"
910

1011
/* ============================================================================
1112
* ASYNCIO DEBUG ADDRESS FUNCTIONS
@@ -71,8 +72,13 @@ read_async_debug(RemoteUnwinderObject *unwinder)
7172
int result = _Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, async_debug_addr, size, &unwinder->async_debug_offsets);
7273
if (result < 0) {
7374
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read AsyncioDebug offsets");
75+
return result;
7476
}
75-
return result;
77+
if (_PyRemoteDebug_ValidateAsyncDebugOffsets(&unwinder->async_debug_offsets) < 0) {
78+
set_exception_cause(unwinder, PyExc_RuntimeError, "Invalid AsyncioDebug offsets");
79+
return PY_REMOTE_DEBUG_INVALID_ASYNC_DEBUG_OFFSETS;
80+
}
81+
return 0;
7682
}
7783

7884
int
@@ -85,7 +91,11 @@ ensure_async_debug_offsets(RemoteUnwinderObject *unwinder)
8591

8692
// Try to load async debug offsets (the target process may have
8793
// loaded asyncio since we last checked)
88-
if (read_async_debug(unwinder) < 0) {
94+
int result = read_async_debug(unwinder);
95+
if (result == PY_REMOTE_DEBUG_INVALID_ASYNC_DEBUG_OFFSETS) {
96+
return -1;
97+
}
98+
if (result < 0) {
8999
PyErr_Clear();
90100
PyErr_SetString(PyExc_RuntimeError, "AsyncioDebug section not available");
91101
set_exception_cause(unwinder, PyExc_RuntimeError,

0 commit comments

Comments
 (0)