diff --git a/atomic_reactor/plugins/fetch_sources.py b/atomic_reactor/plugins/fetch_sources.py index abc6eab8d..40d7da418 100644 --- a/atomic_reactor/plugins/fetch_sources.py +++ b/atomic_reactor/plugins/fetch_sources.py @@ -790,7 +790,26 @@ def exclude_files_from_remote_sources(self, remote_sources_map, remote_sources_d unpack_dir = remote_archive + '_unpacked' with tarfile.open(remote_archive) as tf: - tf.extractall(unpack_dir) + 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, unpack_dir) delete_app = self._check_if_package_excluded(remote_json['packages'], denylist_sources, remote_archive) diff --git a/atomic_reactor/plugins/resolve_remote_source.py b/atomic_reactor/plugins/resolve_remote_source.py index f04764920..9f48691d9 100644 --- a/atomic_reactor/plugins/resolve_remote_source.py +++ b/atomic_reactor/plugins/resolve_remote_source.py @@ -225,7 +225,26 @@ def inject_into_build_dir( created_dirs.append(dest_dir) with tarfile.open(remote_source.tarball_path) as tf: - tf.extractall(dest_dir) + 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, dest_dir) config_files = self.cachito_session.get_request_config_files(remote_source.id) self.generate_cachito_config_files(dest_dir, config_files)