From 23d405ea553843442e034e8ee8345ed8445a38d2 Mon Sep 17 00:00:00 2001 From: Melissa Jost Date: Thu, 3 Nov 2022 09:06:03 -0700 Subject: [PATCH] tests, resources: CVE-2007-4559 Patch Hi, we are security researchers from the Advanced Research Center at Trellix. We have began a campaign to patch a widespread bug named CVE-2007-4559. CVE-2007-4559 is a 15 year old bug in the Python tarfile package. By using extract() or extractall() on a tarfile object without sanitizing input, a maliciously crafted .tar file could perform a directory path traversal attack. We found at least one unsantized extractall() in your codebase and are providing a patch for you via pull request. The patch essentially checks to see if all tarfile members will be extracted safely and throws an exception otherwise. We encourage you to use this patch or your own solution to secure against CVE-2007-4559. If you have further questions you may contact us through this projects lead researcher Kasimir Schulz. Change-Id: I891ac6652cfbd479aed51d64ef6d4e0fe740e06d Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/65271 Reviewed-by: Bobby Bruce Maintainer: Jason Lowe-Power Tested-by: kokoro Reviewed-by: Jason Lowe-Power --- src/python/gem5/resources/downloader.py | 25 ++++++++++++++++++++++++- tests/gem5/fixture.py | 23 ++++++++++++++++++++++- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/python/gem5/resources/downloader.py b/src/python/gem5/resources/downloader.py index bc277eeeb4..1fda8d86b6 100644 --- a/src/python/gem5/resources/downloader.py +++ b/src/python/gem5/resources/downloader.py @@ -501,5 +501,28 @@ def get_resource( ) unpack_to = download_dest[: -len(tar_extension)] with tarfile.open(download_dest) as f: - f.extractall(unpack_to) + + def is_within_directory(directory, target): + + abs_directory = os.path.abspath(directory) + abs_target = os.path.abspath(target) + + prefix = os.path.commonprefix([abs_directory, abs_target]) + + return prefix == abs_directory + + def safe_extract( + tar, path=".", members=None, *, numeric_owner=False + ): + + for member in tar.getmembers(): + member_path = os.path.join(path, member.name) + if not is_within_directory(path, member_path): + raise Exception( + "Attempted Path Traversal in Tar File" + ) + + tar.extractall(path, members, numeric_owner=numeric_owner) + + safe_extract(f, unpack_to) os.remove(download_dest) diff --git a/tests/gem5/fixture.py b/tests/gem5/fixture.py index 5d6ae0cd05..65b5454cae 100644 --- a/tests/gem5/fixture.py +++ b/tests/gem5/fixture.py @@ -357,7 +357,28 @@ class DownloadedArchive(DownloadedProgram): import tarfile with tarfile.open(self.filename) as tf: - tf.extractall(self.path) + + def is_within_directory(directory, target): + + abs_directory = os.path.abspath(directory) + abs_target = os.path.abspath(target) + + prefix = os.path.commonprefix([abs_directory, abs_target]) + + return prefix == abs_directory + + def safe_extract( + tar, path=".", members=None, *, numeric_owner=False + ): + + for member in tar.getmembers(): + member_path = os.path.join(path, member.name) + if not is_within_directory(path, member_path): + raise Exception("Attempted Path Traversal in Tar File") + + tar.extractall(path, members, numeric_owner=numeric_owner) + + safe_extract(tf, self.path) def _setup(self, testitem): # Check to see if there is a file downloaded