Skip to content

Commit 75dbefc

Browse files
imsahil007terriko
authored andcommitted
fix: extract apk packages for alpine and android (#1258)
1 parent 0a5fdc3 commit 75dbefc

File tree

3 files changed

+55
-15
lines changed

3 files changed

+55
-15
lines changed

cve_bin_tool/async_utils.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,18 +73,18 @@ def run_coroutine(coro):
7373
return result
7474

7575

76-
async def aio_run_command(args):
76+
async def aio_run_command(args, process_can_fail=False):
7777
process = await asyncio.create_subprocess_exec(
7878
*args,
7979
stdout=asyncio.subprocess.PIPE,
8080
stderr=asyncio.subprocess.PIPE,
8181
)
8282
stdout, stderr = await process.communicate()
83-
if process.returncode != 0:
83+
if process.returncode != 0 and not process_can_fail:
8484
raise subprocess.CalledProcessError(
8585
args, process.returncode, output=stdout, stderr=stderr
8686
)
87-
return stdout, stderr # binary encoded
87+
return stdout, stderr, process.returncode # binary encoded
8888

8989

9090
class ChangeDirContext:

cve_bin_tool/extractor.py

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"""
99
import itertools
1010
import os
11+
import re
1112
import shutil
1213
import sys
1314
import tempfile
@@ -47,11 +48,11 @@ def __init__(self, logger=None, error_mode=ErrorMode.TruncTrace):
4748
self.extract_file_rpm: {".rpm"},
4849
self.extract_file_deb: {".deb", ".ipk"},
4950
self.extract_file_cab: {".cab"},
51+
self.extract_file_apk: {".apk"},
5052
self.extract_file_zip: {
5153
".exe",
5254
".zip",
5355
".jar",
54-
".apk",
5556
".msi",
5657
".egg",
5758
".whl",
@@ -78,13 +79,13 @@ async def extract_file_rpm(self, filename, extraction_path):
7879
if not await aio_inpath("rpm2cpio") or not await aio_inpath("cpio"):
7980
await rpmextract("-xC", extraction_path, filename)
8081
else:
81-
stdout, stderr = await aio_run_command(["rpm2cpio", filename])
82+
stdout, stderr, _ = await aio_run_command(["rpm2cpio", filename])
8283
if stderr or not stdout:
8384
return 1
8485
cpio_path = os.path.join(extraction_path, "data.cpio")
8586
async with FileIO(cpio_path, "wb") as f:
8687
await f.write(stdout)
87-
stdout, stderr = await aio_run_command(
88+
stdout, stderr, _ = await aio_run_command(
8889
["cpio", "-idm", "--file", cpio_path]
8990
)
9091
if stdout or not stderr:
@@ -94,13 +95,13 @@ async def extract_file_rpm(self, filename, extraction_path):
9495
with ErrorHandler(mode=self.error_mode, logger=self.logger):
9596
raise Exception("7z is required to extract rpm files")
9697
else:
97-
stdout, stderr = await aio_run_command(["7z", "x", filename])
98+
stdout, stderr, _ = await aio_run_command(["7z", "x", filename])
9899
if stderr or not stdout:
99100
return 1
100101
filenames = await aio_glob(os.path.join(extraction_path, "*.cpio"))
101102
filename = filenames[0]
102103

103-
stdout, stderr = await aio_run_command(["7z", "x", filename])
104+
stdout, stderr, _ = await aio_run_command(["7z", "x", filename])
104105
if stderr or not stdout:
105106
return 1
106107
return 0
@@ -111,45 +112,82 @@ async def extract_file_deb(self, filename, extraction_path):
111112
with ErrorHandler(mode=self.error_mode, logger=self.logger):
112113
raise Exception("'ar' is required to extract deb files")
113114
else:
114-
stdout, stderr = await aio_run_command(["ar", "x", filename])
115+
stdout, stderr, _ = await aio_run_command(["ar", "x", filename])
115116
if stderr:
116117
return 1
117118
datafile = await aio_glob(os.path.join(extraction_path, "data.tar.*"))
118119
with ErrorHandler(mode=ErrorMode.Ignore) as e:
119120
await aio_unpack_archive(datafile[0], extraction_path)
120121
return e.exit_code
121122

123+
async def extract_file_apk(self, filename, extraction_path):
124+
"""Check whether it is alpine or android package"""
125+
126+
is_tar = True
127+
process_can_fail = True
128+
if await aio_inpath("unzip"):
129+
stdout, stderr, return_code = await aio_run_command(
130+
["unzip", "-l", filename], process_can_fail
131+
)
132+
if return_code == 0:
133+
is_tar = False
134+
elif await aio_inpath("7z"):
135+
stdout, stderr, return_code = await aio_run_command(
136+
["7z", "t", filename], process_can_fail
137+
)
138+
if re.search(b"Type = Zip", stdout):
139+
is_tar = False
140+
elif await aio_inpath("zipinfo"):
141+
stdout, stderr, return_code = await aio_run_command(
142+
["zipinfo", filename], process_can_fail
143+
)
144+
if return_code == 0:
145+
is_tar = False
146+
elif await aio_inpath("file"):
147+
stdout, stderr, return_code = await aio_run_command(
148+
["file", filename], process_can_fail
149+
)
150+
if re.search(b"Zip archive data", stdout):
151+
is_tar = False
152+
if is_tar:
153+
self.logger.debug(f"Extracting {filename} as a tar.gzip file")
154+
with ErrorHandler(mode=ErrorMode.Ignore) as e:
155+
await aio_unpack_archive(filename, extraction_path, format="gztar")
156+
return e.exit_code
157+
else:
158+
return await self.extract_file_zip(filename, extraction_path)
159+
122160
@staticmethod
123161
async def extract_file_cab(filename, extraction_path):
124162
"""Extract cab files"""
125163
if sys.platform.startswith("linux"):
126164
if not await aio_inpath("cabextract"):
127165
raise Exception("'cabextract' is required to extract cab files")
128166
else:
129-
stdout, stderr = await aio_run_command(
167+
stdout, stderr, _ = await aio_run_command(
130168
["cabextract", "-d", extraction_path, filename]
131169
)
132170
if stderr or not stdout:
133171
return 1
134172
else:
135-
stdout, stderr = await aio_run_command(
173+
stdout, stderr, _ = await aio_run_command(
136174
["Expand", filename, "-R -F:*", extraction_path]
137175
)
138176
if stderr or not stdout:
139177
return 1
140178
return 0
141179

142180
@staticmethod
143-
async def extract_file_zip(filename, extraction_path):
181+
async def extract_file_zip(filename, extraction_path, process_can_fail=False):
144182
"""Extract zip files"""
145183
if await aio_inpath("unzip"):
146-
stdout, stderr = await aio_run_command(
184+
stdout, stderr, _ = await aio_run_command(
147185
["unzip", "-n", "-d", extraction_path, filename]
148186
)
149187
if stderr or not stdout:
150188
return 1
151189
elif await aio_inpath("7z"):
152-
stdout, stderr = await aio_run_command(["7z", "x", filename])
190+
stdout, stderr, _ = await aio_run_command(["7z", "x", filename])
153191
if stderr or not stdout:
154192
return 1
155193
else:

test/test_strings.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ async def _parse_test(self, filename):
2727
"""Helper function to parse a binary file and check whether
2828
the given string is in the parsed result"""
2929
self.strings.filename = os.path.join(ASSETS_PATH, filename)
30-
binutils_strings, _ = await aio_run_command(["strings", self.strings.filename])
30+
binutils_strings, _, _ = await aio_run_command(
31+
["strings", self.strings.filename]
32+
)
3133
ours = await self.strings.aio_parse()
3234
for theirs in binutils_strings.splitlines():
3335
assert theirs.decode("utf-8") in ours

0 commit comments

Comments
 (0)