PPSA02664
/ PPSA03416 - image+0xafc959, write to
0xfffe0
Highest value. Reached only once
sceKernelCreateSema was implemented (D193). Two titles,
identical. 0xfffe0 is around a megabyte - not a
null-plus-offset, so more likely a computed pointer that came out wrong,
and the run now says so in as many words: an address in no region
this run mapped, with rcx holding it and
rdx holding 0x100000.
One suspect eliminated. memalign was
the leading hypothesis. Forcing a dump for it with
ORBISTOUN_DUMP=memalign (D198) showed
arg0=0x8, arg1=0x1988 - a request that succeeds - so it is
not the source.
It is not a naming problem, and the argument was readable all
along. This used to say the next move was to name
libkernel::0x6abac2f3dc6f8cee. Every naming mechanism has
since been run to exhaustion and none reaches it (D213) - and it turned
out not to matter, because the argument answers the question
and had never been read. The readable window declared for dumps was a
guard page too low, so 0x600000800d38 fell in the one page
it excluded and rendered as a count (D217).
What it is, now that it dumps:
arg0 = 0x600000800d38 -> stack+0x800d38 = 00*8, 49 ba a2 01 00 00 00 00, 01, 00*8
arg1 = 0x100000 <- and the fault has rdx = 0x100000
arg2 = 0x0
arg3 = 0x40000
arg4 = 0x0
arg5 = 0x600000800db8 -> stack+0x800db8 = <image base>, 0x20, 0x10, 0x600000800ee0
0x100000 - 0x20 = 0xfffe0, which is the faulting address
exactly. The guest asks for a megabyte aligned to 256 KB, then indexes
base + size - 0x20 with base zero.
Two sources for that zero are eliminated, not argued about: it is
not the stub return (an unimplemented stub returns a
non-zero placeholder), and it is not unwritten memory
(ORBISTOUN_STACK_FILL=5a leaves arg0's first
eight bytes zero and the fault unmoved). The guest wrote that zero
itself, as an out-parameter it expected filled.
Characterised, and the first positive fact about it after
seven eliminations. Seven things were eliminated - the stub
return, unwritten stack, unwritten heap, both stack-pointing argument
targets, memalign, and the unfilled slot in the object the
fault carries. Every candidate for a lost base was gone, which
left the reading nobody had tested: that no base was lost and the
address was right.
Reserving 0xf0000+0x10000 for one run moved the fault
213 bytes on - and watching that region said why, and
contradicted the first reading of it (D224, corrected by
D226).
The guest writes {next, prev, .., count=1} there: a
circular list head with one node, an arena descriptor, whose lock is the
mutex at image+0x1a2ddb8 taken immediately before. It asks
for arg1 = 0x100000 bytes aligned to
arg3 = 0x40000 and lays that header at
region_end - 0x20 - so with the base lost,
region_end is 0 + 0x100000 and the header
lands at 0xfffe0.
So 0xfffe0 is not an address the guest wanted;
it is size - 0x20 from a base of zero, and the mapping only
gave a wrong pointer somewhere to land. The
FURTHER was bought by answering wrongly, which is the
progress principle 3 refuses to count.
What to do: libkernel::0x6abac2f3dc6f8cee is a
region allocator. arg1 is a size,
arg3 an alignment, and the caller wants a base it can put
an arena header at the top of. Implementing that is the fix; the mapping
must stay a diagnostic. Where the base is handed back is still open -
the return value, arg0 and arg5 are all
eliminated.