This is an automated email from the ASF dual-hosted git repository.

juergbi pushed a commit to branch juerg/tar
in repository https://gitbox.apache.org/repos/asf/buildstream-plugins.git

commit 4d7472abc8e21a3acddb04aeb4ae5a6ed48aa3eb
Author: Jürg Billeter <[email protected]>
AuthorDate: Fri Jul 12 17:11:46 2024 +0200

    cargo.py: Check tar member paths
---
 src/buildstream_plugins/sources/cargo.py | 32 +++++++++++++++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

diff --git a/src/buildstream_plugins/sources/cargo.py 
b/src/buildstream_plugins/sources/cargo.py
index 6334a54..402b9ee 100644
--- a/src/buildstream_plugins/sources/cargo.py
+++ b/src/buildstream_plugins/sources/cargo.py
@@ -146,8 +146,14 @@ class Crate(SourceFetcher):
         try:
             mirror_file = self._get_mirror_file()
             with tarfile.open(mirror_file) as tar:
-                tar.extractall(path=directory)
                 members = tar.getmembers()
+                if hasattr(tarfile, "tar_filter"):
+                    # Python 3.12+ (and older versions with backports)
+                    tar.extractall(path=directory, filter="tar")
+                else:
+                    for member in members:
+                        self._assert_tarinfo_safe(member, directory)
+                    tar.extractall(path=directory, members=members)
 
             if members:
                 dirname = members[0].name.split("/")[0]
@@ -184,6 +190,30 @@ class Crate(SourceFetcher):
     #                   Private helpers                    #
     ########################################################
 
+    # Assert that a tarfile is safe to extract; specifically, make
+    # sure that we don't do anything outside of the target
+    # directory (this is possible, if, say, someone engineered a
+    # tarfile to contain paths that start with ..).
+    def _assert_tarinfo_safe(self, member: tarfile.TarInfo, target_dir: str):
+        final_path = os.path.abspath(os.path.join(target_dir, member.path))
+        if not final_path.startswith(target_dir):
+            raise SourceError(
+                "{}: Tarfile attempts to extract outside the staging area: "
+                "{} -> {}".format(self, member.path, final_path)
+            )
+
+        if member.islnk():
+            linked_path = os.path.abspath(os.path.join(target_dir, 
member.linkname))
+            if not linked_path.startswith(target_dir):
+                raise SourceError(
+                    "{}: Tarfile attempts to hardlink outside the staging 
area: "
+                    "{} -> {}".format(self, member.path, final_path)
+                )
+
+        # Don't need to worry about symlinks because they're just
+        # files here and won't be able to do much harm once we are
+        # in a sandbox.
+
     # _download()
     #
     # Downloads the crate from the url and caches it.

Reply via email to