Skip to content

gh-157265: Honor None result of filter for link fallbacks - #157266

Merged
encukou merged 3 commits into
python:mainfrom
encukou:tarfile-hardlink-none
Sep 11, 2026
Merged

encukou merged 3 commits into
python:mainfrom
encukou:tarfile-hardlink-none

Conversation

@encukou

@encukou encukou commented Sep 10, 2026 •

Copy link
Copy Markdown
Member

@encukou
encukou merged commit fb2f0bb into python:main Sep 11, 2026
60 checks passed
@encukou
encukou deleted the tarfile-hardlink-none branch September 11, 2026 12:19
@encukou encukou added needs backport to 3.10 only security fixes needs backport to 3.11 only security fixes needs backport to 3.12 only security fixes 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 Sep 11, 2026
@miss-islington-app

Copy link
Copy Markdown

Thanks @encukou for the PR 🌮🎉.. I'm working now to backport this PR to: 3.10.
🐍🍒⛏🤖

@miss-islington-app

Copy link
Copy Markdown

Thanks @encukou for the PR 🌮🎉.. I'm working now to backport this PR to: 3.12.
🐍🍒⛏🤖

@miss-islington-app

Copy link
Copy Markdown

Thanks @encukou for the PR 🌮🎉.. I'm working now to backport this PR to: 3.11.
🐍🍒⛏🤖

@miss-islington-app

Copy link
Copy Markdown

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

@miss-islington-app

Copy link
Copy Markdown

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

@miss-islington-app

Copy link
Copy Markdown

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

@bedevere-app

bedevere-app Bot commented Sep 11, 2026

Copy link
Copy Markdown

GH-157304 is a backport of this pull request to the 3.10 branch.

@bedevere-app bedevere-app Bot removed the needs backport to 3.10 only security fixes label Sep 11, 2026
@bedevere-app

bedevere-app Bot commented Sep 11, 2026

Copy link
Copy Markdown

GH-157305 is a backport of this pull request to the 3.12 branch.

@bedevere-app bedevere-app Bot removed the needs backport to 3.12 only security fixes label Sep 11, 2026
@bedevere-app

bedevere-app Bot commented Sep 11, 2026

Copy link
Copy Markdown

GH-157306 is a backport of this pull request to the 3.11 branch.

@bedevere-app bedevere-app Bot removed the needs backport to 3.11 only security fixes label Sep 11, 2026
@bedevere-app

bedevere-app Bot commented Sep 11, 2026

Copy link
Copy Markdown

GH-157307 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 Sep 11, 2026
@bedevere-app

bedevere-app Bot commented Sep 11, 2026

Copy link
Copy Markdown

GH-157308 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 Sep 11, 2026
@bedevere-app

bedevere-app Bot commented Sep 11, 2026

Copy link
Copy Markdown

GH-157309 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 Sep 11, 2026
@bedevere-bot

Copy link
Copy Markdown

⚠️⚠️⚠️ Buildbot failure ⚠️⚠️⚠️

Hi! The buildbot AMD64 Debian root 3.x (tier-1) has failed when building commit fb2f0bb.

What do you need to do:

  1. Don't panic.
  2. Check the buildbot page in the devguide if you don't know what the buildbots are or how they work.
  3. Go to the page of the buildbot that failed (https://buildbot.python.org/#/builders/345/builds/15324) and take a look at the build logs.
  4. Check if the failure is related to this commit (fb2f0bb) or if it is a false positive.
  5. If the failure is related to this commit, please, reflect that on the issue and make a new Pull Request with a fix.

You can take a look at the buildbot page here:

https://buildbot.python.org/#/builders/345/builds/15324

Failed tests:

  • test.test_multiprocessing_fork.test_processes

Failed subtests:

  • test_interrupt - test.test_multiprocessing_fork.test_processes.WithProcessesTestProcess.test_interrupt

Summary of the results of the build (if available):

==

Click to see traceback logs
Traceback (most recent call last):
  File "/root/buildarea/3.x.angelico-debian-amd64/build/Lib/contextlib.py", line 116, in inner
    return func(*args, **kwds)
  File "/root/buildarea/3.x.angelico-debian-amd64/build/Lib/test/_test_multiprocessing.py", line 651, in test_interrupt
    exitcode = self._kill_process(multiprocessing.Process.interrupt)
  File "/root/buildarea/3.x.angelico-debian-amd64/build/Lib/contextlib.py", line 116, in inner
    return func(*args, **kwds)
  File "/root/buildarea/3.x.angelico-debian-amd64/build/Lib/test/_test_multiprocessing.py", line 632, in _kill_process
    self.assertEqual(join(), None)
                     ~~~~^^
  File "/root/buildarea/3.x.angelico-debian-amd64/build/Lib/test/_test_multiprocessing.py", line 305, in __call__
    return self.func(*args, **kwds)
           ~~~~~~~~~^^^^^^^^^^^^^^^
  File "/root/buildarea/3.x.angelico-debian-amd64/build/Lib/multiprocessing/process.py", line 156, in join
    res = self._popen.wait(timeout)
  File "/root/buildarea/3.x.angelico-debian-amd64/build/Lib/multiprocessing/popen_fork.py", line 44, in wait
    return self.poll(os.WNOHANG if timeout == 0.0 else 0)
           ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/root/buildarea/3.x.angelico-debian-amd64/build/Lib/multiprocessing/popen_fork.py", line 28, in poll
    pid, sts = os.waitpid(self.pid, flag)
               ~~~~~~~~~~^^^^^^^^^^^^^^^^
  File "/root/buildarea/3.x.angelico-debian-amd64/build/Lib/test/_test_multiprocessing.py", line 628, in handler
    raise RuntimeError('join took too long: %s' % p)
RuntimeError: join took too long: <Process name='Process-1' pid=3460618 parent=3460616 started daemon>


Traceback (most recent call last):
  File "/root/buildarea/3.x.angelico-debian-amd64/build/Lib/contextlib.py", line 116, in inner
    return func(*args, **kwds)
  File "/root/buildarea/3.x.angelico-debian-amd64/build/Lib/test/_test_multiprocessing.py", line 651, in test_interrupt
    exitcode = self._kill_process(multiprocessing.Process.interrupt)
  File "/root/buildarea/3.x.angelico-debian-amd64/build/Lib/contextlib.py", line 116, in inner
    return func(*args, **kwds)
  File "/root/buildarea/3.x.angelico-debian-amd64/build/Lib/test/_test_multiprocessing.py", line 632, in _kill_process
    self.assertEqual(join(), None)
                     ~~~~^^
  File "/root/buildarea/3.x.angelico-debian-amd64/build/Lib/test/_test_multiprocessing.py", line 305, in __call__
    return self.func(*args, **kwds)
           ~~~~~~~~~^^^^^^^^^^^^^^^
  File "/root/buildarea/3.x.angelico-debian-amd64/build/Lib/multiprocessing/process.py", line 156, in join
    res = self._popen.wait(timeout)
  File "/root/buildarea/3.x.angelico-debian-amd64/build/Lib/multiprocessing/popen_fork.py", line 44, in wait
    return self.poll(os.WNOHANG if timeout == 0.0 else 0)
           ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/root/buildarea/3.x.angelico-debian-amd64/build/Lib/multiprocessing/popen_fork.py", line 28, in poll
    pid, sts = os.waitpid(self.pid, flag)
               ~~~~~~~~~~^^^^^^^^^^^^^^^^
  File "/root/buildarea/3.x.angelico-debian-amd64/build/Lib/test/_test_multiprocessing.py", line 628, in handler
    raise RuntimeError('join took too long: %s' % p)
RuntimeError: join took too long: <Process name='Process-171' pid=3439307 parent=3438815 started daemon>

@bedevere-bot

Copy link
Copy Markdown

⚠️⚠️⚠️ Buildbot failure ⚠️⚠️⚠️

Hi! The buildbot ARM64 Windows 3.x (tier-2) has failed when building commit fb2f0bb.

What do you need to do:

  1. Don't panic.
  2. Check the buildbot page in the devguide if you don't know what the buildbots are or how they work.
  3. Go to the page of the buildbot that failed (https://buildbot.python.org/#/builders/729/builds/11241) and take a look at the build logs.
  4. Check if the failure is related to this commit (fb2f0bb) or if it is a false positive.
  5. If the failure is related to this commit, please, reflect that on the issue and make a new Pull Request with a fix.

You can take a look at the buildbot page here:

https://buildbot.python.org/#/builders/729/builds/11241

Failed tests:

  • test_tarfile

Failed subtests:

  • test_sneaky_hardlink_fallback - test.test_tarfile.TestExtractionFilters.test_sneaky_hardlink_fallback

Summary of the results of the build (if available):

==

Click to see traceback logs
Traceback (most recent call last):
  File "C:\Users\buildworker\buildarea\3.x.ware-win11-arm64\build\Lib\test\test_tarfile.py", line 4625, in test_sneaky_hardlink_fallback
    self.expect_exception(
    ~~~~~~~~~~~~~~~~~~~~~^
        tarfile.LinkFallbackError,
        ^^^^^^^^^^^^^^^^^^^^^^^^^^
        "link 'boom' would be extracted as a copy of "
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        + "'c/escape', which was rejected")
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\buildworker\buildarea\3.x.ware-win11-arm64\build\Lib\test\test_tarfile.py", line 4099, in expect_exception
    with self.assertRaisesRegex(exc_type, message_re):
         ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
AssertionError: LinkFallbackError not raised

@bedevere-bot

Copy link
Copy Markdown

⚠️⚠️⚠️ Buildbot failure ⚠️⚠️⚠️

Hi! The buildbot AMD64 Windows11 Non-Debug 3.x (tier-1) has failed when building commit fb2f0bb.

What do you need to do:

  1. Don't panic.
  2. Check the buildbot page in the devguide if you don't know what the buildbots are or how they work.
  3. Go to the page of the buildbot that failed (https://buildbot.python.org/#/builders/914/builds/6095) and take a look at the build logs.
  4. Check if the failure is related to this commit (fb2f0bb) or if it is a false positive.
  5. If the failure is related to this commit, please, reflect that on the issue and make a new Pull Request with a fix.

You can take a look at the buildbot page here:

https://buildbot.python.org/#/builders/914/builds/6095

Failed tests:

  • test_tarfile

Failed subtests:

  • test_sneaky_hardlink_fallback - test.test_tarfile.TestExtractionFilters.test_sneaky_hardlink_fallback

Summary of the results of the build (if available):

==

Click to see traceback logs
Traceback (most recent call last):
  File "b:\uildarea\3.x.ware-win11.nondebug\build\Lib\test\test_tarfile.py", line 4625, in test_sneaky_hardlink_fallback
    self.expect_exception(
    ~~~~~~~~~~~~~~~~~~~~~^
        tarfile.LinkFallbackError,
        ^^^^^^^^^^^^^^^^^^^^^^^^^^
        "link 'boom' would be extracted as a copy of "
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        + "'c/escape', which was rejected")
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "b:\uildarea\3.x.ware-win11.nondebug\build\Lib\test\test_tarfile.py", line 4099, in expect_exception
    with self.assertRaisesRegex(exc_type, message_re):
         ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
AssertionError: LinkFallbackError not raised

encukou added a commit that referenced this pull request Sep 11, 2026
gh-157266: Adjust test for Windows

On Windows (no symlinks, no hardlinks), the behaviour is
the same as without the fix in GH-157266:
- a/t/dummy is extracted
- b/ is extracted
- c/ is *not* created (the target, a/t, is not in the archive)
- c/escape: c/ is created; escape is skipped (target,
   c/../../link_here, is not in archive)
- c is not recreated as a directory
- boom is not created (target is c/escape, which falls back to
  ..\..\link_here, which does not exist in archive)
clin1234 pushed a commit to clin1234/cpython that referenced this pull request Sep 12, 2026
clin1234 pushed a commit to clin1234/cpython that referenced this pull request Sep 12, 2026
pythongh-157266: Adjust test for Windows

On Windows (no symlinks, no hardlinks), the behaviour is
the same as without the fix in pythonGH-157266:
- a/t/dummy is extracted
- b/ is extracted
- c/ is *not* created (the target, a/t, is not in the archive)
- c/escape: c/ is created; escape is skipped (target,
   c/../../link_here, is not in archive)
- c is not recreated as a directory
- boom is not created (target is c/escape, which falls back to
  ..\..\link_here, which does not exist in archive)
johnslavik pushed a commit to johnslavik/cpython that referenced this pull request Sep 14, 2026
johnslavik pushed a commit to johnslavik/cpython that referenced this pull request Sep 14, 2026
pythongh-157266: Adjust test for Windows

On Windows (no symlinks, no hardlinks), the behaviour is
the same as without the fix in pythonGH-157266:
- a/t/dummy is extracted
- b/ is extracted
- c/ is *not* created (the target, a/t, is not in the archive)
- c/escape: c/ is created; escape is skipped (target,
   c/../../link_here, is not in archive)
- c is not recreated as a directory
- boom is not created (target is c/escape, which falls back to
  ..\..\link_here, which does not exist in archive)
encukou added a commit to miss-islington/cpython that referenced this pull request Sep 14, 2026
pythongh-157266: Adjust test for Windows

On Windows (no symlinks, no hardlinks), the behaviour is
the same as without the fix in pythonGH-157266:
- a/t/dummy is extracted
- b/ is extracted
- c/ is *not* created (the target, a/t, is not in the archive)
- c/escape: c/ is created; escape is skipped (target,
   c/../../link_here, is not in archive)
- c is not recreated as a directory
- boom is not created (target is c/escape, which falls back to
  ..\..\link_here, which does not exist in archive)
encukou added a commit to miss-islington/cpython that referenced this pull request Sep 14, 2026
pythongh-157266: Adjust test for Windows

On Windows (no symlinks, no hardlinks), the behaviour is
the same as without the fix in pythonGH-157266:
- a/t/dummy is extracted
- b/ is extracted
- c/ is *not* created (the target, a/t, is not in the archive)
- c/escape: c/ is created; escape is skipped (target,
   c/../../link_here, is not in archive)
- c is not recreated as a directory
- boom is not created (target is c/escape, which falls back to
  ..\..\link_here, which does not exist in archive)
encukou added a commit to miss-islington/cpython that referenced this pull request Sep 14, 2026
pythongh-157266: Adjust test for Windows

On Windows (no symlinks, no hardlinks), the behaviour is
the same as without the fix in pythonGH-157266:
- a/t/dummy is extracted
- b/ is extracted
- c/ is *not* created (the target, a/t, is not in the archive)
- c/escape: c/ is created; escape is skipped (target,
   c/../../link_here, is not in archive)
- c is not recreated as a directory
- boom is not created (target is c/escape, which falls back to
  ..\..\link_here, which does not exist in archive)
encukou added a commit to miss-islington/cpython that referenced this pull request Sep 14, 2026
pythongh-157266: Adjust test for Windows

On Windows (no symlinks, no hardlinks), the behaviour is
the same as without the fix in pythonGH-157266:
- a/t/dummy is extracted
- b/ is extracted
- c/ is *not* created (the target, a/t, is not in the archive)
- c/escape: c/ is created; escape is skipped (target,
   c/../../link_here, is not in archive)
- c is not recreated as a directory
- boom is not created (target is c/escape, which falls back to
  ..\..\link_here, which does not exist in archive)
encukou added a commit to miss-islington/cpython that referenced this pull request Sep 14, 2026
pythongh-157266: Adjust test for Windows

On Windows (no symlinks, no hardlinks), the behaviour is
the same as without the fix in pythonGH-157266:
- a/t/dummy is extracted
- b/ is extracted
- c/ is *not* created (the target, a/t, is not in the archive)
- c/escape: c/ is created; escape is skipped (target,
   c/../../link_here, is not in archive)
- c is not recreated as a directory
- boom is not created (target is c/escape, which falls back to
  ..\..\link_here, which does not exist in archive)
encukou added a commit to miss-islington/cpython that referenced this pull request Sep 14, 2026
pythongh-157266: Adjust test for Windows

On Windows (no symlinks, no hardlinks), the behaviour is
the same as without the fix in pythonGH-157266:
- a/t/dummy is extracted
- b/ is extracted
- c/ is *not* created (the target, a/t, is not in the archive)
- c/escape: c/ is created; escape is skipped (target,
   c/../../link_here, is not in archive)
- c is not recreated as a directory
- boom is not created (target is c/escape, which falls back to
  ..\..\link_here, which does not exist in archive)
LearningCircuit added a commit to LearningCircuit/local-deep-research that referenced this pull request Sep 18, 2026
CVE-2026-87910 / PSF-2026-40 (Medium): when tarfile cannot create a
link and falls back to extracting the linked member as a copy, the
extraction filter is consulted twice — once with the member's name
replaced by the link's location, once under its own name. The first
call's None (explicit rejection) was discarded, so a member a filter
refused to see materialised at the link's location anyway (alert
#8273, Grype, python 3.14.7 binary).

The fix is merged upstream (python/cpython#157266, commit fb2f0bbc)
but no released 3.14 image carries it. Following the established
CVE-2026-15310 zipfile-backport pattern:

- scripts/patch_cpython_tarfile_cve_2026_87910.py applies the reviewed
  4-line pure-Python fix to the stdlib in builder-base and ldr (both
  stages build from the fresh base image), fails closed on source
  drift, and verifies at build time by reproducing the vulnerable
  fallback: a filter that allows secret.txt under its own name but
  rejects it under the hardlink's must leave nothing at the link's
  location. Verified against pristine 3.14.7: unpatched the copy
  materialises, patched it does not; ordinary hardlink extraction
  unaffected.
- .grype.yaml: fix-state-unknown binary-CPE entry with the same
  removal condition as the zipfile backport (fixed 3.14 image ships).
- tests/deployment/test_cpython_tarfile_backport.py: contract tests
  for hunk application, idempotency, drift refusal, plus the
  behavioral property on the image's 3.14 stdlib (skipped on the 3.12
  dev venv, which predates this project's image scope).

Resolves #8273.
encukou added a commit that referenced this pull request Sep 21, 2026
…acks (GH-157266) (GH-157308)

(cherry picked from commit fb2f0bb)
Also includes commit d9565e5:
gh-157266: Adjust test for Windows (GH-157334)

Co-authored-by: Petr Viktorin <encukou@gmail.com>
Co-authored-by: Stan Ulbrych <stan@python.org>
LearningCircuit added a commit to LearningCircuit/local-deep-research that referenced this pull request Sep 25, 2026
- Dockerfile: correct the tarfile CVE comment — the upstream fix is merged
  on CPython main (python/cpython#157266, fb2f0bbc), not the 3.14
  maintenance branch; the 3.14 backport (python/cpython#157307) is open.
- test_cpython_tarfile_backport.py: skip the behavioral test based on
  whether the ambient tarfile actually carries the patch markers, not a
  version check plus two strings every 3.14.x contains; fix the module
  docstring's stale wording.
- test_cpython_tarfile_backport.py: make the source-level test reject the
  variant that captures the first filter result but overwrites it before
  the None check, by asserting on the exact upstream hunk structure
  instead of marker presence plus a call count.
- patch_cpython_tarfile_cve_2026_87910.py: print a clear notice (exit 0)
  when the target's tarfile already contains the fix; extend
  verify_runtime to exercise the accepted fallback-copy path, which the
  existing benign check never enters.
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