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 2200b383a38176e3952679b8fd0f3dfd3109fecf
Author: Jürg Billeter <[email protected]>
AuthorDate: Fri Jul 12 17:12:18 2024 +0200

    docker.py: Check tar member paths
---
 src/buildstream_plugins/sources/docker.py | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/src/buildstream_plugins/sources/docker.py 
b/src/buildstream_plugins/sources/docker.py
index 4bca2b0..70e9fd4 100644
--- a/src/buildstream_plugins/sources/docker.py
+++ b/src/buildstream_plugins/sources/docker.py
@@ -570,6 +570,12 @@ class DockerSource(Source):
                 # extract files for the current layer
                 with tarfile.open(blob_path, tarinfo=ReadableTarInfo) as tar:
                     with self.tempdir() as td:
+                        if hasattr(tarfile, "tar_filter"):
+                            # Python 3.12+ (and older versions with backports)
+                            tar.extraction_filter = tarfile.tar_filter
+                        else:
+                            for member in extract_fileset:
+                                self._assert_tarinfo_safe(member, td)
                         tar.extractall(path=td, members=extract_fileset)
                         link_files(td, directory)
 
@@ -618,6 +624,30 @@ class DockerSource(Source):
 
         return extract_fileset, delete_fileset
 
+    # 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.
+
 
 # Plugin entry point
 def setup():

Reply via email to