Skip to content

Commit 0c98a22

Browse files
Make extraction work for MSI files when unzip and 7zip installed.
This commit fixes an issue where if both unzip and 7zip were installed, MSI file extraction failed because unzip was attempted first, and failed. Now in the case where both are installed, unzip is tried, and if that fails, then 7zip is tried.
1 parent 94fd6ef commit 0c98a22

File tree

1 file changed

+45
-30
lines changed

1 file changed

+45
-30
lines changed

cve_bin_tool/extractor.py

+45-30
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,45 @@
4646
EXTENSIONS = "extensions"
4747
MIMES = "mimes"
4848

49+
# Invalid key for unzip and 7z extraction to prevent freezing on password
50+
# protected files.
51+
STATIC_INVALID_KEY = "StaticInvalidKey"
52+
53+
54+
async def unzip_file(filename, extraction_path, process_can_fail):
55+
"""Extracts files using the unzip utility."""
56+
stdout, stderr, _ = await aio_run_command(
57+
["unzip", "-P", STATIC_INVALID_KEY, "-n", "-d", extraction_path, filename],
58+
process_can_fail,
59+
)
60+
if not stderr:
61+
return 0
62+
if "incorrect password" in stderr.decode():
63+
LOGGER.error(f"Failed to extract {filename}: The file is password protected")
64+
return 0
65+
is_exe = filename.endswith(".exe")
66+
if is_exe:
67+
return 0 # not all .exe files are zipfiles, no need for error
68+
return 1
69+
70+
71+
async def unzip_7z(filename, extraction_path, process_can_fail):
72+
"""Extracts files using the 7z utility. 7z supports more file format than\
73+
unzip does.
74+
"""
75+
stdout, stderr, _ = await aio_run_command(
76+
["7z", "x", f"-p{STATIC_INVALID_KEY}", filename], process_can_fail
77+
)
78+
if stdout and not stderr:
79+
return 0
80+
if "Wrong password" in stderr.decode():
81+
LOGGER.error(f"Failed to extract {filename}: The file is password protected")
82+
return 0
83+
is_exe = filename.endswith(".exe")
84+
if is_exe:
85+
return 0 # not all .exe files are zipfiles, no need for error
86+
return 1
87+
4988

5089
class BaseExtractor:
5190
"""Extracts tar, rpm, etc. files"""
@@ -382,41 +421,17 @@ async def extract_file_zip(filename, extraction_path, process_can_fail=True):
382421
freezing during extraction if they are password protected.
383422
Providing a key during extraction has no effect if the zip file is
384423
not password protected and extraction will happen as normal."""
385-
386-
is_exe = filename.endswith(".exe")
387-
key = "StaticInvalidKey"
388424
if await aio_inpath("unzip"):
389-
stdout, stderr, _ = await aio_run_command(
390-
["unzip", "-P", key, "-n", "-d", extraction_path, filename],
391-
process_can_fail,
392-
)
393-
if stderr:
394-
if "incorrect password" in stderr.decode():
395-
LOGGER.error(
396-
f"Failed to extract {filename}: The file is password protected"
397-
)
398-
return 0
399-
if is_exe:
400-
return 0 # not all .exe files are zipfiles, no need for error
401-
return 1
402-
elif await aio_inpath("7z"):
403-
stdout, stderr, _ = await aio_run_command(
404-
["7z", "x", f"-p{key}", filename], process_can_fail
405-
)
406-
if stderr or not stdout:
407-
if "Wrong password" in stderr.decode():
408-
LOGGER.error(
409-
f"Failed to extract {filename}: The file is password protected"
410-
)
411-
return 0
412-
if is_exe:
413-
return 0 # not all .exe files are zipfiles, no need for error
414-
return 1
425+
result = await unzip_file(filename, extraction_path, process_can_fail)
426+
if result == 0:
427+
return result
428+
LOGGER.debug(f"Failed to extract {filename} using unzip. Trying 7z.")
429+
if await aio_inpath("7z"):
430+
return await unzip_7z(filename, extraction_path, process_can_fail)
415431
else:
416432
with ErrorHandler(mode=ErrorMode.Ignore) as e:
417433
await aio_unpack_archive(filename, extraction_path)
418434
return e.exit_code
419-
return 0
420435

421436

422437
class TempDirExtractorContext(BaseExtractor):

0 commit comments

Comments
 (0)