From 3969b7c103207517b6ace3d5c56e5261e73ac24a Mon Sep 17 00:00:00 2001 From: urknall Date: Tue, 10 Mar 2026 12:56:07 +0100 Subject: [PATCH] fix: handle negative node read size in ubifs walk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In ubi_reader ≤0.8.13 (master as of 2026-03), _index() computes read_size = chdr.len - UBIFS_COMMON_HDR_SZ node_buf = ubifs.file.read(read_size) without first checking that read_size >= 0. A zero-filled erase block (factory bad block, or any block whose first bytes are all 0x00) causes the common-node header to be read as all-zeros, so chdr.len == 0 and read_size == -24 (== -UBIFS_COMMON_HDR_SZ). Python's io.BufferedReader raises ValueError: read length must be non-negative or -1 which propagates through walk.index() and is caught by extract_files as: extract_files Error: read length must be non-negative or -1 This aborts the entire UBIFS extraction even though only one LEB is affected and the rest of the filesystem is intact. Fix: add a bounds check for read_size < 0 immediately after the subtraction, matching the style of the adjacent len(buf) guard that already handles the case where the common header itself is short: - With -w / --warn-only-block-read-errors the corrupted node is skipped with an 'Error'-level message and _index() returns. - Without -w the existing 'Fatal' path is taken, preserving the pre-fix behaviour for strict mode. --- ubireader/ubifs/walk.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ubireader/ubifs/walk.py b/ubireader/ubifs/walk.py index eb97262..cf6bbe0 100755 --- a/ubireader/ubifs/walk.py +++ b/ubireader/ubifs/walk.py @@ -90,6 +90,12 @@ def _index(ubifs: Ubifs, lnum: int, offset: int, inodes: MutableMapping[int, Ino log(index , '%s file addr: %s' % (chdr, ubifs.file.last_read_addr())) verbose_display(chdr) read_size = chdr.len - UBIFS_COMMON_HDR_SZ + if read_size < 0: + if settings.warn_only_block_read_errors: + error(index, 'Error', 'LEB: %s at %s, Node len (%s) < common header size, skipping.' % (lnum, ubifs.leb_size * lnum + offset, chdr.len)) + return + else: + error(index, 'Fatal', 'LEB: %s at %s, Node len (%s) < common header size.' % (lnum, ubifs.leb_size * lnum + offset, chdr.len)) node_buf = ubifs.file.read(read_size) file_offset = ubifs.file.last_read_addr()