From 1819805f2019c731bcaefd6b12fd814790f88fcd Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Tue, 19 Mar 2024 12:43:07 +0100 Subject: [PATCH] cve-2007-4559-tarfile Minimal patch for pip --- src/pip/_internal/utils/unpacking.py | 7 +++++++ src/pip/_vendor/distlib/util.py | 13 +++++++++++++ tests/unit/test_utils_unpacking.py | 17 +++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/src/pip/_internal/utils/unpacking.py b/src/pip/_internal/utils/unpacking.py index 5f63f97..c31542f 100644 --- a/src/pip/_internal/utils/unpacking.py +++ b/src/pip/_internal/utils/unpacking.py @@ -184,6 +184,13 @@ def untar_file(filename: str, location: str) -> None: "outside target directory ({})" ) raise InstallationError(message.format(filename, path, location)) + + # Call the `data` filter for its side effect (raising exception) + try: + tarfile.data_filter(member.replace(name=fn), location) + except tarfile.LinkOutsideDestinationError: + pass + if member.isdir(): ensure_dir(path) elif member.issym(): diff --git a/src/pip/_vendor/distlib/util.py b/src/pip/_vendor/distlib/util.py index 80bfc86..7e0941a 100644 --- a/src/pip/_vendor/distlib/util.py +++ b/src/pip/_vendor/distlib/util.py @@ -1249,6 +1249,19 @@ def unarchive(archive_filename, dest_dir, format=None, check=True): for tarinfo in archive.getmembers(): if not isinstance(tarinfo.name, text_type): tarinfo.name = tarinfo.name.decode('utf-8') + + # Limit extraction of dangerous items, if this Python + # allows it easily. If not, just trust the input. + # See: https://docs.python.org/3/library/tarfile.html#extraction-filters + def extraction_filter(member, path): + """Run tarfile.tar_fillter, but raise the expected ValueError""" + # This is only called if the current Python has tarfile filters + try: + return tarfile.tar_filter(member, path) + except tarfile.FilterError as exc: + raise ValueError(str(exc)) + archive.extraction_filter = extraction_filter + archive.extractall(dest_dir) finally: diff --git a/tests/unit/test_utils_unpacking.py b/tests/unit/test_utils_unpacking.py index ccb7a30..05324ad 100644 --- a/tests/unit/test_utils_unpacking.py +++ b/tests/unit/test_utils_unpacking.py @@ -171,6 +171,23 @@ class TestUnpackArchives: test_tar = self.make_tar_file("test_tar.tar", files) untar_file(test_tar, self.tempdir) + def test_unpack_tar_filter(self) -> None: + """ + Test that the tarfile.data_filter is used to disallow dangerous + behaviour (PEP-721) + """ + test_tar = os.path.join(self.tempdir, "test_tar_filter.tar") + with tarfile.open(test_tar, "w") as mytar: + file_tarinfo = tarfile.TarInfo("bad-link") + file_tarinfo.type = tarfile.SYMTYPE + file_tarinfo.linkname = "../../../../pwn" + mytar.addfile(file_tarinfo, io.BytesIO(b"")) + with pytest.raises(InstallationError) as e: + untar_file(test_tar, self.tempdir) + + assert "is outside the destination" in str(e.value) + + def test_unpack_tar_unicode(tmpdir: Path) -> None: test_tar = tmpdir / "test.tar" -- 2.44.0