diff --git a/cve_bin_tool/extractor.py b/cve_bin_tool/extractor.py index 8f4e3017a3..7e2b79b9d8 100644 --- a/cve_bin_tool/extractor.py +++ b/cve_bin_tool/extractor.py @@ -46,6 +46,45 @@ EXTENSIONS = "extensions" MIMES = "mimes" +# Invalid key for unzip and 7z extraction to prevent freezing on password +# protected files. +STATIC_INVALID_KEY = "StaticInvalidKey" + + +async def unzip_file(filename, extraction_path, process_can_fail): + """Extracts files using the unzip utility.""" + stdout, stderr, _ = await aio_run_command( + ["unzip", "-P", STATIC_INVALID_KEY, "-n", "-d", extraction_path, filename], + process_can_fail, + ) + if not stderr: + return 0 + if "incorrect password" in stderr.decode(): + LOGGER.error(f"Failed to extract {filename}: The file is password protected") + return 0 + is_exe = filename.endswith(".exe") + if is_exe: + return 0 # not all .exe files are zipfiles, no need for error + return 1 + + +async def unzip_7z(filename, extraction_path, process_can_fail): + """Extracts files using the 7z utility. 7z supports more file format than\ + unzip does. + """ + stdout, stderr, _ = await aio_run_command( + ["7z", "x", f"-p{STATIC_INVALID_KEY}", filename], process_can_fail + ) + if stdout and not stderr: + return 0 + if "Wrong password" in stderr.decode(): + LOGGER.error(f"Failed to extract {filename}: The file is password protected") + return 0 + is_exe = filename.endswith(".exe") + if is_exe: + return 0 # not all .exe files are zipfiles, no need for error + return 1 + class BaseExtractor: """Extracts tar, rpm, etc. files""" @@ -382,41 +421,17 @@ async def extract_file_zip(filename, extraction_path, process_can_fail=True): freezing during extraction if they are password protected. Providing a key during extraction has no effect if the zip file is not password protected and extraction will happen as normal.""" - - is_exe = filename.endswith(".exe") - key = "StaticInvalidKey" if await aio_inpath("unzip"): - stdout, stderr, _ = await aio_run_command( - ["unzip", "-P", key, "-n", "-d", extraction_path, filename], - process_can_fail, - ) - if stderr: - if "incorrect password" in stderr.decode(): - LOGGER.error( - f"Failed to extract {filename}: The file is password protected" - ) - return 0 - if is_exe: - return 0 # not all .exe files are zipfiles, no need for error - return 1 - elif await aio_inpath("7z"): - stdout, stderr, _ = await aio_run_command( - ["7z", "x", f"-p{key}", filename], process_can_fail - ) - if stderr or not stdout: - if "Wrong password" in stderr.decode(): - LOGGER.error( - f"Failed to extract {filename}: The file is password protected" - ) - return 0 - if is_exe: - return 0 # not all .exe files are zipfiles, no need for error - return 1 + result = await unzip_file(filename, extraction_path, process_can_fail) + if result == 0: + return result + LOGGER.debug(f"Failed to extract {filename} using unzip. Trying 7z.") + if await aio_inpath("7z"): + return await unzip_7z(filename, extraction_path, process_can_fail) else: with ErrorHandler(mode=ErrorMode.Ignore) as e: await aio_unpack_archive(filename, extraction_path) return e.exit_code - return 0 class TempDirExtractorContext(BaseExtractor):