Skip to content

Commit

Permalink
Set safe default extraction filter for tar archives
Browse files Browse the repository at this point in the history
[PEP 706](https://peps.python.org/pep-0706/), first implemented in Python
3.11.4, mitigates some of the security issues of `TarFile.extract()` and
`TarFile.extractall()` by allowing to specify a `filter` keyword-only
parameter.
Set a safe default (`data_filter`) for the filter if available,
reverting to Python 3.11 behavior ('fully_trusted') otherwise, see
https://docs.python.org/3/library/tarfile.html#supporting-older-python-versions
  • Loading branch information
nsoranzo committed Jan 14, 2025
1 parent 9fc0f05 commit d67c1a1
Show file tree
Hide file tree
Showing 5 changed files with 16 additions and 6 deletions.
3 changes: 3 additions & 0 deletions lib/galaxy/tool_util/verify/interactor.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,9 @@ def test_data_download(self, tool_id, filename, mode="file", is_output=True, too
else:
# Galaxy < 21.01
with tarfile.open(fileobj=fileobj) as tar_contents:
tar_contents.extraction_filter = getattr(
tarfile, "data_filter", (lambda member, path: member)
)
tar_contents.extractall(path=path)
result = path
else:
Expand Down
6 changes: 3 additions & 3 deletions lib/galaxy/tools/imp_exp/unpack_tar_gz_archive.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ def unpack_archive(archive_file, dest_dir):
with zipfile.ZipFile(archive_file, "r") as zip_archive:
zip_archive.extractall(path=dest_dir)
else:
archive_fp = tarfile.open(archive_file, mode="r")
archive_fp.extractall(path=dest_dir)
archive_fp.close()
with tarfile.open(archive_file, mode="r") as archive_fp:
archive_fp.extraction_filter = getattr(tarfile, "data_filter", (lambda member, path: member))
archive_fp.extractall(path=dest_dir)


def main(options, args):
Expand Down
4 changes: 3 additions & 1 deletion lib/galaxy/util/compression_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,9 @@ def isfile(self, member: ArchiveMemberType) -> bool:
return False

def open_tar(self, filepath: StrPath, mode: Literal["a", "r", "w", "x"]) -> tarfile.TarFile:
return tarfile.open(filepath, mode, errorlevel=0)
tf = tarfile.open(filepath, mode, errorlevel=0)
tf.extraction_filter = getattr(tarfile, "data_filter", (lambda member, path: member))
return tf

def open_zip(self, filepath: StrPath, mode: Literal["a", "r", "w", "x"]) -> zipfile.ZipFile:
return zipfile.ZipFile(filepath, mode)
Expand Down
5 changes: 4 additions & 1 deletion lib/tool_shed/util/repository_content_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def tar_open(uploaded_file):
tar = tarfile.open(uploaded_file, "r:*")
else:
tar = tarfile.open(uploaded_file)
tar.extraction_filter = getattr(tarfile, "data_filter", (lambda member, path: member))
return tar


Expand All @@ -49,14 +50,16 @@ def upload_tar(
dry_run: bool = False,
remove_repo_files_not_in_tar: bool = True,
new_repo_alert: bool = False,
tar=None,
tar: Optional[tarfile.TarFile] = None,
rdah: Optional[RepositoryDependencyAttributeHandler] = None,
tdah: Optional[ToolDependencyAttributeHandler] = None,
) -> ChangeResponseT:
host = trans.repositories_hostname
app = trans.app
if tar is None:
tar = tar_open(uploaded_file)
else:
tar.extraction_filter = getattr(tarfile, "data_filter", (lambda member, path: member))
rdah = rdah or RepositoryDependencyAttributeHandler(trans, unpopulate=False)
tdah = tdah or ToolDependencyAttributeHandler(trans, unpopulate=False)
# Upload a tar archive of files.
Expand Down
4 changes: 3 additions & 1 deletion test/unit/tool_shed/test_shed_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ def community_file_dir():
response = requests.get(URL)
response.raise_for_status()
b = BytesIO(response.content)
tarfile.open(fileobj=b, mode="r:gz").extractall(extracted_archive_dir)
with tarfile.open(fileobj=b, mode="r:gz") as tar:
tar.extraction_filter = getattr(tarfile, "data_filter", (lambda member, path: member))
tar.extractall(extracted_archive_dir)
try:
yield extracted_archive_dir
finally:
Expand Down

0 comments on commit d67c1a1

Please sign in to comment.