Repository navigation
Heap out-of-bound read in socket.sendmsg ancillary parser after re-entrant __index__ clears the control list #143637
Copy link
Copy link
Closed
Labels
extension-modulesC modules in the Modules dirC modules in the Modules dirtype-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
Description
What happened?
_socket_socket_sendmsg_impl fast-paths ancillary data with PySequence_Fast, assuming the original list stays stable. Parsing each (level, type, data) tuple calls PyLong_AsLongAndOverflow, which runs __index__; a malicious __index__ can clear the shared list mid-loop, leaving ncmsgs and cached element pointers stale. The next PySequence_Fast_GET_ITEM then indexes past the shortened list and dereferences freed slots, crashing with a heap OOB read at Modules/socketmodule.c:5005.
Proof of Concept:
import socket
seq = []
class Mut:
def __init__(self):
self.tripped = False
def __index__(self):
if not self.tripped:
self.tripped = True
seq.clear()
return 0
seq[:] = [
(socket.SOL_SOCKET, Mut(), b'x'),
(socket.SOL_SOCKET, 0, b'x'),
]
left, right = socket.socketpair()
left.sendmsg([b'x'], seq)Vulnerable Code Snippet:
Click to expand
/* Buggy Re-entrant Path */
long
PyLong_AsLongAndOverflow(PyObject *vv, int *overflow)
{
/* ... */
if (PyLong_Check(vv)) {
v = (PyLongObject *)vv;
}
else {
v = (PyLongObject *)_PyNumber_Index(vv); /* Reentrant call site */
if (v == NULL)
return -1;
do_decref = 1;
}
/* ... */
}
if ((cmsg_fast = PySequence_Fast(cmsg_arg,
"sendmsg() argument 2 must be an "
"iterable")) == NULL)
goto finally;
ncmsgs = PySequence_Fast_GET_SIZE(cmsg_fast);
/* ... */
while (ncmsgbufs < ncmsgs) {
if (!PyArg_Parse(PySequence_Fast_GET_ITEM(cmsg_fast, ncmsgbufs), /* crashing pointer derived */
"(iiy*):[sendmsg() ancillary data items]",
&cmsgs[ncmsgbufs].level,
&cmsgs[ncmsgbufs].type,
&cmsgs[ncmsgbufs].data)) /* Crash site */
goto finally;
/* ... */
}
/* Clobbering Path */
static void
list_clear_impl(PyListObject *a, bool is_resize)
{
PyObject **items = a->ob_item;
/* ... */
Py_ssize_t i = Py_SIZE(a);
Py_SET_SIZE(a, 0);
FT_ATOMIC_STORE_PTR_RELEASE(a->ob_item, NULL);
a->allocated = 0;
while (--i >= 0) {
Py_XDECREF(items[i]); /* state mutate site */
}
free_list_items(items, use_qsbr);
}Sanitizer Output:
Click to expand
AddressSanitizer:DEADLYSIGNAL
=================================================================
==423360==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000008 (pc 0x73089bf5b108 bp 0x7ffe70547070 sp 0x7ffe70546db0 T0)
==423360==The signal is caused by a READ memory access.
==423360==Hint: address points to the zero page.
#0 0x73089bf5b108 in _socket_socket_sendmsg_impl Modules/socketmodule.c:5005
#1 0x73089bf5b108 in _socket_socket_sendmsg Modules/clinic/socketmodule.c.h:188
#2 0x605448f333e7 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169
#3 0x605448f333e7 in PyObject_Vectorcall Objects/call.c:327
#4 0x605448de75a2 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1620
#5 0x6054492b1ad6 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121
#6 0x6054492b1ad6 in _PyEval_Vector Python/ceval.c:2001
#7 0x6054492b1ad6 in PyEval_EvalCode Python/ceval.c:884
#8 0x6054493f716e in run_eval_code_obj Python/pythonrun.c:1365
#9 0x6054493f716e in run_mod Python/pythonrun.c:1459
#10 0x6054493fbe17 in pyrun_file Python/pythonrun.c:1293
#11 0x6054493fbe17 in _PyRun_SimpleFileObject Python/pythonrun.c:521
#12 0x6054493fc93c in _PyRun_AnyFileObject Python/pythonrun.c:81
#13 0x60544946fe3c in pymain_run_file_obj Modules/main.c:410
#14 0x60544946fe3c in pymain_run_file Modules/main.c:429
#15 0x60544946fe3c in pymain_run_python Modules/main.c:691
#16 0x60544947171e in Py_RunMain Modules/main.c:772
#17 0x60544947171e in pymain_main Modules/main.c:802
#18 0x60544947171e in Py_BytesMain Modules/main.c:826
#19 0x73089c42a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#20 0x73089c42a28a in __libc_start_main_impl ../csu/libc-start.c:360
#21 0x605448e0b634 in _start (/home/jackfromeast/Desktop/entropy/targets/grammar-afl++-latest/targets/cpython/python+0x206634) (BuildId: 4d105290d0ad566a4d6f4f7b2f05fbc9e317b533)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV Modules/socketmodule.c:5005 in _socket_socket_sendmsg_impl
==423360==ABORTING
CPython versions tested on:
Details
| Python Version | Status | Exit Code |
|---|---|---|
Python 3.9.24+ (heads/3.9:111bbc15b26, Oct 28 2025, 16:51:20) |
ASAN | 1 |
Python 3.10.19+ (heads/3.10:014261980b1, Oct 28 2025, 16:52:08) [Clang 18.1.3 (1ubuntu1)] |
ASAN | 1 |
Python 3.11.14+ (heads/3.11:88f3f5b5f11, Oct 28 2025, 16:53:08) [Clang 18.1.3 (1ubuntu1)] |
ASAN | 1 |
Python 3.12.12+ (heads/3.12:8cb2092bd8c, Oct 28 2025, 16:54:14) [Clang 18.1.3 (1ubuntu1)] |
ASAN | 1 |
Python 3.13.9+ (heads/3.13:9c8eade20c6, Oct 28 2025, 16:55:18) [Clang 18.1.3 (1ubuntu1)] |
ASAN | 1 |
Python 3.14.0+ (heads/3.14:2e216728038, Oct 28 2025, 16:56:16) [Clang 18.1.3 (1ubuntu1)] |
ASAN | 1 |
Python 3.15.0a1+ (heads/main:f5394c257ce, Oct 28 2025, 19:29:54) [GCC 13.3.0] |
ASAN | 1 |
Output from running 'python -VV' on the command line:
Python 3.15.0a1+ (heads/main:f5394c257ce, Oct 28 2025, 19:29:54) [GCC 13.3.0]
Linked PRs
- gh-143637: Fix re-entrant mutation of ancillary data in socket.sendmsg() #143892
- [3.13] gh-143637: Fix re-entrant mutation of ancillary data in socket.sendmsg() (GH-143892) #144785
- [3.14] gh-143637: Fix re-entrant mutation of ancillary data in socket.sendmsg() (GH-143892) #144786
- gh-143637: Fix test_socket.test_sendmsg_reentrant_ancillary_mutation() on Solaris #144890
- [3.14] gh-143637: Fix test_socket.test_sendmsg_reentrant_ancillary_mutation() on Solaris (GH-144890) #144901
- [3.13] gh-143637: Fix test_socket.test_sendmsg_reentrant_ancillary_mutation() on Solaris (GH-144890) #144902
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
extension-modulesC modules in the Modules dirC modules in the Modules dirtype-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
Activity
priyanshu2282-cyber commentedon Jan 11, 2026
Hi, thanks for the detailed report, I just wanted to ask, whether someone is working on a fix for it, or if it is okay for me to raise a PR. I would be happy to coordinate or help in any way that’s useful.
pythongh-143637: Fix reentrant mutation crash in socket.sendmsg
Fix re-entrant mutation crashes in socket sendmsg/recvmsg_into via __…
pythongh-143988: Fix re-entrant mutation crashes in socket sendmsg/re…
pythongh-143988: Fix re-entrant mutation crashes in socket sendmsg/re…
pythongh-143988: Fix re-entrant mutation crashes in socket sendmsg/re…
pythongh-143988: Fix re-entrant mutation crashes in socket sendmsg/re…
pythongh-143988: Fix re-entrant mutation crashes in socket sendmsg/re…
gh-143637: Fix re-entrant mutation of ancillary data in socket.sendms…
pythongh-143637: Fix re-entrant mutation of ancillary data in socket.…
pythongh-143637: Fix re-entrant mutation of ancillary data in socket.…
vstinner commentedon Feb 13, 2026
Fixed. Thanks for your bug report @jackfromeast.
3 remaining items
vstinner commentedon Feb 16, 2026
Hi @kulikjak, if I modify the unit test on Linux to raise the exception, I get the following error:
The ancillary data is:
vstinner commentedon Feb 16, 2026
We can modify the test to use ancillary data which fail on all platforms.
kulikjak commentedon Feb 16, 2026
Well, seems like Solaris is much more forgiving in how it handles invalid ancillary data. I did manage to raise an
OSErrorwith0x1010beingsocket.SCM_RIGHTS. Maybe we can add this line to the list?pythongh-143637: Fix test_socket.test_sendmsg_reentrant_ancillary_mut…
vstinner commentedon Feb 16, 2026
Ok. Can you test my fix #144890 on Solaris?
kulikjak commentedon Feb 17, 2026
Thank you @vstinner - tested with all three affected runtimes and the issue is gone.
gh-143637: Fix test_socket.test_sendmsg_reentrant_ancillary_mutation(…
pythongh-143637: Fix test_socket.test_sendmsg_reentrant_ancillary_mut…
pythongh-143637: Fix test_socket.test_sendmsg_reentrant_ancillary_mut…
[3.13] gh-143637: Fix test_socket.test_sendmsg_reentrant_ancillary_mu…
[3.14] gh-143637: Fix test_socket.test_sendmsg_reentrant_ancillary_mu…
pythongh-143637: Fix re-entrant mutation of ancillary data in socket.…
pythongh-143637: Fix test_socket.test_sendmsg_reentrant_ancillary_mut…
pythongh-143637: Fix re-entrant mutation of ancillary data in socket.…
pythongh-143637: Fix test_socket.test_sendmsg_reentrant_ancillary_mut…