Skip to content

fix(rar5): correct x86 E8/E9 filter range checks (corrupts real executables) - #121

Open
jdlien wants to merge 2 commits into
KarpelesLab:masterfrom
jdlien:rar5-x86-filter-fix
Open

fix(rar5): correct x86 E8/E9 filter range checks (corrupts real executables)#121
jdlien wants to merge 2 commits into
KarpelesLab:masterfrom
jdlien:rar5-x86-filter-fix

Conversation

@jdlien

@jdlien jdlien commented Jul 16, 2026

Copy link
Copy Markdown

The decode-direction x86 filter flattens unrar's nested sign check into an else if, so a negative operand that stays negative after adding the position — a byte pattern the encoder never rewrote (e.g. a stray 0xE8 inside a ModRM/displacement sequence) — falls through and gets the position wrongly subtracted, corrupting real x86 code.

Found by differential testing against WinRAR 7.23 + UnRAR: the first 32 KiB of notepad.exe compressed with -ma5 -m3 (filter type 1, X86Call) decoded to the right length but 48 wrong bytes across 15 sites, each the operand after a false-positive 0xE8. Nesting the checks as unrar/libarchive do makes it decode byte-identical to unrar. Regression tests carry the verbatim case plus both boundary companions.

Second commit is an unrelated one-liner: tests/adc.rs uses {:#02x}, which current stable clippy rejects (unused_format_specs) under -D warnings, failing the --all-features test build. Folded in so CI is green here; happy to split it out if you'd prefer.

jdlien added 2 commits July 16, 2026 10:28
The decode-direction address fixup flattened unrar's nested condition
into an else-if:

    if (addr < 0)  { if (addr + off >= 0)  addr += FILE_SIZE; }
    else           { if (addr < FILE_SIZE) addr -= off;       }

A negative operand that stays negative after adding the position (a
byte pattern the encoder never rewrote, e.g. a stray 0xE8 inside a
ModRM/displacement sequence followed by high bytes) fell through into
the (addr - FILE_SIZE) check, which any negative value passes, and got
the position wrongly subtracted.

Found by differential testing against WinRAR 7.23 + UnRAR: the first
32 KiB of notepad.exe compressed with -ma5 -m3 (filter type 1, X86Call)
decoded to the right length but 48 wrong bytes across 15 sites, each
the 4-byte operand after a false-positive 0xE8; every wrong value was
exactly (original - position). With the nested checks the whole
corpus decodes byte-identical to unrar. Regression test carries the
verbatim case from that archive plus both boundary companions.
`{:#02x}` sets a width of 2 that the `#` (0x) alternate form makes
inapplicable, so current stable clippy fails the --all-features test
build under -D warnings. Use `{:#04x}` for the intended two-digit form.
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