Skip to content

Commit 361be20

Browse files
committed
Fix handling of LZ4 legacy frames.
There is no end magic after the compressed content, but we can detect it given that except for the last block, all blocks are 8MB uncompressed. Inspired by vmlinux-to-elf (see https://github.com/marin-m/vmlinux-to-elf/blob/master/vmlinux_to_elf/utils/lz4_legacy.py).
1 parent 736b0b4 commit 361be20

File tree

3 files changed

+46
-2
lines changed

3 files changed

+46
-2
lines changed

poetry.lock

Lines changed: 37 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pluggy = "^1.0.0"
2828
file-magic = "^0.4.0"
2929
hyperscan = "^0.2.0"
3030
lark = "^1.1.2"
31+
lz4 = "^4.0.0"
3132

3233

3334
[tool.poetry.dev-dependencies]

unblob/handlers/compression/lz4.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import io
55
from typing import Optional
66

7+
from lz4.block import decompress
78
from structlog import get_logger
89

910
from unblob.extractors import Command
@@ -28,6 +29,7 @@
2829
FRAME_SIZE_LEN
2930
) = BLOCK_CHECKSUM_LEN = CONTENT_CHECKSUM_LEN = MAGIC_LEN = DICTID_LEN = 4
3031
FLG_LEN = BD_LEN = HC_LEN = 1
32+
MAX_LEGACY_BLOCK_SIZE = 8 * 1024 * 1024 # 8 MB
3133

3234

3335
class FLG:
@@ -89,7 +91,12 @@ def calculate_chunk(self, file: File, start_offset: int) -> Optional[ValidChunk]
8991
file.seek(-4, io.SEEK_CUR)
9092
break
9193

92-
file.seek(block_compressed_size, io.SEEK_CUR)
94+
compressed_block = file.read(block_compressed_size)
95+
uncompressed_block = decompress(compressed_block, MAX_LEGACY_BLOCK_SIZE)
96+
97+
# See 'fixed block size' in https://android.googlesource.com/platform/external/lz4/+/HEAD/doc/lz4_Frame_format.md#legacy-frame
98+
if len(uncompressed_block) < MAX_LEGACY_BLOCK_SIZE:
99+
break
93100

94101
end_offset = file.tell()
95102
return ValidChunk(start_offset=start_offset, end_offset=end_offset)

0 commit comments

Comments
 (0)