199 lines
7.8 KiB
Markdown
199 lines
7.8 KiB
Markdown
# SDK v0.41 startup call graph
|
|
|
|
This is an offline source, relocation, and disassembly audit of the installed
|
|
SDK v0.41 `target/lib/crt1.o`. It describes the unsafe stock startup, not a new
|
|
Chimera GFX artifact. The complete machine-readable reachable graph contains
|
|
31 functions and 182 call or tail-call edges in
|
|
`manifests/runtime/phase-0.5-startup-audit.json`.
|
|
|
|
## Transitive startup objects
|
|
|
|
`crt/Makefile` compiles and partially links exactly these objects into one
|
|
relocatable `crt1.o` with `prospero-lld -r`:
|
|
|
|
| Object | Public source | Role |
|
|
|---|---|---|
|
|
| `crt.o` | `crt/crt.c` | entry, BSS, init/run/terminate |
|
|
| `syscall.o` | `crt/syscall.c` | syscall bootstrap |
|
|
| `klog.o` | `crt/klog.c` | kernel log helpers |
|
|
| `nid.o` | `crt/nid.c` | symbol-name encoding |
|
|
| `kernel.o` | `crt/kernel.c` | kernel transport and process helpers |
|
|
| `rtld.o` | `crt/rtld.c` | runtime-loader core |
|
|
| `rtld_so.o` | `crt/rtld_so.c` | shared-object mapping and relocation |
|
|
| `rtld_sprx.o` | `crt/rtld_sprx.c` | Sce module load/start/stop/unload |
|
|
| `rtld_payload.o` | `crt/rtld_payload.c` | payload relocation and arrays |
|
|
| `rtld_dlfcn.o` | `crt/rtld_dlfcn.c` | `dlopen`/`dlsym` facade |
|
|
| `mdbg.o` | `crt/mdbg.c` | memory-debug transport helpers |
|
|
| `patch.o` | `crt/patch.c` | credentials and syscall-bound patches |
|
|
|
|
The files named `crti.o`, `crtn.o`, `crtbegin.o`, `crtend.o`, `crtbeginS.o`,
|
|
and `crtendS.o` are empty `ar` archives at the installed release. The audit
|
|
enumerates them rather than assuming their filename implies contents.
|
|
|
|
## Reachable startup paths
|
|
|
|
The important conservative paths from source, relocations, and disassembly are:
|
|
|
|
```text
|
|
_start
|
|
|- zero [__bss_start, __bss_end)
|
|
|- __crt_syscall_init
|
|
|- __kernel_init
|
|
| `- kernel_copyout (reachable in compiled object)
|
|
|- __klog_init
|
|
|- kernel_dynlib_dlsym -> set __isthreaded = 1
|
|
|- __patch_init UNSAFE
|
|
| |- kernel_get_ucred_caps -> kernel_copyout
|
|
| |- kernel_get_ucred_attrs -> kernel_copyout
|
|
| |- kernel_set_ucred_caps -> kernel_copyin KERNEL WRITE
|
|
| |- kernel_set_ucred_attrs -> kernel_copyin KERNEL WRITE
|
|
| `- kernel_copyin at process offsets 0xf0/0xf8 KERNEL WRITE
|
|
|- __rtld_init UNSAFE
|
|
| |- __rtld_sprx_init -> sceKernelLoadStartModule
|
|
| |- __rtld_so_init
|
|
| |- __rtld_payload_init
|
|
| `- __rtld_dlfcn_init
|
|
|- __rtld_payload_new/open/init
|
|
| `- constructors
|
|
|- main
|
|
|- __rtld_lib_fini/close/destroy
|
|
| `- destructors
|
|
`- payload_terminate
|
|
|- ret for the CRT's detected hijacked-process case
|
|
|- resolved exit for another case
|
|
`- trap when exit cannot be resolved
|
|
```
|
|
|
|
Indirect calls are retained as `INDIRECT:<operand>` in the JSON graph rather
|
|
than guessed. A relocation to the `sceKernelLoadStartModule` function-pointer
|
|
slot is retained explicitly. This makes the graph conservative without
|
|
inventing a firmware ABI.
|
|
|
|
## Linked but not startup-reachable
|
|
|
|
The monolithic `crt1.o` also contains `__dlopen`, `__dlsym`,
|
|
`kernel_mprotect`, `kernel_overlap_sockets`, and
|
|
`kernel_set_vmem_protection`, although the disassembly graph did not find them
|
|
reachable from the stock `_start`. Their presence demonstrates why an import
|
|
inventory alone would be insufficient: prohibited-capability code can be
|
|
statically linked without appearing as an undefined symbol.
|
|
|
|
## Driver and linker behavior
|
|
|
|
The `prospero-clang` wrapper normally adds `crt1.o`, `libc`, `libkernel_web`,
|
|
`libSceLibcInternal`, and `libSceNet`. A no-output `-###` trace with both
|
|
`-nostartfiles` and `-nodefaultlibs` adds none of them. The linker wrapper still
|
|
selects the public `elf_x86_64.x` script, PIE mode, an ELF x86-64 emulation,
|
|
0x4000 maximum page size, emulated TLS support, and GNU hashing unless the
|
|
caller overrides applicable options.
|
|
|
|
The linker script retains preinit/init/fini arrays and a dynamic segment. It
|
|
also declares the text load segment with flags `0x7`; that is a source fact,
|
|
not a claim about final loader-enforced permissions.
|
|
|
|
## Why there is no custom linker map
|
|
|
|
The loader return contract failed before the build gate. In accordance with
|
|
the task rule, no custom `_start` source or PS5 ELF was created. Therefore a
|
|
custom linker map, imports, `DT_NEEDED`, relocations, arrays, TLS inventory,
|
|
double-build hash, and artifact disassembly are all explicitly recorded as
|
|
`NOT_PERFORMED_BLOCKED_BEFORE_BUILD`, not silently treated as passing.
|
|
|
|
## Phase 0.6 exact runtime chain
|
|
|
|
This addendum is the reviewed source call graph for the installed chain. No new
|
|
probe artifact exists, so there is no probe disassembly call graph to report.
|
|
|
|
```text
|
|
Payload Manager /loadpayload:<path>
|
|
`- ps5_launch_elf(path)
|
|
|- open(path, O_RDONLY)
|
|
|- connect(127.0.0.1:9021)
|
|
`- send(ELF bytes)
|
|
|
|
elfldr serve_elfldr
|
|
`- elfldr_spawn
|
|
|- rfork_thread
|
|
| `- child: elfldr_rfork_entry
|
|
| |- sys_budget_set(0)
|
|
| |- open(/dev/deci_{stdin,stdout,stderr})
|
|
| |- ptrace(PT_TRACE_ME)
|
|
| `- execve(SceSpZeroConf)
|
|
|- parent: pt_syscall(599)
|
|
| `- pt_syscall -> unbounded pt_step loop
|
|
|- elfldr_set_heap_size(-1)
|
|
|- kernel_mprotect(eboot entry page, RWX)
|
|
|- install INT3 -> continue -> wait -> restore byte
|
|
`- elfldr_exec
|
|
|- backup jaildir/rootdir/caps/authid
|
|
|- elfldr_raise_privileges
|
|
| `- set rootdir/jaildir/UID/caps
|
|
|- elfldr_prepare_exec
|
|
| |- elfldr_load
|
|
| | |- mmap/copy/RELATIVE relocations
|
|
| | `- per-segment mprotect + msync
|
|
| |- elfldr_payload_args
|
|
| | |- mmap page
|
|
| | |- two IPv6 sockets + overlap
|
|
| | `- pipe + six payload_args_t fields
|
|
| `- [RSP-8]=old RIP; RIP=entry; RDI=args
|
|
|- restore jaildir/rootdir/caps/authid (not UID)
|
|
`- ptrace(PT_DETACH)
|
|
|
|
SDK v0.41 payload _start
|
|
|- clear BSS
|
|
|- initialize syscall/kernel/klog
|
|
|- __patch_init
|
|
|- initialize rtld and constructors
|
|
|- main
|
|
|- destructors and rtld cleanup
|
|
`- payload_terminate
|
|
`- return OR exit OR trap (exact child branch unproven)
|
|
```
|
|
|
|
The exact elfldr release binary is stripped, so the source graph is bound to
|
|
the release by source commit and release-asset SHA-256. Static binary evidence
|
|
records entry `0x4700`, 164 relocations, 24 undefined dynamic symbols, three
|
|
`DT_NEEDED` modules, zero-byte init/fini arrays, no TLS, and hashes of the
|
|
complete readelf report and disassembly in
|
|
`manifests/runtime/phase-0.6-loader-runtime-audit.json`.
|
|
|
|
## Phase 0.7 hardened callgraph addendum
|
|
|
|
Phase 0.7 uses new hardened elfldr and controlled Payload Manager binaries;
|
|
the graph above remains the historical stock Phase-0.6 chain.
|
|
|
|
The lifecycle source-level action is deliberately narrow:
|
|
|
|
```text
|
|
SDK _start
|
|
|- BSS and stock SDK v0.41 runtime initialization
|
|
|- __patch_init
|
|
|- main
|
|
| |- sceKernelSendNotificationRequest
|
|
| `- _exit
|
|
`- payload_terminate [not reached from main]
|
|
```
|
|
|
|
The hardened loader retains its required first-stage and ptrace operations,
|
|
but each single-step operation now has both a one-second monotonic deadline
|
|
and a 65,536-step ceiling. Cleanup tracks the child, breakpoint, mappings, and
|
|
descriptors in one state. The success and failure paths restore all five
|
|
credential fields and verify every restoration. The runtime supervisor waits
|
|
at most 2000 ms, then uses a bounded SIGTERM/SIGKILL/reap sequence.
|
|
|
|
The controlled manager opens, hashes, rewinds, and streams one no-follow file
|
|
descriptor. The hardened receiver independently rehashes the received bytes
|
|
and checks the exact versioned header and permanent denylist.
|
|
|
|
The committed machine audit contains every extracted call edge, not a sample:
|
|
|
|
- lifecycle: 499 edges;
|
|
- hardened elfldr: 1032 edges;
|
|
- controlled manager: 478 edges.
|
|
|
|
Full disassembly, normalized linker maps, symbol/relocation/section reports,
|
|
and text callgraphs are in the ignored `outputs/phase07/audit/` package. Their
|
|
hashes and the complete edge arrays are committed in
|
|
`manifests/runtime/phase-0.7-offline-audit.json`.
|