Skip to content

Commit 6657166

Browse files
authored
Merge pull request #125 from maurycy/maurycy-memcpy-get-member
gh-148178: Harden remote debug alignment checks
2 parents 215390a + 174853d commit 6657166

File tree

2 files changed

+108
-61
lines changed

2 files changed

+108
-61
lines changed

Modules/_remote_debugging/_remote_debugging.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,10 @@ typedef enum _WIN32_THREADSTATE {
120120
* MACROS AND CONSTANTS
121121
* ============================================================================ */
122122

123-
#define GET_MEMBER(type, obj, offset) (*(type*)((char*)(obj) + (offset)))
123+
#define GET_MEMBER(type, obj, offset) \
124+
(*(const type *)memcpy(&(type){0}, (const char *)(obj) + (offset), sizeof(type)))
124125
#define CLEAR_PTR_TAG(ptr) (((uintptr_t)(ptr) & ~Py_TAG_BITS))
125-
#define GET_MEMBER_NO_TAG(type, obj, offset) (type)(CLEAR_PTR_TAG(*(type*)((char*)(obj) + (offset))))
126+
#define GET_MEMBER_NO_TAG(type, obj, offset) (type)(CLEAR_PTR_TAG(GET_MEMBER(type, obj, offset)))
126127

127128
/* Size macros for opaque buffers */
128129
#define SIZEOF_BYTES_OBJ sizeof(PyBytesObject)

Modules/_remote_debugging/debug_offsets_validation.h

Lines changed: 105 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -107,14 +107,36 @@ validate_span(
107107
return 0;
108108
}
109109

110+
static inline int
111+
validate_alignment(
112+
const char *field_name,
113+
uint64_t offset,
114+
size_t alignment)
115+
{
116+
if (alignment > 1 && offset % alignment != 0) {
117+
PyErr_Format(
118+
PyExc_RuntimeError,
119+
"Invalid debug offsets: %s=%llu is not aligned to %zu bytes",
120+
field_name,
121+
(unsigned long long)offset,
122+
alignment);
123+
return -1;
124+
}
125+
return 0;
126+
}
127+
110128
static inline int
111129
validate_field(
112130
const char *field_name,
113131
uint64_t reported_size,
114132
uint64_t offset,
115133
size_t width,
134+
size_t alignment,
116135
size_t buffer_size)
117136
{
137+
if (validate_alignment(field_name, offset, alignment) < 0) {
138+
return -1;
139+
}
118140
if (validate_span(field_name, offset, width, reported_size, "reported size") < 0) {
119141
return -1;
120142
}
@@ -128,6 +150,7 @@ validate_nested_field(
128150
uint64_t base_offset,
129151
uint64_t nested_offset,
130152
size_t width,
153+
size_t alignment,
131154
size_t buffer_size)
132155
{
133156
if (base_offset > UINT64_MAX - nested_offset) {
@@ -142,6 +165,7 @@ validate_nested_field(
142165
reported_size,
143166
base_offset + nested_offset,
144167
width,
168+
alignment,
145169
buffer_size);
146170
}
147171

@@ -150,8 +174,12 @@ validate_fixed_field(
150174
const char *field_name,
151175
uint64_t offset,
152176
size_t width,
177+
size_t alignment,
153178
size_t buffer_size)
154179
{
180+
if (validate_alignment(field_name, offset, alignment) < 0) {
181+
return -1;
182+
}
155183
return validate_span(field_name, offset, width, buffer_size, "local buffer size");
156184
}
157185

@@ -169,37 +197,40 @@ validate_fixed_field(
169197
} \
170198
} while (0)
171199

172-
#define PY_REMOTE_DEBUG_VALIDATE_FIELD(section, field, field_size, buffer_size) \
200+
#define PY_REMOTE_DEBUG_VALIDATE_FIELD(section, field, field_size, field_alignment, buffer_size) \
173201
do { \
174202
if (validate_field( \
175203
#section "." #field, \
176204
debug_offsets->section.size, \
177205
debug_offsets->section.field, \
178206
field_size, \
207+
field_alignment, \
179208
buffer_size) < 0) { \
180209
return -1; \
181210
} \
182211
} while (0)
183212

184-
#define PY_REMOTE_DEBUG_VALIDATE_NESTED_FIELD(section, base, nested_section, field, field_size, buffer_size) \
213+
#define PY_REMOTE_DEBUG_VALIDATE_NESTED_FIELD(section, base, nested_section, field, field_size, field_alignment, buffer_size) \
185214
do { \
186215
if (validate_nested_field( \
187216
#section "." #base "." #field, \
188217
debug_offsets->section.size, \
189218
debug_offsets->section.base, \
190219
debug_offsets->nested_section.field, \
191220
field_size, \
221+
field_alignment, \
192222
buffer_size) < 0) { \
193223
return -1; \
194224
} \
195225
} while (0)
196226

197-
#define PY_REMOTE_DEBUG_VALIDATE_FIXED_FIELD(section, field, field_size, buffer_size) \
227+
#define PY_REMOTE_DEBUG_VALIDATE_FIXED_FIELD(section, field, field_size, field_alignment, buffer_size) \
198228
do { \
199229
if (validate_fixed_field( \
200230
#section "." #field, \
201231
debug_offsets->section.field, \
202232
field_size, \
233+
field_alignment, \
203234
buffer_size) < 0) { \
204235
return -1; \
205236
} \
@@ -216,84 +247,84 @@ validate_fixed_field(
216247
* the unwinder, so no validation is needed for them.
217248
*/
218249
#define PY_REMOTE_DEBUG_RUNTIME_STATE_FIELDS(APPLY, buffer_size) \
219-
APPLY(runtime_state, interpreters_head, sizeof(uintptr_t), buffer_size)
250+
APPLY(runtime_state, interpreters_head, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size)
220251

221252
#define PY_REMOTE_DEBUG_THREAD_STATE_FIELDS(APPLY, buffer_size) \
222-
APPLY(thread_state, native_thread_id, sizeof(unsigned long), buffer_size); \
223-
APPLY(thread_state, interp, sizeof(uintptr_t), buffer_size); \
224-
APPLY(thread_state, datastack_chunk, sizeof(uintptr_t), buffer_size); \
225-
APPLY(thread_state, status, FIELD_SIZE(PyThreadState, _status), buffer_size); \
226-
APPLY(thread_state, holds_gil, sizeof(int), buffer_size); \
227-
APPLY(thread_state, gil_requested, sizeof(int), buffer_size); \
228-
APPLY(thread_state, current_exception, sizeof(uintptr_t), buffer_size); \
229-
APPLY(thread_state, thread_id, sizeof(unsigned long), buffer_size); \
230-
APPLY(thread_state, next, sizeof(uintptr_t), buffer_size); \
231-
APPLY(thread_state, current_frame, sizeof(uintptr_t), buffer_size); \
232-
APPLY(thread_state, base_frame, sizeof(uintptr_t), buffer_size); \
233-
APPLY(thread_state, last_profiled_frame, sizeof(uintptr_t), buffer_size)
253+
APPLY(thread_state, native_thread_id, sizeof(unsigned long), _Alignof(long), buffer_size); \
254+
APPLY(thread_state, interp, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \
255+
APPLY(thread_state, datastack_chunk, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \
256+
APPLY(thread_state, status, FIELD_SIZE(PyThreadState, _status), _Alignof(unsigned int), buffer_size); \
257+
APPLY(thread_state, holds_gil, sizeof(int), _Alignof(int), buffer_size); \
258+
APPLY(thread_state, gil_requested, sizeof(int), _Alignof(int), buffer_size); \
259+
APPLY(thread_state, current_exception, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \
260+
APPLY(thread_state, thread_id, sizeof(unsigned long), _Alignof(long), buffer_size); \
261+
APPLY(thread_state, next, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \
262+
APPLY(thread_state, current_frame, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \
263+
APPLY(thread_state, base_frame, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \
264+
APPLY(thread_state, last_profiled_frame, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size)
234265

235266
#define PY_REMOTE_DEBUG_INTERPRETER_STATE_FIELDS(APPLY, buffer_size) \
236-
APPLY(interpreter_state, id, sizeof(int64_t), buffer_size); \
237-
APPLY(interpreter_state, next, sizeof(uintptr_t), buffer_size); \
238-
APPLY(interpreter_state, threads_head, sizeof(uintptr_t), buffer_size); \
239-
APPLY(interpreter_state, threads_main, sizeof(uintptr_t), buffer_size); \
240-
APPLY(interpreter_state, gil_runtime_state_locked, sizeof(int), buffer_size); \
241-
APPLY(interpreter_state, gil_runtime_state_holder, sizeof(PyThreadState *), buffer_size); \
242-
APPLY(interpreter_state, code_object_generation, sizeof(uint64_t), buffer_size); \
243-
APPLY(interpreter_state, tlbc_generation, sizeof(uint32_t), buffer_size)
267+
APPLY(interpreter_state, id, sizeof(int64_t), _Alignof(int64_t), buffer_size); \
268+
APPLY(interpreter_state, next, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \
269+
APPLY(interpreter_state, threads_head, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \
270+
APPLY(interpreter_state, threads_main, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \
271+
APPLY(interpreter_state, gil_runtime_state_locked, sizeof(int), _Alignof(int), buffer_size); \
272+
APPLY(interpreter_state, gil_runtime_state_holder, sizeof(PyThreadState *), _Alignof(PyThreadState *), buffer_size); \
273+
APPLY(interpreter_state, code_object_generation, sizeof(uint64_t), _Alignof(uint64_t), buffer_size); \
274+
APPLY(interpreter_state, tlbc_generation, sizeof(uint32_t), _Alignof(uint32_t), buffer_size)
244275

245276
#define PY_REMOTE_DEBUG_INTERPRETER_FRAME_FIELDS(APPLY, buffer_size) \
246-
APPLY(interpreter_frame, previous, sizeof(uintptr_t), buffer_size); \
247-
APPLY(interpreter_frame, executable, sizeof(uintptr_t), buffer_size); \
248-
APPLY(interpreter_frame, instr_ptr, sizeof(uintptr_t), buffer_size); \
249-
APPLY(interpreter_frame, owner, sizeof(char), buffer_size); \
250-
APPLY(interpreter_frame, stackpointer, sizeof(uintptr_t), buffer_size); \
251-
APPLY(interpreter_frame, tlbc_index, sizeof(int32_t), buffer_size)
277+
APPLY(interpreter_frame, previous, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \
278+
APPLY(interpreter_frame, executable, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \
279+
APPLY(interpreter_frame, instr_ptr, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \
280+
APPLY(interpreter_frame, owner, sizeof(char), _Alignof(char), buffer_size); \
281+
APPLY(interpreter_frame, stackpointer, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \
282+
APPLY(interpreter_frame, tlbc_index, sizeof(int32_t), _Alignof(int32_t), buffer_size)
252283

253284
#define PY_REMOTE_DEBUG_CODE_OBJECT_FIELDS(APPLY, buffer_size) \
254-
APPLY(code_object, qualname, sizeof(uintptr_t), buffer_size); \
255-
APPLY(code_object, filename, sizeof(uintptr_t), buffer_size); \
256-
APPLY(code_object, linetable, sizeof(uintptr_t), buffer_size); \
257-
APPLY(code_object, firstlineno, sizeof(int), buffer_size); \
258-
APPLY(code_object, co_code_adaptive, sizeof(char), buffer_size); \
259-
APPLY(code_object, co_tlbc, sizeof(uintptr_t), buffer_size)
285+
APPLY(code_object, qualname, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \
286+
APPLY(code_object, filename, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \
287+
APPLY(code_object, linetable, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \
288+
APPLY(code_object, firstlineno, sizeof(int), _Alignof(int), buffer_size); \
289+
APPLY(code_object, co_code_adaptive, sizeof(char), _Alignof(char), buffer_size); \
290+
APPLY(code_object, co_tlbc, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size)
260291

261292
#define PY_REMOTE_DEBUG_SET_OBJECT_FIELDS(APPLY, buffer_size) \
262-
APPLY(set_object, used, sizeof(Py_ssize_t), buffer_size); \
263-
APPLY(set_object, mask, sizeof(Py_ssize_t), buffer_size); \
264-
APPLY(set_object, table, sizeof(uintptr_t), buffer_size)
293+
APPLY(set_object, used, sizeof(Py_ssize_t), _Alignof(Py_ssize_t), buffer_size); \
294+
APPLY(set_object, mask, sizeof(Py_ssize_t), _Alignof(Py_ssize_t), buffer_size); \
295+
APPLY(set_object, table, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size)
265296

266297
#define PY_REMOTE_DEBUG_LONG_OBJECT_FIELDS(APPLY, buffer_size) \
267-
APPLY(long_object, lv_tag, sizeof(uintptr_t), buffer_size); \
268-
APPLY(long_object, ob_digit, sizeof(digit), buffer_size)
298+
APPLY(long_object, lv_tag, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \
299+
APPLY(long_object, ob_digit, sizeof(digit), _Alignof(digit), buffer_size)
269300

270301
#define PY_REMOTE_DEBUG_BYTES_OBJECT_FIELDS(APPLY, buffer_size) \
271-
APPLY(bytes_object, ob_size, sizeof(Py_ssize_t), buffer_size); \
272-
APPLY(bytes_object, ob_sval, sizeof(char), buffer_size)
302+
APPLY(bytes_object, ob_size, sizeof(Py_ssize_t), _Alignof(Py_ssize_t), buffer_size); \
303+
APPLY(bytes_object, ob_sval, sizeof(char), _Alignof(char), buffer_size)
273304

274305
#define PY_REMOTE_DEBUG_UNICODE_OBJECT_FIELDS(APPLY, buffer_size) \
275-
APPLY(unicode_object, length, sizeof(Py_ssize_t), buffer_size); \
276-
APPLY(unicode_object, asciiobject_size, sizeof(char), buffer_size)
306+
APPLY(unicode_object, length, sizeof(Py_ssize_t), _Alignof(Py_ssize_t), buffer_size); \
307+
APPLY(unicode_object, asciiobject_size, sizeof(char), _Alignof(char), buffer_size)
277308

278309
#define PY_REMOTE_DEBUG_GEN_OBJECT_FIELDS(APPLY, buffer_size) \
279-
APPLY(gen_object, gi_frame_state, sizeof(int8_t), buffer_size); \
280-
APPLY(gen_object, gi_iframe, FIELD_SIZE(PyGenObject, gi_iframe), buffer_size)
310+
APPLY(gen_object, gi_frame_state, sizeof(int8_t), _Alignof(int8_t), buffer_size); \
311+
APPLY(gen_object, gi_iframe, FIELD_SIZE(PyGenObject, gi_iframe), _Alignof(_PyInterpreterFrame), buffer_size)
281312

282313
#define PY_REMOTE_DEBUG_TASK_OBJECT_FIELDS(APPLY, buffer_size) \
283-
APPLY(asyncio_task_object, task_name, sizeof(uintptr_t), buffer_size); \
284-
APPLY(asyncio_task_object, task_awaited_by, sizeof(uintptr_t), buffer_size); \
285-
APPLY(asyncio_task_object, task_is_task, sizeof(char), buffer_size); \
286-
APPLY(asyncio_task_object, task_awaited_by_is_set, sizeof(char), buffer_size); \
287-
APPLY(asyncio_task_object, task_coro, sizeof(uintptr_t), buffer_size); \
288-
APPLY(asyncio_task_object, task_node, SIZEOF_LLIST_NODE, buffer_size)
314+
APPLY(asyncio_task_object, task_name, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \
315+
APPLY(asyncio_task_object, task_awaited_by, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \
316+
APPLY(asyncio_task_object, task_is_task, sizeof(char), _Alignof(char), buffer_size); \
317+
APPLY(asyncio_task_object, task_awaited_by_is_set, sizeof(char), _Alignof(char), buffer_size); \
318+
APPLY(asyncio_task_object, task_coro, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \
319+
APPLY(asyncio_task_object, task_node, SIZEOF_LLIST_NODE, _Alignof(struct llist_node), buffer_size)
289320

290321
#define PY_REMOTE_DEBUG_ASYNC_INTERPRETER_STATE_FIELDS(APPLY, buffer_size) \
291-
APPLY(asyncio_interpreter_state, asyncio_tasks_head, SIZEOF_LLIST_NODE, buffer_size)
322+
APPLY(asyncio_interpreter_state, asyncio_tasks_head, SIZEOF_LLIST_NODE, _Alignof(struct llist_node), buffer_size)
292323

293324
#define PY_REMOTE_DEBUG_ASYNC_THREAD_STATE_FIELDS(APPLY, buffer_size) \
294-
APPLY(asyncio_thread_state, asyncio_running_loop, sizeof(uintptr_t), buffer_size); \
295-
APPLY(asyncio_thread_state, asyncio_running_task, sizeof(uintptr_t), buffer_size); \
296-
APPLY(asyncio_thread_state, asyncio_tasks_head, SIZEOF_LLIST_NODE, buffer_size)
325+
APPLY(asyncio_thread_state, asyncio_running_loop, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \
326+
APPLY(asyncio_thread_state, asyncio_running_task, sizeof(uintptr_t), _Alignof(uintptr_t), buffer_size); \
327+
APPLY(asyncio_thread_state, asyncio_tasks_head, SIZEOF_LLIST_NODE, _Alignof(struct llist_node), buffer_size)
297328

298329
/* Called once after reading _Py_DebugOffsets, before any hot-path use. */
299330
static inline int
@@ -321,23 +352,31 @@ _PyRemoteDebug_ValidateDebugOffsetsLayout(struct _Py_DebugOffsets *debug_offsets
321352
err_stackitem,
322353
exc_value,
323354
sizeof(uintptr_t),
355+
_Alignof(uintptr_t),
324356
sizeof(_PyErr_StackItem));
325357
PY_REMOTE_DEBUG_VALIDATE_NESTED_FIELD(
326358
thread_state,
327359
exc_state,
328360
err_stackitem,
329361
exc_value,
330362
sizeof(uintptr_t),
363+
_Alignof(uintptr_t),
331364
SIZEOF_THREAD_STATE);
332365

333366
PY_REMOTE_DEBUG_VALIDATE_READ_SECTION(gc, SIZEOF_GC_RUNTIME_STATE);
334-
PY_REMOTE_DEBUG_VALIDATE_FIELD(gc, frame, sizeof(uintptr_t), SIZEOF_GC_RUNTIME_STATE);
367+
PY_REMOTE_DEBUG_VALIDATE_FIELD(
368+
gc,
369+
frame,
370+
sizeof(uintptr_t),
371+
_Alignof(uintptr_t),
372+
SIZEOF_GC_RUNTIME_STATE);
335373
PY_REMOTE_DEBUG_VALIDATE_NESTED_FIELD(
336374
interpreter_state,
337375
gc,
338376
gc,
339377
frame,
340378
sizeof(uintptr_t),
379+
_Alignof(uintptr_t),
341380
INTERP_STATE_BUFFER_SIZE);
342381

343382
PY_REMOTE_DEBUG_VALIDATE_SECTION(interpreter_frame);
@@ -351,13 +390,19 @@ _PyRemoteDebug_ValidateDebugOffsetsLayout(struct _Py_DebugOffsets *debug_offsets
351390
SIZEOF_CODE_OBJ);
352391

353392
PY_REMOTE_DEBUG_VALIDATE_SECTION(pyobject);
354-
PY_REMOTE_DEBUG_VALIDATE_FIELD(pyobject, ob_type, sizeof(uintptr_t), SIZEOF_PYOBJECT);
393+
PY_REMOTE_DEBUG_VALIDATE_FIELD(
394+
pyobject,
395+
ob_type,
396+
sizeof(uintptr_t),
397+
_Alignof(uintptr_t),
398+
SIZEOF_PYOBJECT);
355399

356400
PY_REMOTE_DEBUG_VALIDATE_SECTION(type_object);
357401
PY_REMOTE_DEBUG_VALIDATE_FIELD(
358402
type_object,
359403
tp_flags,
360404
sizeof(unsigned long),
405+
_Alignof(unsigned long),
361406
SIZEOF_TYPE_OBJ);
362407

363408
PY_REMOTE_DEBUG_VALIDATE_SECTION(set_object);
@@ -389,6 +434,7 @@ _PyRemoteDebug_ValidateDebugOffsetsLayout(struct _Py_DebugOffsets *debug_offsets
389434
llist_node,
390435
next,
391436
sizeof(uintptr_t),
437+
_Alignof(uintptr_t),
392438
SIZEOF_LLIST_NODE);
393439

394440
return 0;

0 commit comments

Comments
 (0)