gh-149509: Fix posix_spawn heap corruption when environ is mutated during the call#149724
Open
1fanwang wants to merge 1 commit into
Open
gh-149509: Fix posix_spawn heap corruption when environ is mutated during the call#1497241fanwang wants to merge 1 commit into
1fanwang wants to merge 1 commit into
Conversation
…-call When env is None, py_posix_spawn aliases the global C environ array into envlist without copying it, but envc is left uninitialised. The cleanup block decided whether to free envlist by comparing it against environ. If something running during the call (an LD_PRELOAD interposer such as gprofng, or an audit hook that ends up modifying the environment) replaces environ with a different pointer, the identity check would mis-classify the borrowed pointer as owned and free it with the uninitialised envc, corrupting the process environment and typically crashing. Track ownership explicitly with an envlist_owned flag instead of inferring it from a pointer identity check, and initialise envc to 0. The regression test simulates the interposer using a sys audit hook that swaps environ via ctypes between argument parsing and the cleanup path.
picnixz
reviewed
May 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #149509.
When
os.posix_spawn(..., env=None)is called and the global Cenvironis replaced between the argv parsing and the cleanup branch — by anLD_PRELOADinterposer (the original report came from gprofng), an audit hook, or anything else — theif (envlist != environ)cleanup test misfires. The originalenvironpointer was captured byparse_envlist, the newenvirondoesn't match, so the cleanup treats the borrowedenvlistas an owned heap allocation._Py_FREELIST_FREEthen walks pastenvc(which the borrow path leaves uninitialised), corrupting the heap and crashing the interpreter.The fix tracks ownership explicitly. An
envlist_ownedflag is set only on the path that callsparse_envlist(which mallocs). The cleanup runs only when that flag is set, and the matchingenvcinitialisation is moved up so the cleanup loop always has a defined upper bound.Tests
Lib/test/test_os/test_posix.py::_PosixSpawnMixin::test_env_none_with_environ_mutated_during_callreproduces the bug in anassert_python_oksubprocess so the environ swap stays isolated. The subprocess installs asys.addaudithookthat — whenos.posix_spawnfires — usesctypes.c_void_p.in_dll(libc, 'environ')to pointenvironat an empty replacement array, then calls the spawn, then restores. Because_PosixSpawnMixinis inherited by bothPosixSpawnTestsandPosixSpawnPTests, the test coversposix_spawnandposix_spawnp.The test aborts the interpreter on
mainwithDebug memory block ... pad bytes are not all FORBIDDENBYTE(exit 139). With this PR it passes.NEWS
Misc/NEWS.d/next/Library/2026-05-12-07-01-29.gh-issue-149509.WwKxjE.rst.