Skip to content

gh-148660: Fix use-after-free in OrderedDict.copy() on reentrant mutation#151573

Merged
gpshead merged 2 commits into
python:mainfrom
gpshead:gh-148660-odict-copy-uaf-minimal
Jun 29, 2026
Merged

gh-148660: Fix use-after-free in OrderedDict.copy() on reentrant mutation#151573
gpshead merged 2 commits into
python:mainfrom
gpshead:gh-148660-odict-copy-uaf-minimal

Conversation

@gpshead

@gpshead gpshead commented Jun 17, 2026

Copy link
Copy Markdown
Member

OrderedDict.copy() walks the internal linked list while building the new dict. The loop body can run arbitrary Python (a key's __eq__/__hash__, or a subclass __getitem__/__setitem__) which can clear the source dict and free the nodes being iterated.

Detect this the same way OrderedDict.__eq__ already does (gh-119004): snapshot od_state before the loop, hold a strong reference to the key and read the hash before any reentrant call, and raise RuntimeError if the state changed before advancing to the next node.

…t mutation

OrderedDict.copy() walks the internal linked list while building the new
dict. The loop body can run arbitrary Python (a key's __eq__/__hash__, or
a subclass __getitem__/__setitem__) which can clear the source dict and
free the nodes being iterated.

Detect this the same way OrderedDict.__eq__ already does (pythongh-119004):
snapshot od_state before the loop, hold a strong reference to the key and
read the hash before any reentrant call, and raise RuntimeError if the
state changed before advancing to the next node.
@gpshead gpshead 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 17, 2026
@gpshead gpshead self-assigned this Jun 17, 2026
@gpshead gpshead merged commit 7d128e3 into python:main Jun 29, 2026
54 checks passed
@miss-islington-app

Copy link
Copy Markdown

Thanks @gpshead for the PR 🌮🎉.. I'm working now to backport this PR to: 3.13, 3.14, 3.15.
🐍🍒⛏🤖

@bedevere-app

bedevere-app Bot commented Jun 29, 2026

Copy link
Copy Markdown

GH-152540 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 29, 2026
@miss-islington-app

Copy link
Copy Markdown

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

cherry_picker 7d128e319f3730e776a9161a4b5e9de95c802eaf 3.13

@bedevere-app

bedevere-app Bot commented Jun 29, 2026

Copy link
Copy Markdown

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

@bedevere-app

bedevere-app Bot commented Jun 29, 2026

Copy link
Copy Markdown

GH-152542 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 Jun 29, 2026
gpshead added a commit that referenced this pull request Jun 29, 2026
…nt mutation (GH-151573) (#152541)

gh-148660: Fix use-after-free in OrderedDict.copy() on reentrant mutation (GH-151573)

* gh-148660: Fix use-after-free in OrderedDict.copy() on reentrant mutation

OrderedDict.copy() walks the internal linked list while building the new
dict. The loop body can run arbitrary Python (a key's __eq__/__hash__, or
a subclass __getitem__/__setitem__) which can clear the source dict and
free the nodes being iterated.

Detect this the same way OrderedDict.__eq__ already does (gh-119004):
snapshot od_state before the loop, hold a strong reference to the key and
read the hash before any reentrant call, and raise RuntimeError if the
state changed before advancing to the next node.

* gh-148660: fix NEWS nit, suppress undocumented OrderedDict.copy xref
(cherry picked from commit 7d128e3)

Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com>
gpshead added a commit that referenced this pull request Jun 29, 2026
…nt mutation (GH-151573) (#152540)

gh-148660: Fix use-after-free in OrderedDict.copy() on reentrant mutation (GH-151573)

* gh-148660: Fix use-after-free in OrderedDict.copy() on reentrant mutation

OrderedDict.copy() walks the internal linked list while building the new
dict. The loop body can run arbitrary Python (a key's __eq__/__hash__, or
a subclass __getitem__/__setitem__) which can clear the source dict and
free the nodes being iterated.

Detect this the same way OrderedDict.__eq__ already does (gh-119004):
snapshot od_state before the loop, hold a strong reference to the key and
read the hash before any reentrant call, and raise RuntimeError if the
state changed before advancing to the next node.

* gh-148660: fix NEWS nit, suppress undocumented OrderedDict.copy xref
(cherry picked from commit 7d128e3)

Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com>
gpshead added a commit that referenced this pull request Jun 29, 2026
…nt mutation (GH-151573) (#152542)

OrderedDict.copy() walks the internal linked list while building the new
dict. The loop body can run arbitrary Python (a key's __eq__/__hash__, or
a subclass __getitem__/__setitem__) which can clear the source dict and
free the nodes being iterated.

Detect this the same way OrderedDict.__eq__ already does (gh-119004):
snapshot od_state before the loop, hold a strong reference to the key and
read the hash before any reentrant call, and raise RuntimeError if the
state changed before advancing to the next node.

(cherry picked from commit 7d128e3)
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.

1 participant