Skip to content

gh-143988: Fix re-entrant mutation crashes in socket sendmsg/recvmsg_into via __buffer__#143987

Merged
vstinner merged 10 commits into
python:mainfrom
tonghuaroot:fix-socket-reentrant-mutation
Jun 10, 2026
Merged

gh-143988: Fix re-entrant mutation crashes in socket sendmsg/recvmsg_into via __buffer__#143987
vstinner merged 10 commits into
python:mainfrom
tonghuaroot:fix-socket-reentrant-mutation

Conversation

@tonghuaroot

@tonghuaroot tonghuaroot commented Jan 18, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR fixes two heap out-of-bounds read vulnerabilities in socket.sendmsg() and socket.recvmsg_into() that are related to gh-143637.

While gh-143637 addresses the __index__ re-entrancy issue in sendmsg() ancillary data parsing (argument 2), there are two additional vulnerable code paths that use the __buffer__ protocol:

  1. socket.sendmsg() argument 1 (data buffers) - in sock_sendmsg_iovec()
  2. socket.recvmsg_into() argument 1 (buffers) - in sock_recvmsg_into()

Root Cause

The vulnerability occurs because:

  1. PySequence_Fast() returns the original list object when the input is already a list (not a copy)
  2. During iteration, PyObject_GetBuffer() triggers __buffer__ protocol callbacks which may clear the list
  3. Subsequent iterations access invalid memory (heap OOB read), leading to a crash (SIGSEGV)

Proof of Concept

sendmsg() data buffers crash:

import socket

seq = []

class MutBuffer:
    def __init__(self, data):
        self._data = bytes(data)
        self.tripped = False
    
    def __buffer__(self, flags):
        if not self.tripped:
            self.tripped = True
            seq.clear()  # Clear during iteration!
        return memoryview(self._data)

seq[:] = [MutBuffer(b'Hello'), b'World', b'Test']
left, right = socket.socketpair()
left.sendmsg(seq)  # CRASH: SIGSEGV

recvmsg_into() buffers crash:

import socket

seq = []

class MutBuffer:
    def __init__(self, data):
        self._data = bytearray(data)
        self.tripped = False
    
    def __buffer__(self, flags):
        if not self.tripped:
            self.tripped = True
            seq.clear()  # Clear during iteration!
        return memoryview(self._data)

seq[:] = [MutBuffer(b'x' * 100), bytearray(100), bytearray(100)]
left, right = socket.socketpair()
left.send(b'Hello World!')
right.recvmsg_into(seq)  # CRASH: SIGSEGV

Fix

Replace PySequence_Fast() with PySequence_Tuple() which always creates a new tuple, ensuring the sequence cannot be mutated during iteration.

Testing

Added Lib/test/test_socket_reentrant.py with regression tests for both vulnerable code paths.


Note: This is related to but separate from PR #143892 which fixes the __index__ issue.

@tonghuaroot tonghuaroot changed the title Fix re-entrant mutation crashes in socket sendmsg/recvmsg_into via __buffer__ gh-143988: tation crashes in socket sendmsg/recvmsg_into via __buffer__ Jan 18, 2026
@tonghuaroot tonghuaroot force-pushed the fix-socket-reentrant-mutation branch from 333ee07 to 78c18ed Compare January 18, 2026 06:58
Comment thread Lib/test/test_socket_reentrant.py Outdated
@bedevere-app

bedevere-app Bot commented Jan 18, 2026

Copy link
Copy Markdown

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

And if you don't make the requested changes, you will be poked with soft cushions!

@tonghuaroot tonghuaroot force-pushed the fix-socket-reentrant-mutation branch from 78c18ed to 42ad743 Compare January 19, 2026 02:21
@tonghuaroot

Copy link
Copy Markdown
Contributor Author

I have made the requested changes; please review again.

@bedevere-app

bedevere-app Bot commented Jan 19, 2026

Copy link
Copy Markdown

Thanks for making the requested changes!

@picnixz: please review the changes made to this pull request.

@bedevere-app bedevere-app Bot requested a review from picnixz January 19, 2026 02:26
Comment thread Lib/test/test_socket.py Outdated
Comment thread Lib/test/test_socket.py Outdated
Comment thread Lib/test/test_socket.py Outdated
Comment thread Lib/test/test_socket.py
Comment thread Lib/test/test_socket.py Outdated
@bedevere-app

bedevere-app Bot commented Jan 19, 2026

Copy link
Copy Markdown

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@picnixz

picnixz commented Jan 19, 2026

Copy link
Copy Markdown
Member

Please read the devguide:

  • Do not forcepush.
  • Do not hit the "update branch" button if there is no need to (that is, if the CI is already green for the tests). it wastes resources and notifies everyone..

@tonghuaroot tonghuaroot force-pushed the fix-socket-reentrant-mutation branch 2 times, most recently from 720a086 to 4b592ef Compare January 19, 2026 02:41
…cvmsg_into via __buffer__

Fix crashes in socket.sendmsg() and socket.recvmsg_into() that could
occur if buffer sequences are mutated re-entrantly during argument
parsing via __buffer__ protocol callbacks.

The vulnerability occurs because:
1. PySequence_Fast() returns the original list object when the input
   is already a list (not a copy)
2. During iteration, PyObject_GetBuffer() triggers __buffer__
   callbacks which may clear the list
3. Subsequent iterations access invalid memory (heap OOB read)

The fix replaces PySequence_Fast() with PySequence_Tuple() which
always creates a new tuple, ensuring the sequence cannot be mutated
during iteration.

This addresses two vulnerabilities related to pythongh-143637:
- sendmsg() argument 1 (data buffers) - via __buffer__
- recvmsg_into() argument 1 (buffers) - via __buffer__
@tonghuaroot tonghuaroot force-pushed the fix-socket-reentrant-mutation branch from 4b592ef to 2c8aad6 Compare January 19, 2026 02:43
@tonghuaroot

Copy link
Copy Markdown
Contributor Author

Please read the devguide:

  • Do not forcepush.
  • Do not hit the "update branch" button if there is no need to (that is, if the CI is already green for the tests). it wastes resources and notifies everyone..

Sorry about the force pushes - I'll use regular commits going forward. Thanks for the reminder about the devguide.

@tonghuaroot

Copy link
Copy Markdown
Contributor Author

I have made the requested changes; please review again.

@bedevere-app

bedevere-app Bot commented Jan 19, 2026

Copy link
Copy Markdown

Thanks for making the requested changes!

@picnixz: please review the changes made to this pull request.

@bedevere-app bedevere-app Bot requested a review from picnixz January 19, 2026 02:54
Comment thread Lib/test/test_socket.py Outdated
Comment thread Lib/test/test_socket.py Outdated
@@ -0,0 +1,3 @@
Fixed crashes in :meth:`socket.socket.sendmsg` and :meth:`socket.socket.recvmsg_into`
that could occur if buffer sequences are mutated re-entrantly during argument parsing

@picnixz picnixz Jan 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that could occur if buffer sequences are concurrently mutated
  • Remove argument parsing mention. It is an implementation detail.
  • We do not really use the term re-entrency. I do not share the definition of re-entrency and prefer using concurrently here (you do two things at the same time)

Comment thread Modules/socketmodule.c Outdated

@vstinner vstinner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Remaining comments are minor issues.

Comment thread Modules/socketmodule.c Outdated
Comment thread Lib/test/test_socket.py Outdated
@vstinner

Copy link
Copy Markdown
Member

The "Tests / Docs / Docs (pull_request)" CI failed with:

python: can't open file '/home/runner/work/cpython/cpython/Doc/tools/check-html-ids.py': [Errno 2] No such file or directory

@vstinner prefers the original name; revert the rename and keep the diff
minimal.
…WS to Library

- Rename sock_recvmsg_into's fast to buffers_tuple (per @vstinner).
- Trim ReentrantMutationTests docstring to fit 80 columns.
- This is a crash-robustness fix, not a security vulnerability; move the
  NEWS entry from Security/ to Library/.
@tonghuaroot

Copy link
Copy Markdown
Contributor Author

Thanks @vstinner! Addressed all three:

  • Renamed fast to buffers_tuple in sock_recvmsg_into.
  • Trimmed the ReentrantMutationTests docstring to fit 80 columns.
  • Moved the NEWS entry from Security/ to Library/ — agreed this is a crash-robustness fix rather than a security vulnerability.

The failing Docs (pull_request) job looks unrelated to this change: it errors on a missing Doc/tools/check-html-ids.py on the runner, while this PR only touches socketmodule.c, test_socket.py, and the NEWS entry.

@vstinner

Copy link
Copy Markdown
Member

@picnixz: Would you mind to review the updated PR? It seems like 2 of your comments were not addressed yet.

Comment thread Modules/socketmodule.c
@picnixz

picnixz commented Jun 10, 2026

Copy link
Copy Markdown
Member

I think the docs issue is because of the branch not being up-to-date. You can hit the "Update branch" button to merge main into this branch (just don't force push)

@vstinner vstinner enabled auto-merge (squash) June 10, 2026 12:36
@vstinner vstinner merged commit 896f7fd into python:main Jun 10, 2026
54 checks passed
@vstinner vstinner added needs backport to 3.13 bugs and security fixes needs backport to 3.14 bugs and security fixes needs backport to 3.15 pre-release feature fixes, bugs and security fixes labels Jun 10, 2026
@miss-islington-app

Copy link
Copy Markdown

Thanks @tonghuaroot for the PR, and @vstinner for merging it 🌮🎉.. I'm working now to backport this PR to: 3.13.
🐍🍒⛏🤖

@miss-islington-app

Copy link
Copy Markdown

Thanks @tonghuaroot for the PR, and @vstinner for merging it 🌮🎉.. I'm working now to backport this PR to: 3.15.
🐍🍒⛏🤖

@miss-islington-app

Copy link
Copy Markdown

Thanks @tonghuaroot for the PR, and @vstinner for merging it 🌮🎉.. I'm working now to backport this PR to: 3.14.
🐍🍒⛏🤖

@miss-islington-app

Copy link
Copy Markdown

Sorry, @tonghuaroot and @vstinner, I could not cleanly backport this to 3.14 due to a conflict.
Please backport using cherry_picker on command line.

cherry_picker 896f7fdc7d0ba6d4ace06935b9d67c4da0f9ecbe 3.14

@miss-islington-app

Copy link
Copy Markdown

Sorry, @tonghuaroot and @vstinner, I could not cleanly backport this to 3.13 due to a conflict.
Please backport using cherry_picker on command line.

cherry_picker 896f7fdc7d0ba6d4ace06935b9d67c4da0f9ecbe 3.13

@bedevere-app

bedevere-app Bot commented Jun 10, 2026

Copy link
Copy Markdown

GH-151246 is a backport of this pull request to the 3.15 branch.

@bedevere-app bedevere-app Bot removed the needs backport to 3.15 pre-release feature fixes, bugs and security fixes label Jun 10, 2026
vstinner pushed a commit to vstinner/cpython that referenced this pull request Jun 10, 2026
…cvmsg_into (python#143987)

Fix crashes in socket.sendmsg() and socket.recvmsg_into() that could
occur if buffer sequences are mutated re-entrantly during argument
parsing via __buffer__ protocol callbacks.

The bug occurs because:

1. PySequence_Fast() returns the original list object when the input
   is already a list (not a copy).
2. During iteration, PyObject_GetBuffer() triggers __buffer__
   callbacks which may clear the list.
3. Subsequent iterations access invalid memory (heap OOB read).

The fix replaces PySequence_Fast() with PySequence_Tuple() which
always creates a new tuple, ensuring the sequence cannot be mutated
during iteration.

Co-authored-by: tonghuaroot <23011166+tonghuaroot@users.noreply.github.com>
(cherry picked from commit 896f7fd)
@bedevere-app

bedevere-app Bot commented Jun 10, 2026

Copy link
Copy Markdown

GH-151251 is a backport of this pull request to the 3.14 branch.

@bedevere-app bedevere-app Bot removed the needs backport to 3.14 bugs and security fixes label Jun 10, 2026
@vstinner

Copy link
Copy Markdown
Member

Merged, thanks for your fix. I backport the change to 3.14 and 3.15 branches. (The 3.14 backport will be backported to 3.13 once it will be merged.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs backport to 3.13 bugs and security fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants