Skip to content

Commit

Permalink
Bug 1806899 - Sanitize extractall input (m-c tooltool) r=jcristau
Browse files Browse the repository at this point in the history
Syncs m-c copy of tooltool.py with mozilla-releng/tooltool#1066

Differential Revision: https://phabricator.services.mozilla.com/D169017
  • Loading branch information
gbrownmozilla committed Feb 7, 2023
1 parent 738c1de commit fcc5e54
Showing 1 changed file with 31 additions and 10 deletions.
41 changes: 31 additions & 10 deletions python/mozbuild/mozbuild/action/tooltool.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import pprint
import re
import shutil
import stat
import sys
import tarfile
import tempfile
Expand All @@ -46,7 +47,7 @@
from random import random
from subprocess import PIPE, Popen

__version__ = "1.3.0"
__version__ = "1.4.0"

# Allowed request header characters:
# !#$%&'()*+,-./:;<=>?@[]^_`{|}~ and space, a-z, A-Z, 0-9, \, "
Expand Down Expand Up @@ -955,6 +956,29 @@ def clean_path(dirname):
CHECKSUM_SUFFIX = ".checksum"


def validate_tar_member(member, 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

member_path = os.path.join(path, member.name)
if not _is_within_directory(path, member_path):
raise Exception("Attempted path traversal in tar file: " + member.name)
if member.mode & (stat.S_ISUID | stat.S_ISGID):
raise Exception("Attempted setuid or setgid in tar file: " + member.name)


def safe_extract(tar, path=".", members=None, *, numeric_owner=False):
def _files(tar, path):
for member in tar:
validate_tar_member(member, path)
yield member

tar.extractall(path, members=_files(tar, path), numeric_owner=numeric_owner)


def unpack_file(filename):
"""Untar `filename`, assuming it is uncompressed or compressed with bzip2,
xz, gzip, zst, or unzip a zip file. The file is assumed to contain a single
Expand All @@ -965,9 +989,8 @@ def unpack_file(filename):
base_file, tar_ext = os.path.splitext(tar_file)
clean_path(base_file)
log.info('untarring "%s"' % filename)
tar = tarfile.open(filename)
tar.extractall()
tar.close()
with tarfile.open(filename) as tar:
safe_extract(tar)
elif os.path.isfile(filename) and filename.endswith(".tar.xz"):
base_file = filename.replace(".tar.xz", "")
clean_path(base_file)
Expand All @@ -980,9 +1003,8 @@ def unpack_file(filename):
fileobj = BytesIO()
fileobj.write(stdout)
fileobj.seek(0)
tar = tarfile.open(fileobj=fileobj, mode="r|")
tar.extractall()
tar.close()
with tarfile.open(fileobj=fileobj, mode="r|") as tar:
safe_extract(tar)
elif os.path.isfile(filename) and filename.endswith(".tar.zst"):
import zstandard

Expand All @@ -991,9 +1013,8 @@ def unpack_file(filename):
log.info('untarring "%s"' % filename)
dctx = zstandard.ZstdDecompressor()
with dctx.stream_reader(open(filename, "rb")) as fileobj:
tar = tarfile.open(fileobj=fileobj, mode="r|")
tar.extractall()
tar.close()
with tarfile.open(fileobj=fileobj, mode="r|") as tar:
safe_extract(tar)
elif os.path.isfile(filename) and zipfile.is_zipfile(filename):
base_file = filename.replace(".zip", "")
clean_path(base_file)
Expand Down

0 comments on commit fcc5e54

Please sign in to comment.