software bounds guard wraps at the address-space top: ADD-computed end address escapes the OOB trap for multi-byte accesses (found by the #166 derived trap gate) #752
Description
Found RED by the VCR-VER-002 derived-ARM-trap gate (#166, v0.43 verification-closure lane): the i32 load/store OOB trap-preservation VC rejects the SHIPPED --safety-bounds software guard shape for multi-byte accesses, with counterexamples pinned at the top of the address space.
The divergence
generate_load_with_bounds_check / the store twin (crates/synth-synthesis/src/instruction_selector.rs) emit:
ADD r12, addr, #(offset + size - 1) ; end address — WRAPPING 32-bit add
CMP r12, r10 ; r10 = linear-memory size
BLO +0 ; in-bounds skips the trap
UDF #0
LDR/STR ...
WASM Core's effective-address check is EXACT arithmetic: trap iff addr + offset + size > mem_size. The guard computes addr + (offset+size-1) mod 2^32: for addr >= 2^32 - (offset+size-1) the end address wraps to a small value, BLO passes, and the access goes through — reading/writing below the linear-memory base (the LDR [r11, addr, #offset] hardware address also wraps). Example (word load, offset 0): addr = 0xFFFF_FFFF → r12 = 3 < r10 → no trap; WASM requires one.
Byte accesses with offset 0 are exact (end = addr + 0 cannot wrap) — the gate verifies that case green, so this is specifically the multi-byte / non-zero-offset class.
Evidence
crates/synth-verify/src/translation_validator.rstestword_load_software_bounds_guard_wraps_at_address_toppins the divergence asInvalidwith the counterexample restricted toaddr >= 0xFFFF_FFFD(flip it toVerifiedwhen this is fixed).- Test
wraparound_safe_bounds_guard_verifiesproves the gate is satisfiable by a correct guard, i.e. the red is not vacuous:
CMP r10, #k; BHS +0; UDF(bound < k ⇒ always trap) thenSUB r12, r10, #k; CMP addr, r12; BLS +0; UDFwithk = offset + size— exact on both paths, same instruction count +3.
Severity / exploitability
Requires a WASM-side address in the top ~3 bytes of the i32 address space, so any module whose index arithmetic can be attacker-influenced can escape the software bounds check downward by up to offset+size-1 bytes below the heap base. MPU/masking modes are unaffected (#651's masking clamps the effective address; MPU faults on the physical access).
Related: #377 (inline UDF bounds trap), #651 (masking mode), #166 (trap-preservation VC).
Activity
feat(#166): live trap-preservation VC — derived ARM trap terms for di…
verification-arc closure: LIVE trap-preservation VC for five trap cla…
fix(#752): wraparound-safe software bounds guard — SUB-from-bound sha…
test(#752): flip the pinned wraparound divergence to Verified — gate …
test(#752): re-pin the #494 bounds-elision byte evidence to the wrapa…
fix(#752): RISC-V twin — software guard compares addr against the com…
test(#752): wraparound differential rows + CI wiring — 19 vectors x b…
test(#752)/docs: re-pin the optimized-path guard byte probe + guard-s…
fix(#752): wraparound-safe software bounds guard — the ADD-computed e…
chore(release): v0.43.0 — isolation + verification closure (multi-mem…
chore(release): v0.43.0 — isolation + verification closure (multi-mem…