Repository navigation
gh-157579: Fix race condition in the cleanup of tempfile.TemporaryDirectory - #157580
Conversation
This reduces the attack surface -- readable files avoid the race condition.
Co-authored-by: Stan Ulbrych <stan@python.org>
Documentation build overview
18 files changed ·
|
|
I'm not sure why Emscripten failed in this run on The test swaps a directory for a symlink to the outside directory mid-recovery, however the |
|
Will take a look. |
|
Meanwhile let's start buildbots for all the other architectures/configurations |
|
🤖 New build scheduled with the buildbot fleet by @encukou for commit a837624 🤖 Results will be shown at: https://buildbot.python.org/all/#/grid?branch=refs%2Fpull%2F157580%2Fmerge If you want to schedule another build, you need to add the 🔨 test-with-buildbots label again. |
|
And it seems all the buildbots older with masOS <26 (and iOS) are failing on We don't know if the test passes or not, as we don't reach the final assertions. I'm also not quite sure why this happens, and I don't have access to a machine to debug. It's possible that the hook's |
Funny storyI can reproduce! .... on an ancient Intel MacBook that bought it in this state to take macOS screenshots for tutorials. It lasts ~10 min on battery and has a broken screen. It also has only has 1 USB port, so I can charge it, or connect a monitor/LAN, but not both at once. (This was never a problem for screenshots...) So, work is slow. But, in the end, after several tries, I did manage to find a compatible dongle. Turns out that on old macOS, you can't rename a directory if you don't have write permissions on that directory. (On Linux and -- apparently -- new macs, you need write on the containing directory; that has the inode you're manipulating.) The rmtree will:
Back in the test, in the
|
|
Sorry, @StanFromIreland and @encukou, I could not cleanly backport this to |
|
Sorry, @StanFromIreland and @encukou, I could not cleanly backport this to |
|
GH-158429 is a backport of this pull request to the 3.13 branch. |
|
GH-158430 is a backport of this pull request to the 3.14 branch. |
|
GH-158431 is a backport of this pull request to the 3.15 branch. |
|
GH-158489 is a backport of this pull request to the 3.12 branch. |
…raryDirectory (GH-157580) (#158489) * gh-157579: Fix race condition in the cleanup of `tempfile.TemporaryDirectory` (GH-157580) (cherry picked from commit 5c20517) * Add root user checks to test.support This partially backports commit 86b8617 (GH-146195); making existing tests use the helper is omitted. * gh-134993: Add os.lstat() to os.supports_dir_fd (#135188) Co-authored-by: Stan Ulbrych <stan@python.org> Co-authored-by: Victor Stinner <vstinner@python.org> Co-authored-by: Petr Viktorin <encukou@gmail.com>
…1527) Grype matches CVE-2026-12345 (TemporaryDirectory cleanup race, medium) against the python 3.14.8 binary in the base image and lists a fix only in 3.15.0. The fix is merged on main and 3.15 (python/cpython#157580, #158431); the 3.14 backport (python/cpython#158430) is still open. Refs #1412 Signed-off-by: Jürgen Kreileder <jk@blackdown.de>
…oraryDirectory` (GH-157580) (GH-158430) * gh-157579: Fix race condition in the cleanup of `tempfile.TemporaryDirectory` (GH-157580) (cherry picked from commit 5c20517) * Add root user checks to test.support This partially backports commit 86b8617 (GH-146195); making existing tests use the helper is omitted. --------- Co-authored-by: Stan Ulbrych <stan@python.org> Co-authored-by: Petr Viktorin <encukou@gmail.com>
…oraryDirectory` (GH-157580) (#158429) * gh-157579: Fix race condition in the cleanup of `tempfile.TemporaryDirectory` (GH-157580) (cherry picked from commit 5c20517) Co-authored-by: Stan Ulbrych <stan@python.org> Co-authored-by: Petr Viktorin <encukou@gmail.com> * Add root user checks to test.support This partially backports commit 86b8617 (GH-146195); making existing tests use the helper is omitted. * Skip test on Android * Skip other affected test --------- Co-authored-by: Stan Ulbrych <stan@python.org> Co-authored-by: Petr Viktorin <encukou@gmail.com> Co-authored-by: T. Wouters <thomas@python.org>
…oraryDirectory` (GH-157580) (GH-158430) (#159074) * [3.12] gh-157579: Fix race condition in the cleanup of `tempfile.TemporaryDirectory` (GH-157580) (GH-158430) * gh-157579: Fix race condition in the cleanup of `tempfile.TemporaryDirectory` (GH-157580) (cherry picked from commit 5c20517) * Add root user checks to test.support This partially backports commit 86b8617 (GH-146195); making existing tests use the helper is omitted. --------- (cherry picked from commit 58ed025) Co-authored-by: Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> Co-authored-by: Stan Ulbrych <stan@python.org> Co-authored-by: Petr Viktorin <encukou@gmail.com> * gh-134993: Add os.lstat() to os.supports_dir_fd (#135188) --------- Co-authored-by: Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> Co-authored-by: Stan Ulbrych <stan@python.org> Co-authored-by: Victor Stinner <vstinner@python.org>
|
Reminder for the 3.11 backport, or remove the label. |
….TemporaryDirectory (CVE-2026-12345) When TemporaryDirectory cleanup recovers from a PermissionError it resets permissions and retries removal. It did that by resolving paths again, so an attacker who could modify the tree during cleanup could replace a directory with a symlink and make cleanup delete files, or reset their permissions and flags, outside of the temporary directory. Files are now handled relative to the open directory file descriptors that the fd-based shutil.rmtree() walk already holds. Port of the upstream fix (pythonGH-157580, pythonGH-158430), based on the 3.12 backport (python#159074), plus pythongh-134993 (os.lstat in os.supports_dir_fd). 3.10.22.x: the 3.12 fix relies on 3.12's shutil.rmtree() API (onexc, a public dir_fd parameter, and the _onexc_kwargs switch that passes direntry/dir_fd to the callback). 3.10 only has onerror and a recursive _rmtree_safe_fd(), so this adds the private keyword arguments _dir_fd and _onerror_kwargs to rmtree() instead and threads the parent directory fd and os.DirEntry through _rmtree_safe_fd(). With _onerror_kwargs left false, existing onerror callbacks get the same three positional arguments as before. TemporaryDirectory._rmtree() is ported onto the 3.11 shape of the code (bpo-43153 and pythongh-79325 are picked first), using os.lstat(base, dir_fd=...) where 3.12 uses os.path.isdir()/isjunction() on the full path. Tests are adapted: onerror instead of onexc, local root and platform skips instead of support.requires_non_root_user and PY_SUPPORT_TIER. (cherry picked from commit c39b52d) (cherry picked from commit 5c20517) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…TemporaryDirectory (CVE-2026-12345) When TemporaryDirectory cleanup recovers from a PermissionError it resets permissions and retries removal. It did that by resolving paths again, so an attacker who could modify the tree during cleanup could replace a directory with a symlink and make cleanup delete files, or reset their permissions and flags, outside of the temporary directory. Files are now handled relative to the open directory file descriptors that the fd-based shutil.rmtree() walk already holds. Port of the upstream fix (pythonGH-157580, pythonGH-158430), based on the 3.12 backport (python#159074), plus pythongh-134993 (os.lstat in os.supports_dir_fd). 3.10.22.x: the 3.12 fix relies on 3.12's shutil.rmtree() API (onexc, a public dir_fd parameter, and the _onexc_kwargs switch that passes direntry/dir_fd to the callback). 3.10 only has onerror and a recursive _rmtree_safe_fd(), so this adds the private keyword arguments _dir_fd and _onerror_kwargs to rmtree() instead and threads the parent directory fd and os.DirEntry through _rmtree_safe_fd(). With _onerror_kwargs left false, existing onerror callbacks get the same three positional arguments as before. TemporaryDirectory._rmtree() is ported onto the 3.11 shape of the code (bpo-43153 and pythongh-79325 are picked first), using os.lstat(base, dir_fd=...) where 3.12 uses os.path.isdir()/isjunction() on the full path. Tests are adapted: onerror instead of onexc, local root and platform skips instead of support.requires_non_root_user and PY_SUPPORT_TIER. (cherry picked from commit c39b52d) (cherry picked from commit 5c20517) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 776b466) 3.9.25.x: tests use test.support instead of test.support.os_helper, and test_parent_mode_preserved only covers the default (no ignore_errors) case because 3.9's TemporaryDirectory has no ignore_cleanup_errors.
tempfile.TemporaryDirectory#157579