Files
velzieandClaude Opus 5.5 24adf39bcb browser: instruction fetch reads to the end of an executable mapping (a + INST_ALIGN, not a + 4)
The page's executable test for instruction fetch asked a + 4 <= end, from
the AArch64 build, and fetch asks it of every byte: on x86 the last three
bytes of every executable mapping were not code, so an instruction ending
there decoded short and the process died as an illegal instruction (status
132). Unity's own Mono hit it in its JIT code: a jmp rel32 at a 64 KiB
chunk's +0xfffa (Muck, dm10: 'illegal instruction 0x005611e9 at
pc=0x3a204ffa'). The native host asks a + INST_ALIGN.

tests/x86-programs/exec-tail.c: code whose last byte is a mapping's last
byte, tails of 1 to 8 bytes; on the page tier before the fix: illegal
instruction at +0xffb, status 132; after: as natively. tgkill-futex's ack
counter is atomic (natively the handlers raced and printed 11).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_1896c5b302a54696aaa92c5f4047f20b
2026-10-09 12:50:12 -04:00

35 lines
1.2 KiB
C

// Code that ends in the last bytes of an executable mapping: a JIT's chunk
// (Mono's) can end with a 5-byte jmp in its final bytes. Each case puts
// `mov eax, imm32; ret` so that the ret is the mapping's last byte, then
// shorter tails down to a lone `ret`.
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
int main(void) {
long sum = 0;
for (int tail = 1; tail <= 8; tail++) {
unsigned char *p = mmap(0, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (p == MAP_FAILED) return 1;
memset(p, 0xcc, 4096);
unsigned char *f;
if (tail >= 6) {
f = p + 4096 - 6;
unsigned char code[6] = {0xb8, (unsigned char)(40 + tail), 0, 0, 0, 0xc3};
memcpy(f, code, 6);
} else {
// a short jmp back from the tail to a body earlier in the page, then the tail is a jmp rel32 ending at the last byte
f = p + 4096 - 5;
unsigned char *body = p + 64;
unsigned char code[6] = {0xb8, (unsigned char)(40 + tail), 0, 0, 0, 0xc3};
memcpy(body, code, 6);
int rel = (int)(body - (f + 5));
f[0] = 0xe9; memcpy(f + 1, &rel, 4);
}
int (*fn)(void) = (int (*)(void))f;
sum += fn();
munmap(p, 4096);
}
printf("exec-tail sum %ld\n", sum);
return 0;
}