Skip to content

Commit 2eb0c2f

Browse files
miss-islingtonencukouStanFromIreland
authored
[3.11] gh-157265: tarfile: Honor None result of filter for link fallbacks (GH-157266) (#157306)
* gh-157265: tarfile: Honor None result of filter for link fallbacks (GH-157266) (cherry picked from commit fb2f0bb) Co-authored-by: Petr Viktorin <encukou@gmail.com> Co-authored-by: Stan Ulbrych <stan@python.org> * gh-157265: Adjust test for Windows (GH-157334) 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) --------- Co-authored-by: Petr Viktorin <encukou@gmail.com> Co-authored-by: Stan Ulbrych <stan@python.org>
1 parent 69f92eb commit 2eb0c2f

3 files changed

Lines changed: 34 additions & 4 deletions

File tree

‎Lib/tarfile.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2683,9 +2683,11 @@ def makelink_with_filter(self, tarinfo, targetpath,
26832683
"makelink_with_filter: if filter_function is not None, "
26842684
+ "extraction_root must also not be None")
26852685
try:
2686-
filter_function(
2686+
filtered = filter_function(
26872687
unfiltered.replace(name=tarinfo.name, deep=False),
26882688
extraction_root)
2689+
if filtered is None:
2690+
return
26892691
filtered = filter_function(unfiltered, extraction_root)
26902692
except _FILTER_ERRORS as cause:
26912693
raise LinkFallbackError(tarinfo, unfiltered.name) from cause

‎Lib/test/test_tarfile.py‎

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4085,9 +4085,15 @@ def test_sneaky_hardlink_fallback(self):
40854085
for filter in 'tar', 'fully_trusted':
40864086
with self.subTest(filter), self.check_context(arc.open(), filter):
40874087
if not os_helper.can_symlink():
4088-
self.expect_file("a/t/dummy")
4089-
self.expect_file("b/")
4090-
self.expect_file("c/")
4088+
if filter == 'fully_trusted' or sys.platform == "win32":
4089+
self.expect_file("a/t/dummy")
4090+
self.expect_file("b/")
4091+
self.expect_file("c/")
4092+
else:
4093+
self.expect_exception(
4094+
tarfile.LinkFallbackError,
4095+
"link 'boom' would be extracted as a copy of "
4096+
+ "'c/escape', which was rejected")
40914097
else:
40924098
self.expect_file("a/t/dummy")
40934099
self.expect_file("b/")
@@ -4284,6 +4290,25 @@ def testing_filter(member, path):
42844290
if os_helper.can_chmod():
42854291
self.assertFalse(path.stat().st_mode & stat.S_IWUSR)
42864292

4293+
@symlink_test
4294+
def test_extract_filters_target_none(self):
4295+
# Test that when extract() falls back to extracting (rather than
4296+
# linking) a hardlink target, the member is skipped if the filter
4297+
# returns None.
4298+
with ArchiveMaker() as arc:
4299+
arc.add('a/b/s', symlink_to='../escape')
4300+
arc.add('q', hardlink_to='a/b/s')
4301+
def filter_unsafe_members(member, path):
4302+
try:
4303+
return tarfile.data_filter(member, path)
4304+
except tarfile.FilterError as error:
4305+
return None
4306+
with self.check_context(arc.open(), filter_unsafe_members):
4307+
if os_helper.can_symlink():
4308+
self.expect_file('a/b/s', symlink_to='../escape')
4309+
else:
4310+
self.expect_file('a/b/') # symlink is not extracted
4311+
42874312
def test_link_fallback_normalizes(self):
42884313
# Make sure hardlink fallbacks work for non-normalized paths for all
42894314
# filters
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
In :mod:`tarfile`, when extracting a link falls back to extracting a member
2+
of the archive, skip the member when the filter function returns None when
3+
called with the extracted member's name replaced with the link's.

0 commit comments

Comments
 (0)