Skip to content

Conversation

@a12k
Copy link
Contributor

@a12k a12k commented Dec 31, 2025

This PR addresses a use-after-free vulnerability in save_picklebuffer in Modules/_pickle.c. The issue occurred when a buffer_callback explicitly released the PickleBuffer while the pickler was still serializing it.

Validation

  • New Tests: Added test_release_in_callback_keepalive and test_release_in_callback_complex_keepalive to Lib/test/test_pickle.py.

Linked issue: gh-128038

@picnixz picnixz self-requested a review December 31, 2025 18:15
@picnixz picnixz changed the title gh-143308: Fix Use-After-Free in _pickle by incrementing PickleBuffer exports gh-143308: fix UAF when PickleBuffer is concurrently mutated in a callback Dec 31, 2025
picnixz
picnixz previously approved these changes Dec 31, 2025
@picnixz
Copy link
Member

picnixz commented Dec 31, 2025

Just a small thing to alter and we're good (good to keep a clickable ref)

@picnixz picnixz added needs backport to 3.14 bugs and security fixes needs backport to 3.13 bugs and security fixes labels Dec 31, 2025
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
@picnixz picnixz dismissed their stale review December 31, 2025 22:31

Waiting until the NEWS entry has been moved.


int rc = 0;
Py_buffer keepalive_view; // to ensure that 'view' is kept alive
if (PyObject_GetBuffer(view->obj, &keepalive_view, PyBUF_FULL_RO) != 0) {
Copy link
Member

Choose a reason for hiding this comment

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

Could not we simply apply PyObject_GetBuffer() to the PickleBuffer object itself? We can then get rid of PyPickleBuffer_GetBuffer().

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Potentially! I'd want to test it. @picnixz what do you think? Since this hasn't been merged yet now would seem to be the time.

Copy link
Member

@picnixz picnixz Jan 3, 2026

Choose a reason for hiding this comment

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

It should work. PyPickleBuffer_GetBuffer just returns a (borrowed) ref so it doesn't get any buffer on it. I think it should work so feel free to check!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This worked great, thanks for the suggestion @serhiy-storchaka. @picnixz The change was a little more involved than expected, but by doing this I was able to remove a redundant view, update all the view-> calls, and the exit: label. All tests pass and confirmed that the patch still holds.

view->len);
if (view.readonly) {
rc = _save_bytes_data(st, self, obj, (const char *)view.buf,
view.len);
Copy link
Member

Choose a reason for hiding this comment

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

Can you vertically align 'view.len' with 'st'? (likewise, some lines below)

Comment on lines 2645 to 2646
"PickleBuffer can not be pickled when "
"pointing to a non-contiguous buffer");
Copy link
Member

Choose a reason for hiding this comment

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

Out of curiosity, but do we have a test for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Neither of the tests added test for non-contiguous, but should be straightforward to add a test against a buffer with strides...

Copy link
Member

Choose a reason for hiding this comment

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

I just wanted to be sure that this branch was covered by existing tests or by other tests. We can increase the coverage in a follow-up PR.

Copy link
Member

@serhiy-storchaka serhiy-storchaka left a comment

Choose a reason for hiding this comment

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

LGTM. 👍

In the following issue we can remove PyPickleBuffer_GetBuffer() and PyPickleBuffer_Release().

@picnixz picnixz merged commit 6c53af1 into python:main Jan 3, 2026
46 checks passed
@miss-islington-app
Copy link

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

miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Jan 3, 2026
… a callback (pythonGH-143312)

(cherry picked from commit 6c53af1)

Co-authored-by: Aaron Wieczorek <aaronw@fastmail.com>
Co-authored-by: Aaron Wieczorek <woz@Aarons-MacBook-Pro.local>
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Jan 3, 2026
… a callback (pythonGH-143312)

(cherry picked from commit 6c53af1)

Co-authored-by: Aaron Wieczorek <aaronw@fastmail.com>
Co-authored-by: Aaron Wieczorek <woz@Aarons-MacBook-Pro.local>
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
@bedevere-app
Copy link

bedevere-app bot commented Jan 3, 2026

GH-143396 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 Jan 3, 2026
@bedevere-app
Copy link

bedevere-app bot commented Jan 3, 2026

GH-143397 is a backport of this pull request to the 3.13 branch.

@bedevere-app bedevere-app bot removed the needs backport to 3.13 bugs and security fixes label Jan 3, 2026
picnixz added a commit that referenced this pull request Jan 3, 2026
…n a callback (GH-143312) (#143396)

gh-143308: fix UAF when PickleBuffer is concurrently mutated in a callback (GH-143312)
(cherry picked from commit 6c53af1)

---------------

Co-authored-by: Aaron Wieczorek <aaronw@fastmail.com>
Co-authored-by: Aaron Wieczorek <woz@Aarons-MacBook-Pro.local>
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
picnixz added a commit that referenced this pull request Jan 3, 2026
…n a callback (GH-143312) (#143397)

gh-143308: fix UAF when PickleBuffer is concurrently mutated in a callback (GH-143312)
(cherry picked from commit 6c53af1)

---------------

Co-authored-by: Aaron Wieczorek <aaronw@fastmail.com>
Co-authored-by: Aaron Wieczorek <woz@Aarons-MacBook-Pro.local>
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants