diff --git a/bundle/YouCompleteMe/third_party/ycmd/build.py b/bundle/YouCompleteMe/third_party/ycmd/build.py index 33f83d6..d22e86b 100755 --- a/bundle/YouCompleteMe/third_party/ycmd/build.py +++ b/bundle/YouCompleteMe/third_party/ycmd/build.py @@ -760,7 +760,26 @@ def ExtractCsCompleter( writeStdout, build_dir, package_path ): package_zip.extractall() else: with tarfile.open( package_path ) as package_tar: - package_tar.extractall() + 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(package_tar) writeStdout( 'DONE\n' ) @@ -993,7 +1012,26 @@ def Print( *args, **kwargs ): Print( f"Extracting jdt.ls to { REPOSITORY }..." ) with tarfile.open( file_name ) as package_tar: - package_tar.extractall( REPOSITORY ) + 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(package_tar, REPOSITORY) Print( "Done installing jdt.ls" ) @@ -1077,7 +1115,26 @@ def DownloadClangd( printer ): printer( f"Extracting Clangd to { CLANGD_OUTPUT_DIR }..." ) with tarfile.open( file_name ) as package_tar: - package_tar.extractall( CLANGD_OUTPUT_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(package_tar, CLANGD_OUTPUT_DIR) printer( "Done installing Clangd" )