Skip to content

UdfIn: fix OOB read in CFileId::Parse alignment padding loop - #263

Open
tonghuaroot wants to merge 1 commit into
p7zip-project:masterfrom
tonghuaroot:fix/udf-fileid-alignment-oob-26.01
Open

UdfIn: fix OOB read in CFileId::Parse alignment padding loop#263
tonghuaroot wants to merge 1 commit into
p7zip-project:masterfrom
tonghuaroot:fix/udf-fileid-alignment-oob-26.01

Conversation

@tonghuaroot

Copy link
Copy Markdown

Backports the bounds-check addition landed in upstream 7-Zip 26.01 (released 2026-04-27).

What changed upstream

After consuming the 38-byte fixed File Identifier descriptor header plus the variable-length impLen and idLen fields, CFileId::Parse advances processed up to 3 bytes to reach the next 4-byte boundary while requiring those bytes to be zero. In p7zip the loop reads p[processed] without verifying processed < size:

```cpp
for (;(processed & 3) != 0; processed++)
if (p[processed] != 0)
return S_FALSE;
```

26.01 short-circuits the loop with a bounds check:

```cpp
for (; processed & 3; processed++)
if (processed >= size || p[processed])
return S_FALSE;
```

Impact

Pre-loop, the only available bound is size >= 38 + idLen + impLen == processed (note: < not <= in the pre-check). When the crafted UDF File Identifier descriptor fills the buffer exactly to the fixed-plus-variable size, the alignment loop reads up to 3 bytes past the buffer end on attacker-controlled input.

Patch

Byte-for-byte matches upstream 26.01 for the loop hunk.

Disclosure

I am not a native English speaker. AI tooling was used to polish the prose in this PR description. The fix itself is a direct backport from upstream 7-Zip 26.01 source; no design choices were made beyond matching upstream verbatim.

Upstream 7-Zip 26.01 added a bounds check to the trailing
alignment-padding loop in CFileId::Parse(). After consuming the
38-byte fixed header plus the variable-length impLen and idLen
fields, the loop advances `processed` up to 3 bytes to reach the
next 4-byte boundary while requiring those bytes to be zero.

In p7zip's pre-fix code, that loop reads p[processed] without
verifying that `processed < size`. Pre-loop the only guarantee is
`size >= 38 + idLen + impLen == processed` (note: `<` not `<=`),
so when the crafted UDF File Identifier descriptor fills the buffer
exactly to the fixed-plus-variable size, the loop reads up to 3
bytes past the buffer end on attacker-controlled input.

This patch matches upstream 7-Zip 26.01: short-circuit the loop
condition with `processed >= size` so the OOB index can never be
dereferenced. The post-loop `(processed <= size) ? S_OK : S_FALSE`
check is now redundant since the loop guards `processed < size`.

Signed-off-by: tonghuaroot <tonghuaroot@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant