Files
chimera-gfx-Public/docs/runtime/phase-0.9c-startup-exit-feasibility.md
T
Chimera GFX release export a6037502d7
phase0-ci / build-and-audit (push) Successful in 2m14s
Publish Chimera GFX source
2026-09-03 03:27:14 +02:00

16 KiB

Phase 0.9C startup and exit feasibility

Status: BLOCKED. This is a source-bound offline analysis. It does not add an observer, target source, PS5 object, ELF, linker map, installation package, lifecycle package, transfer path, or execution authority.

Evidence boundary

The exact reviewed sources are:

Component Commit Relevant file identity
hardened elfldr 197623058f509eddde18868dafcb92fdcac66464 elfldr.c SHA-256 9949f8e4037984d10f1f5aa498e4665593d1fac8a33614d7f2141349839bb803
hardened elfldr controlled route same socksrv.c SHA-256 d642ced3e9b4a296dd15e355050ebe956f53a6dfdaa6ac10109cd067a3bba3d7
hardened cleanup model same controlled_runtime.c SHA-256 10145f3bbb3b54e3d715b1667e45c6f12d3c7f52a04342ab104ec8dd49e384c9
hardened PS5 cleanup adapter same ps5_controlled.c SHA-256 68717ef1cc31c483743c5af325c59e73a90f66e93b880b989e349a4ddc748772
controlled Payload Manager e23d94ff91233aa770e2342800c1467875bdef44 verified_launcher.c SHA-256 066100ca4917c7acc560e2e85666ca136cd7ccfd9094417377048f41106dd56e
controlled manager adapter same ps5_launcher.c SHA-256 29c1a5fd01784a59e88b3698940f120cb03020071bc2b7d74a1da1a51524ef59
PS5 Payload SDK v0.41 d2e2e585740362976a39fdd5ccf390f199a7bc37 crt/crt.c SHA-256 3875f4739ec40b33f1f4967a1acbb585a527d2c281a360153e1f69c8b945932a
SDK patch implementation same crt/patch.c SHA-256 4f76a677bba54f4641e1cf2755768c29afb7464a35b2f21e85db2aa2785eceac
SDK CRT object set same crt/Makefile SHA-256 6a62f777f32ab05cbe7bff81c00cfd6639ba8bf440aba611a40ff0b62732568b
SDK compiler wrapper same host/bin/prospero-clang SHA-256 0cf49ae43d6110a7606c0ee4d702fc4b5d5e1c3ae9a722945a48b80294e295ba
SDK linker script same host/elf_x86_64.x SHA-256 169b80d01da601ef96bbc584986608dec1d9c01397eae81eccd4e1a66b0a6c6a

The public bases remain elfldr 699e8bcff03e91e8d6ca6eba281af25c5a58d8c2 and Payload Manager cfbc70f30f419b09bf2b52283f7409e2d3117ee1. The lifecycle source remains bound to commit fe08300339a13f899fb78ea404ada381a5cba87c; its unchanged samples/lifecycle_probe/main.c is 1ae7df1fe921ccab2a252f77975d3d441ef7725e34535b024580c0d4a242d766. None of these historical target sources was modified.

Classifications in this document mean:

  • PROVEN_SAFE: the cited source proves the narrow property stated;
  • PROVEN_SIDE_EFFECTING: the cited source proves a state change or external operation, whether or not an earlier phase accepted it;
  • UNPROVEN: evidence required for the claimed contract is absent;
  • NOT_APPLICABLE: the path deliberately excludes the facility.

PROVEN_SAFE never means hardware-tested.

Loader-to-entry call graph

The controlled route has this source-proven graph:

controlled manager
|- open_verified
|  |- open(O_RDONLY | O_NOFOLLOW | O_CLOEXEC)
|  |- fstat -> bounded read/SHA-256 -> fstat
|  `- lseek(fd, 0)
|- connect_loopback
|- send_all(control header)
|- send_all(exact ELF bytes)
`- close_socket

hardened elfldr on_connection
|- recv/validate controlled header
|- recv exact payload bytes -> independent SHA-256
|- payload_spawn(route=CONTROLLED)
|  `- elfldr_spawn(stdio=-1)
|     |- rfork_thread -> child execve(SceSpZeroConf)
|     |- wait for exec/stop under finite preparation waits
|     |- pt_syscall(process-needed-and-relocate)
|     |- change child heap-size parameter
|     |- make entry page RWX
|     |- install INT3 -> continue -> stop
|     |- restore byte and RX protection
|     |- map payload PT_LOAD image
|     |- apply R_X86_64_RELATIVE relocations
|     |- map payload_args_t page
|     |- create two IPv6 sockets, overlap them, and create a pipe
|     |- back up child credentials
|     |- raise child credentials
|     |- write saved RIP to [RSP-8]
|     |- set RSP=RSP-8, RIP=ELF entry, RDI=payload_args_t*
|     |- restore all five credential fields
|     `- ptrace detach
|- watchdog wait/reap
|  `- on timeout: SIGTERM -> grace -> SIGKILL -> reap
`- write fixed loader-generated exit text

Sources: hardened elfldr socksrv.c:129-157,162-215,289-375; elfldr.c:80-265,273-415,480-545,643-769; controlled_runtime.c:60-92,95-143,146-220,223-250; and ps5_controlled.c:26-59,132-220. The manager side is verified_launcher.c:31-184, include/verified_launcher.h:38-42, and ps5_launcher.c:18-69.

Entry contract classification

Property Classification Evidence and consequence
entry symbol comes from e_entry PROVEN_SAFE elfldr.c:143-265 returns base + e_entry.
first argument in RDI PROVEN_SAFE elfldr.c:401-409 sets r_rdi to the loader-created argument page.
synthetic return address PROVEN_SIDE_EFFECTING elfldr.c:401-407 writes the observed RIP at RSP-8 and moves RSP; the child stack is changed.
x86-64 stack alignment at entry UNPROVEN the loader subtracts eight but never validates the trapped RSP alignment.
meaning and safety of saved RIP UNPROVEN it is the RIP observed at the breakpoint; no reviewed contract proves the post-ret continuation.
preserved general/SIMD register set UNPROVEN source changes RSP, RIP, and RDI but defines no caller/callee preservation contract for a custom entry.
argument layout PROVEN_SAFE SDK include/ps5/payload.h:27-36 and elfldr elfldr.c:349-367 agree on six x86-64 fields.
argument ownership PROVEN_SIDE_EFFECTING elfldr maps and populates the page in the child at elfldr.c:273-372.
argument lifetime after return or exit UNPROVEN success clears the loader cleanup bitmap at elfldr.c:538-545; the mapping then relies on child lifetime/OS teardown.
image mapping PROVEN_SIDE_EFFECTING elfldr allocates child mappings, copies bytes, changes protection, and calls msync at elfldr.c:143-265.
relocation support PROVEN_SAFE only for R_X86_64_RELATIVE elfldr.c:208-222; no complete freestanding artifact exists whose relocations can be checked.
BSS zero-fill by loader UNPROVEN and source-negative base_mirror comes from malloc; data_load copies only p_filesz, then the entire mirror is copied. No zero-fill is visible at elfldr.c:96-109,183-224.
TLS setup UNPROVEN elfldr has no reviewed TLS setup in this path; no future observer layout exists.
constructors/destructors NOT_APPLICABLE to a proposed freestanding entry they are a stock CRT facility and are forbidden for the proposed path.

Normal SDK v0.41 startup

The exact normal graph is:

_start(payload_args_t *)
|- clear [__bss_start, __bss_end)
|- store payload_args
|- payload_init
|  |- __crt_syscall_init
|  |- __kernel_init
|  |- __klog_init
|  |- resolve __isthreaded and write 1
|  |- __patch_init
|  |  |- get process/ucred state
|  |  |- write credential capability bytes
|  |  |- write credential attribute bytes
|  |  |- write syscall lower bound 0
|  |  `- write syscall upper bound -1
|  `- __rtld_init
|- setjmp
|- payload_run
|  |- resolve argc/argv/environ/progname
|  |- create/open payload rtld object
|  |- load DT_NEEDED dependencies and relocate
|  |- run init array
|  |- main
|  |- run fini array
|  `- close/destroy rtld object
`- payload_terminate
   |- return 0 for the runtime's detected hijacked-process case
   |- resolve and call exit(payloadout)
   `- trap if exit resolution/call returns

Sources: SDK crt/crt.c:30-44,51-80,88-146,154-180,197-220; crt/patch.c:27-100; crt/rtld_payload.c:51-60,203-260; and crt/Makefile:19-26,50-54.

Step Classification Reason
BSS clear PROVEN_SIDE_EFFECTING writes every byte in the payload BSS; deterministic and process-local, but still a mutation.
global argument/setjmp state PROVEN_SIDE_EFFECTING writes CRT BSS state.
syscall/kernel/klog bootstrap PROVEN_SIDE_EFFECTING consumes loader-provided kernel transport and initializes global function/state.
__isthreaded = 1 PROVEN_SIDE_EFFECTING writes resolved libc state at crt.c:65-69.
__patch_init PROVEN_SIDE_EFFECTING and prohibited exact capability, attribute, and syscall-bound kernel writes occur before main.
rtld initialization PROVEN_SIDE_EFFECTING resolves functions, allocates bookkeeping, and can load/start Sce modules.
relocation and DT_NEEDED processing PROVEN_SIDE_EFFECTING writes relocations and opens dependencies.
constructors PROVEN_SIDE_EFFECTING arbitrary linked constructor effects are permitted by this path.
heap use PROVEN_SIDE_EFFECTING stock rtld resolves and uses allocation functions.
main UNPROVEN for an observer no Phase-0.9C target implementation exists.
destructors and rtld close PROVEN_SAFE only as attempted normal-path calls no proof covers partial initialization, longjmp, trap, crash, or module-internal cleanup.
payload_terminate branch selection UNPROVEN the actual branch and its platform semantics are not bound to an observer execution.

The normal SDK startup is therefore not kernelwrite-free and is unsuitable for Phase 0.9C. The fact that Phase 0.7 accepted its bounded, process-local effects for a different lifecycle profile does not satisfy this phase's stricter contract.

Error and abnormal paths

Initialization error

_start writes the error to payloadout and calls payload_terminate (crt.c:207-210). A failure after credential capabilities were written but before all patch writes finish has no CRT restoration path. A failure during rtld initialization has no demonstrated full unwind in _start.

Classification: PROVEN_SIDE_EFFECTING for partial startup and UNPROVEN for complete restoration and termination.

Runtime error

payload_run attempts close/destroy on some open/init/fini failures (crt.c:116-146). These are source-proven calls, not proof of module, heap, TLS, file-descriptor, or process cleanup on firmware 9.60.

Classification: PROVEN_SAFE for the presence of the attempted calls; UNPROVEN for complete cleanup.

payload_exit

payload_exit writes payloadout and longjmps to _start (crt.c:175-180). The longjmp leaves payload_run; _start proceeds directly to payload_terminate, so the normal fini/close/destroy sequence is not on that control path.

Classification: PROVEN_SIDE_EFFECTING; full cleanup is UNPROVEN.

Trap, crash, unexpected return, and timeout

  • payload_terminate deliberately traps if its resolved exit path returns or cannot be used (crt.c:162-170).
  • The controlled watchdog treats any reaped child as completion but discards the waitpid status (ps5_controlled.c:36-59).
  • If the child remains alive, the watchdog uses SIGTERM, then SIGKILL, and reaps it (controlled_runtime.c:223-250).
  • The connection handler emits the same fixed success text after payload_spawn returns a nonnegative value (socksrv.c:361-365).

A trap/crash can therefore be indistinguishable from a normal exit to the manager, and timeout termination is not a safe exit under the Phase-0.9C rules. Classification: UNPROVEN for crash cleanup and status meaning; PROVEN_SIDE_EFFECTING and inadmissible for signal termination.

Freestanding feasibility without target implementation

prospero-clang omits crt1.o for -nostartfiles and omits libc, libkernel_web, libSceLibcInternal, and libSceNet for -nodefaultlibs (host/bin/prospero-clang:25-46,69-84). This proves driver suppression only. No custom entry source or target was assembled or linked.

Required facility Theoretical availability Classification
entry address ELF e_entry is transferred to RIP PROVEN_SAFE narrow loader fact
valid stack memory an existing child stack is used UNPROVEN size, alignment, guard, and post-return contract
small automatic buffers mechanically possible if the stack contract holds UNPROVEN
read-only constants PT_LOAD bytes can be mapped and protected PROVEN_SAFE only for loader mapping; relocation closure is artifact-dependent
BSS loader does not prove zero-fill; a custom clear is mechanically possible UNPROVEN until a reviewed entry and map exist
TLS no freestanding TLS contract UNPROVEN
constructors/destructors excluded NOT_APPLICABLE
heap excluded NOT_APPLICABLE
libc/stdio excluded by design NOT_APPLICABLE
raw syscalls no callable observer syscall ABI is supplied by payload_args_t UNPROVEN
system calls from injected text SDK patch widens permitted syscall address bounds UNPROVEN without the prohibited patch
monotonic time hardened loader has a clock, but exposes no clock callback to the payload UNPROVEN in the entry
filesystem open/read/fstat/close requires unresolved imports, a proven raw-syscall ABI, or another supplied callback UNPROVEN
process/service/listener queries no freestanding callable ABI is supplied UNPROVEN
normal ret mechanically reaches the saved RIP UNPROVEN continuation and cleanup
direct process exit would require a proven import/raw syscall and exact teardown contract UNPROVEN
exit status current waiter discards it UNPROVEN delivery
output current payloadout is inside the child mapping and never read by the controlled caller UNPROVEN

The important closure result is negative: removing the CRT also removes the only reviewed syscall, kernel, rtld, import, time, and libc initialization machinery. The loader supplies a dynamic-symbol function pointer and kernel transport fields, but using them would reintroduce dynamic resolution or kernel-access dependencies that this phase excludes. No useful observation primitive is proven available to a zero-import freestanding entry.

Return, exit, and cleanup contract

Resource/state Normal ret process exit error/crash timeout
saved stack continuation resumes the observed RIP; meaning unproven not used may be bypassed bypassed
ELF and argument mappings remain in child after detach OS reclamation expected but not source-proven for this exact contract unproven child is killed/reaped, which is not safe exit
loader-created pipe/sockets remain in child after detach same unproven teardown dependency unproven same inadmissible kill path
observer local buffers stack lifetime follows unproven continuation/process semantics teardown semantics unproven unproven forcibly discarded
file descriptors opened by a future observer no implementation or cleanup contract no implementation or exact teardown proof unproven forcibly discarded
threads a future observer forbids them; existing child/runtime state remains no target observer exists unproven signals affect the whole child
credentials loader restores five fields before detach source-proven attempted and checked restore pre-detach cleanup is tracked; post-detach crash remains dependent on process teardown watchdog does not prove observer cleanup
breakpoint/page restored before payload entry already restored preparation failures use cleanup already restored
loader bookkeeping returns from watchdog on reap waitpid status is discarded status is ambiguous returns timeout/failure
manager bookkeeping send-only function closes its socket before a result no result is received indistinguishable no result is received
exit status no defined status locally available to waitpid but discarded discarded timeout result is loader-local
output availability none child mapping gone; no copy-out none none

The current normal return path is especially unsuitable: ret resumes the SceSpZeroConf continuation rather than proving process termination. The controlled watchdog waits for process exit; if that continuation remains alive, the only bounded endpoint is signal termination. The user explicitly forbids treating kill, crash, timeout, or disconnect as a safe exit.

Decision

No reviewed path proves all of:

  1. kernelwrite-free entry with usable observation dependencies;
  2. correct stack and register ABI;
  3. deterministic BSS/relocation/TLS closure;
  4. normal return or process exit with exact status semantics;
  5. cleanup of mappings, descriptors, stack, loader and manager state;
  6. a safe error path;
  7. a safe deadline path that does not rely on kill; and
  8. result availability after cleanup.

Startup is therefore BLOCKED_STARTUP_ABI_UNPROVEN, exit and cleanup are BLOCKED_EXIT_CLEANUP_UNPROVEN, and the combined Phase-0.9C decision cannot be positive.