Skip to content

Commit 56b8673

Browse files
Reject links replacing the destination in tarfile.tar_filter
1 parent 2d81eae commit 56b8673

4 files changed

Lines changed: 16 additions & 7 deletions

File tree

‎Doc/library/tarfile.rst‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,6 +1131,11 @@ reused in custom filters:
11311131
- :ref:`Refuse <tarfile-extraction-refuse>` to extract files whose absolute
11321132
path (after following symlinks) would end up outside the destination.
11331133
This raises :class:`~tarfile.OutsideDestinationError`.
1134+
- :ref:`Refuse <tarfile-extraction-refuse>` to extract links (hard or soft)
1135+
whose path resolves to the destination directory itself.
1136+
This raises :class:`~tarfile.OutsideDestinationError`.
1137+
Note that such files are refused even on platforms that do not support
1138+
symbolic links.
11341139
- Clear high mode bits (setuid, setgid, sticky) and group/other write bits
11351140
(:const:`~stat.S_IWGRP` | :const:`~stat.S_IWOTH`).
11361141

‎Lib/tarfile.py‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,11 @@ def _get_filtered_attrs(member, dest_path, for_data=True):
848848
strict=os.path.ALLOW_MISSING)
849849
if os.path.commonpath([target_path, dest_path]) != dest_path:
850850
raise OutsideDestinationError(member, target_path)
851+
# A link member that resolves to the destination directory itself
852+
# would replace it with a (sym)link, redirecting the destination
853+
# for all subsequent members.
854+
if (member.islnk() or member.issym()) and target_path == dest_path:
855+
raise OutsideDestinationError(member, target_path)
851856
# Limit permissions (no high bits, and go-w)
852857
mode = member.mode
853858
if mode is not None:
@@ -883,11 +888,6 @@ def _get_filtered_attrs(member, dest_path, for_data=True):
883888
if member.islnk() or member.issym():
884889
if os.path.isabs(member.linkname):
885890
raise AbsoluteLinkError(member)
886-
# A link member that resolves to the destination directory itself
887-
# would replace it with a (sym)link, redirecting the destination
888-
# for all subsequent members.
889-
if target_path == dest_path:
890-
raise OutsideDestinationError(member, target_path)
891891
normalized = os.path.normpath(member.linkname)
892892
if normalized != member.linkname:
893893
new_attrs['linkname'] = normalized

‎Lib/test/test_tarfile.py‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4545,8 +4545,10 @@ def test_link_at_destination(self):
45454545
t.linkname = '.'
45464546
arc.tar_w.addfile(t)
45474547

4548-
with self.check_context(arc.open(), 'data'):
4549-
self.expect_exception(tarfile.OutsideDestinationError)
4548+
for filter in 'tar', 'data':
4549+
with self.subTest(name=name, filter=filter):
4550+
with self.check_context(arc.open(), filter):
4551+
self.expect_exception(tarfile.OutsideDestinationError)
45504552

45514553
@symlink_test
45524554
@os_helper.skip_unless_symlink
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:func:`tarfile.tar_filter` now rejects link members whose path resolves to
2+
the destination directory itself, as :func:`tarfile.data_filter` already did.

0 commit comments

Comments
 (0)