The five Linux rel32 sites subtracted addresses and range-checked the
signed result, so two addresses more than 2^63 apart wrapped into a
small in-range displacement and was written verbatim. SignedDistance
now classifies both addresses by the 2^63 boundary, takes the
high-minus-low magnitude as a plain subtraction and rejects a distance
whose magnitude exceeds int64. The new linux_load_pages test places a
site at 0x500 and the body near 2^64: main wrote a wrapped rel32, the
change throws.
Crafted program headers can map a load segment so its page end sits at
2^63, which places the patcher's extra block above the boundary while
the original code sites stay below it. The trampoline, import trace and
guest module displacement math subtracted addresses as two int64 casts,
which overflows for such pairs before the rel32 range check runs.
Subtract in unsigned arithmetic and cast the true difference once, as
the entry stub builder already does.
On Linux the kernel maps each PT_LOAD from the start of its first page.
When a segment begins inside the page that holds the end of the previous
segment's zero-filled memory, that page is mapped again from the file, and
the bss tail reads whatever bytes precede the segment in the file. Nuvio
Max'd 0.5.27 (PPSA99288) keeps a mutex there and crashes at launch.
A segment whose page would read wrong bytes is now appended to the output
with that page prefix rebuilt from the segments below it. Outputs whose
pages already read right are unchanged.
Co-Authored-By: Claude Opus 5.5 <[email protected]>