From 597c6725898705b3b19b96d508379d6bc2acd9c4 Mon Sep 17 00:00:00 2001 From: priyanshu2282-cyber Date: Fri, 16 Jan 2026 02:06:49 +0530 Subject: [PATCH 01/10] socket: fix re-entrant mutation in sendmsg ancillary data --- Modules/socketmodule.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 1ef359cb265ed4..62af80f9ab2262 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -5001,15 +5001,27 @@ _socket_socket_sendmsg_impl(PySocketSockObject *s, PyObject *data_arg, controllen = controllen_last = 0; while (ncmsgbufs < ncmsgs) { size_t bufsize, space; + PyObject *item; - if (!PyArg_Parse(PySequence_Fast_GET_ITEM(cmsg_fast, ncmsgbufs), + item = PySequence_Fast_GET_ITEM(cmsg_fast, ncmsgbufs); + Py_INCREF(item); + + if (!PyArg_Parse(item, "(iiy*):[sendmsg() ancillary data items]", &cmsgs[ncmsgbufs].level, &cmsgs[ncmsgbufs].type, &cmsgs[ncmsgbufs].data)) + Py_DECREF(item); goto finally; + Py_DECREF(item); bufsize = cmsgs[ncmsgbufs++].data.len; - + space=CMSG_SPACE(bufsize); + if(space>maxcmsgslen){ + PyErr_SetString(PyExc_OSError, "ancillary data item too large"); + goto finally; + } + maxcmsgslen+=space; + } #ifdef CMSG_SPACE if (!get_CMSG_SPACE(bufsize, &space)) { #else From 7e57097b1b0827c47726b7f763831ce360cfb5a0 Mon Sep 17 00:00:00 2001 From: priyanshu2282-cyber Date: Fri, 16 Jan 2026 02:07:14 +0530 Subject: [PATCH 02/10] test_socket: add regression test for sendmsg re-entrancy --- Lib/test/test_socket.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 934b7137096bc0..787425edd3d991 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -3572,6 +3572,33 @@ def _testSendmsgAfterClose(self): class SendmsgStreamTests(SendmsgTests): # Tests for sendmsg() which require a stream socket and do not # involve recvmsg() or recvmsg_into(). + @unittest.skipUnless(hasattr(socket.socket, "sendmsg"), + "sendmsg not supported") + def _test_sendmsg_reentrant_ancillary_mutation(self): + 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() + self.addCleanup(left.close) + self.addCleanup(right.close) + + with self.assertRaises(Exception): + left.sendmsg([b'x'], seq) def testSendmsgExplicitNoneAddr(self): # Check that peer address can be specified as None. From a6fbd4b1889f6312c01f89fc2bd45683db3d14e4 Mon Sep 17 00:00:00 2001 From: priyanshu2282-cyber Date: Fri, 16 Jan 2026 02:42:21 +0530 Subject: [PATCH 03/10] gh-143637: Fix reentrant mutation crash in socket.sendmsg --- Lib/test/test_socket.py | 2 +- Modules/socketmodule.c | 26 +++++++++----------------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 787425edd3d991..14dd0f6483eeec 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -3596,7 +3596,7 @@ def __index__(self): left, right = socket.socketpair() self.addCleanup(left.close) self.addCleanup(right.close) - + with self.assertRaises(Exception): left.sendmsg([b'x'], seq) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 62af80f9ab2262..39d4058d998432 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -5007,30 +5007,22 @@ _socket_socket_sendmsg_impl(PySocketSockObject *s, PyObject *data_arg, Py_INCREF(item); if (!PyArg_Parse(item, - "(iiy*):[sendmsg() ancillary data items]", - &cmsgs[ncmsgbufs].level, - &cmsgs[ncmsgbufs].type, - &cmsgs[ncmsgbufs].data)) + "(iiy*):[sendmsg() ancillary data items]", + &cmsgs[ncmsgbufs].level, + &cmsgs[ncmsgbufs].type, + &cmsgs[ncmsgbufs].data)){ Py_DECREF(item); goto finally; + } Py_DECREF(item); + bufsize = cmsgs[ncmsgbufs++].data.len; - space=CMSG_SPACE(bufsize); - if(space>maxcmsgslen){ - PyErr_SetString(PyExc_OSError, "ancillary data item too large"); - goto finally; - } - maxcmsgslen+=space; - } -#ifdef CMSG_SPACE - if (!get_CMSG_SPACE(bufsize, &space)) { -#else - if (!get_CMSG_LEN(bufsize, &space)) { -#endif + + if(!get_CMSG_SPACE(bufsize, &space)){ PyErr_SetString(PyExc_OSError, "ancillary data item too large"); goto finally; } - controllen += space; + controllen+=space; if (controllen > SOCKLEN_T_LIMIT || controllen < controllen_last) { PyErr_SetString(PyExc_OSError, "too much ancillary data"); goto finally; From be7371d2f8ba2bb2c0eae7cbd254db46ba832026 Mon Sep 17 00:00:00 2001 From: priyanshu2282-cyber Date: Fri, 16 Jan 2026 21:59:37 +0530 Subject: [PATCH 04/10] chore: rerun CI From 4703c2b974ff81966ee3e443816a19f83d56e4fd Mon Sep 17 00:00:00 2001 From: priyanshu2282-cyber Date: Sat, 17 Jan 2026 14:06:04 +0530 Subject: [PATCH 05/10] restore spacing style for controllen calculation --- Modules/socketmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 39d4058d998432..952c3a90321c1b 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -5022,7 +5022,7 @@ _socket_socket_sendmsg_impl(PySocketSockObject *s, PyObject *data_arg, PyErr_SetString(PyExc_OSError, "ancillary data item too large"); goto finally; } - controllen+=space; + controllen += space; if (controllen > SOCKLEN_T_LIMIT || controllen < controllen_last) { PyErr_SetString(PyExc_OSError, "too much ancillary data"); goto finally; From 2bd7e14d75e20f5487b2e8a48c484d3c241d862e Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sat, 17 Jan 2026 08:44:26 +0000 Subject: [PATCH 06/10] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2026-01-17-08-44-25.gh-issue-143637.qyPqDo.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2026-01-17-08-44-25.gh-issue-143637.qyPqDo.rst diff --git a/Misc/NEWS.d/next/Library/2026-01-17-08-44-25.gh-issue-143637.qyPqDo.rst b/Misc/NEWS.d/next/Library/2026-01-17-08-44-25.gh-issue-143637.qyPqDo.rst new file mode 100644 index 00000000000000..cbb21194d5b387 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-17-08-44-25.gh-issue-143637.qyPqDo.rst @@ -0,0 +1 @@ +Fixed a crash in socket.sendmsg() that could occur if ancillary data is mutated re-entrantly during argument parsing. From 710daaad77fe6e74c5c0633ea2f692d4fd42d53c Mon Sep 17 00:00:00 2001 From: priyanshu2282-cyber Date: Sat, 17 Jan 2026 21:27:32 +0530 Subject: [PATCH 07/10] add public wrapper for sendmsg re-entrant ancillary mutation test --- Lib/test/test_socket.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 14dd0f6483eeec..1cda075e80293c 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -3572,8 +3572,12 @@ def _testSendmsgAfterClose(self): class SendmsgStreamTests(SendmsgTests): # Tests for sendmsg() which require a stream socket and do not # involve recvmsg() or recvmsg_into(). + @unittest.skipUnless(hasattr(socket.socket, "sendmsg"), "sendmsg not supported") + def test_sendmsg_reentrant_ancillary_mutation(self): + self._test_sendmsg_reentrant_ancillary_mutation() + def _test_sendmsg_reentrant_ancillary_mutation(self): import socket From 75d8ae9f74b286bdaf5872b714cc0ea15c96284f Mon Sep 17 00:00:00 2001 From: priyanshu2282-cyber Date: Sat, 17 Jan 2026 21:57:06 +0530 Subject: [PATCH 08/10] fixed trailing whitespace --- Lib/test/test_socket.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 1cda075e80293c..eb208c1a40826b 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -3572,12 +3572,12 @@ def _testSendmsgAfterClose(self): class SendmsgStreamTests(SendmsgTests): # Tests for sendmsg() which require a stream socket and do not # involve recvmsg() or recvmsg_into(). - + @unittest.skipUnless(hasattr(socket.socket, "sendmsg"), "sendmsg not supported") def test_sendmsg_reentrant_ancillary_mutation(self): self._test_sendmsg_reentrant_ancillary_mutation() - + def _test_sendmsg_reentrant_ancillary_mutation(self): import socket From 6f0ddf4bd22b7aa5bbb373610441a8f57c5ba784 Mon Sep 17 00:00:00 2001 From: priyanshu2282-cyber Date: Sun, 18 Jan 2026 00:41:20 +0530 Subject: [PATCH 09/10] PySequence_Tuple instead of PySequence_Fast and removed INCREF, DECREF --- Lib/test/test_socket.py | 10 +++++++--- Modules/socketmodule.c | 15 +++++++-------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index eb208c1a40826b..cb2d66bece5a3f 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -3577,7 +3577,7 @@ class SendmsgStreamTests(SendmsgTests): "sendmsg not supported") def test_sendmsg_reentrant_ancillary_mutation(self): self._test_sendmsg_reentrant_ancillary_mutation() - + def _test_sendmsg_reentrant_ancillary_mutation(self): import socket @@ -3601,8 +3601,12 @@ def __index__(self): self.addCleanup(left.close) self.addCleanup(right.close) - with self.assertRaises(Exception): - left.sendmsg([b'x'], seq) + self.assertRaises( + (TypeError, OSError), + left.sendmsg, + [b'x'], + seq, + ) def testSendmsgExplicitNoneAddr(self): # Check that peer address can be specified as None. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 952c3a90321c1b..ad93f9a3a0ed5a 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -4977,11 +4977,13 @@ _socket_socket_sendmsg_impl(PySocketSockObject *s, PyObject *data_arg, if (cmsg_arg == NULL) ncmsgs = 0; else { - if ((cmsg_fast = PySequence_Fast(cmsg_arg, - "sendmsg() argument 2 must be an " - "iterable")) == NULL) + cmsg_fast = PySequence_Tuple(cmsg_arg); + if (cmsg_fast == NULL) { + PyErr_SetString(PyExc_TypeError, + "sendmsg() argument 2 must be an iterable"); goto finally; - ncmsgs = PySequence_Fast_GET_SIZE(cmsg_fast); + } + ncmsgs = PyTuple_GET_SIZE(cmsg_fast); } #ifndef CMSG_SPACE @@ -5003,18 +5005,15 @@ _socket_socket_sendmsg_impl(PySocketSockObject *s, PyObject *data_arg, size_t bufsize, space; PyObject *item; - item = PySequence_Fast_GET_ITEM(cmsg_fast, ncmsgbufs); - Py_INCREF(item); + item = PyTuple_GET_ITEM(cmsg_fast, ncmsgbufs); if (!PyArg_Parse(item, "(iiy*):[sendmsg() ancillary data items]", &cmsgs[ncmsgbufs].level, &cmsgs[ncmsgbufs].type, &cmsgs[ncmsgbufs].data)){ - Py_DECREF(item); goto finally; } - Py_DECREF(item); bufsize = cmsgs[ncmsgbufs++].data.len; From ff8af984921d504424d48260e1fb3cedfac6d098 Mon Sep 17 00:00:00 2001 From: priyanshu2282-cyber Date: Sun, 18 Jan 2026 00:57:37 +0530 Subject: [PATCH 10/10] Fix trailing whitespace --- Lib/test/test_socket.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index cb2d66bece5a3f..670066e4603233 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -3577,7 +3577,7 @@ class SendmsgStreamTests(SendmsgTests): "sendmsg not supported") def test_sendmsg_reentrant_ancillary_mutation(self): self._test_sendmsg_reentrant_ancillary_mutation() - + def _test_sendmsg_reentrant_ancillary_mutation(self): import socket