fix(hopper): probe interior navigation from multi-byte instructions (#1285)
The real-Hopper navigation probe derived its interior coordinate as anchor + 1, which assumes the fixture procedure's first instruction is longer than one byte. Host toolchains without endbr64-style prologue padding (Kali gcc 16, or any build with -fcf-protection=none) compile rea_entry to start with the one-byte push rbp, so anchor + 1 is itself an instruction boundary: goto_address correctly observes that boundary and the boundary-contract run rejects a correct bridge. Advance the probe to the first instruction followed by a coordinate gap larger than one byte and derive the interior-coordinate assertions from that instruction, so the probed coordinate is never an analyzed-object boundary on either prologue encoding.
This commit is contained in:
parent
392f1f3107
commit
bf934d5592
|
|
@ -91,14 +91,29 @@ async function verifyNavigation(
|
|||
);
|
||||
assert.equal(coordinates[0], address);
|
||||
assert.ok(coordinates[1], "fixture omitted a second instruction");
|
||||
const interior = `0x${(BigInt(address) + 1n).toString(16)}`;
|
||||
assert.equal(await call("goto_address", { address: interior }), address);
|
||||
assert.equal(await call("current_address"), address);
|
||||
// The host toolchain controls the prologue encoding: without endbr64-style
|
||||
// padding the first instruction is one byte, so address + 1 is itself an
|
||||
// instruction boundary. Probe from inside the first multi-byte instruction
|
||||
// so the interior coordinate is never an analyzed-object boundary.
|
||||
let anchor = 0;
|
||||
while (anchor + 1 < coordinates.length) {
|
||||
if (BigInt(coordinates[anchor + 1]) - BigInt(coordinates[anchor]) > 1n)
|
||||
break;
|
||||
anchor += 1;
|
||||
}
|
||||
assert.ok(
|
||||
anchor + 1 < coordinates.length,
|
||||
"fixture omitted a multi-byte instruction for interior navigation",
|
||||
);
|
||||
const containing = coordinates[anchor];
|
||||
const interior = `0x${(BigInt(containing) + 1n).toString(16)}`;
|
||||
assert.equal(await call("goto_address", { address: interior }), containing);
|
||||
assert.equal(await call("current_address"), containing);
|
||||
assert.equal(
|
||||
await call("next_address", { address: interior }),
|
||||
coordinates[1],
|
||||
coordinates[anchor + 1],
|
||||
);
|
||||
assert.equal(await call("prev_address", { address: interior }), address);
|
||||
assert.equal(await call("prev_address", { address: interior }), containing);
|
||||
for (const unmapped of ["0x0", "0xfffffffffffffffe"]) {
|
||||
for (const operation of ["goto_address", "next_address", "prev_address"])
|
||||
await invalid(
|
||||
|
|
@ -106,7 +121,7 @@ async function verifyNavigation(
|
|||
{ address: unmapped },
|
||||
/Address is outside every segment/u,
|
||||
);
|
||||
assert.equal(await call("current_address"), address);
|
||||
assert.equal(await call("current_address"), containing);
|
||||
for (const operation of [
|
||||
"set_address_name",
|
||||
"set_bookmark",
|
||||
|
|
|
|||
Loading…
Reference in New Issue