mirror of
https://github.com/python/cpython.git
synced 2026-10-28 18:35:21 +08:00
gh-157265: tarfile: Honor None result of filter for link fallbacks (GH-157266)
Co-authored-by: Stan Ulbrych <stan@python.org>
This commit is contained in:
1 parent
07f33ceb3a
commit
fb2f0bbc3b
3 files changed
+34
-4
No files matched your search
+3
-1
@@ -2841,9 +2841,11 @@ class TarFile(object):
|
||||
"makelink_with_filter: if filter_function is not None, "
|
||||
+ "extraction_root must also not be None")
|
||||
try:
|
||||
filter_function(
|
||||
filtered = filter_function(
|
||||
unfiltered.replace(name=tarinfo.name, deep=False),
|
||||
extraction_root)
|
||||
if filtered is None:
|
||||
return
|
||||
filtered = filter_function(unfiltered, extraction_root)
|
||||
except _FILTER_ERRORS as cause:
|
||||
raise LinkFallbackError(tarinfo, unfiltered.name) from cause
|
||||
|
||||
@@ -4621,9 +4621,15 @@ class TestExtractionFilters(unittest.TestCase):
|
||||
for filter in 'tar', 'fully_trusted':
|
||||
with self.subTest(filter), self.check_context(arc.open(), filter):
|
||||
if not os_helper.can_symlink():
|
||||
self.expect_file("a/t/dummy")
|
||||
self.expect_file("b/")
|
||||
self.expect_file("c/")
|
||||
if filter == 'tar':
|
||||
self.expect_exception(
|
||||
tarfile.LinkFallbackError,
|
||||
"link 'boom' would be extracted as a copy of "
|
||||
+ "'c/escape', which was rejected")
|
||||
else:
|
||||
self.expect_file("a/t/dummy")
|
||||
self.expect_file("b/")
|
||||
self.expect_file("c/")
|
||||
else:
|
||||
self.expect_file("a/t/dummy")
|
||||
self.expect_file("b/")
|
||||
@@ -4820,6 +4826,25 @@ class TestExtractionFilters(unittest.TestCase):
|
||||
if os_helper.can_chmod():
|
||||
self.assertFalse(path.stat().st_mode & stat.S_IWUSR)
|
||||
|
||||
@symlink_test
|
||||
def test_extract_filters_target_none(self):
|
||||
# Test that when extract() falls back to extracting (rather than
|
||||
# linking) a hardlink target, the member is skipped if the filter
|
||||
# returns None.
|
||||
with ArchiveMaker() as arc:
|
||||
arc.add('a/b/s', symlink_to='../escape')
|
||||
arc.add('q', hardlink_to='a/b/s')
|
||||
def filter_unsafe_members(member, path):
|
||||
try:
|
||||
return tarfile.data_filter(member, path)
|
||||
except tarfile.FilterError as error:
|
||||
return None
|
||||
with self.check_context(arc.open(), filter_unsafe_members):
|
||||
if os_helper.can_symlink():
|
||||
self.expect_file('a/b/s', symlink_to='../escape')
|
||||
else:
|
||||
self.expect_file('a/b/') # symlink is not extracted
|
||||
|
||||
def test_link_fallback_normalizes(self):
|
||||
# Make sure hardlink fallbacks work for non-normalized paths for all
|
||||
# filters
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
In :mod:`tarfile`, when extracting a link falls back to extracting a member
|
||||
of the archive, skip the member when the filter function returns None when
|
||||
called with the extracted member's name replaced with the link's.
|
||||
Reference in new issue
Block a user