feat(kernel): KRNBUG-XEX-001 — real XexCheckExecutablePrivilege from XEX header bitmap
Replace stub_return_zero with a canary-faithful implementation that returns bit `priv` of the loaded XEX's XEX_HEADER_SYSTEM_FLAGS (key 0x00030000) bitmap. Mirrors xenia-canary xboxkrnl_modules.cc:22-39: `(flags >> priv) & 1` for priv < 32, else 0. Plumbing: - xenia-xex: header_keys::SYSTEM_FLAGS const + get_system_flags() accessor. - xenia-kernel/state.rs: pub xex_system_flags: u32 + xex_priv_logged HashSet for one-shot per-priv tracing. - xenia-app: kernel.xex_system_flags wired in cmd_exec_inner. - xenia-kernel/exports.rs: real export body + unit test covering bits 10/11/0/64 + zero-flags case. Sylpheed's bitmap is 0x00000400 (only XEX_SYSTEM_PAL50_INCOMPATIBLE, bit 10). At -n 500M with the fix: - XGetAVPack: 0 -> 1 (priv-10 gate at lr=0x824ab598 flipped). - 10 other canary-only exports + 9 producer PCs + 3 parked handles unchanged. Priv-11 site at sub_824A9710 is downstream and still not reached — AV/crypto block aborts after XGetAVPack returns our placeholder 0x16 (canary returns 8/HDMI; Sylpheed accepts only 3/4/6/8 per xenia-canary xam_info.cc:250-251). Tests 588 -> 589. Lockstep deterministic (3 reruns identical): n50m goes 50000008 -> 50000005 instr / 407415 -> 407417 imp / swaps=2 / draws=0. Goldens re-baselined (sylpheed_n50m, sylpheed_n2m); oracle test green. Full chain-of-effects + next-frontier hand-off in audit-findings.md under KRNBUG-XEX-001. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4813,3 +4813,81 @@ If after the fix the producer is reached and dispatcher fields
|
||||
populate, the parked-waiter deadlock should resolve — or surface
|
||||
the next layer of bugs (e.g. signaling code reads non-zero handle
|
||||
but `wake_eligible_waiters` fails).
|
||||
|
||||
### KRNBUG-XEX-001 — `XexCheckExecutablePrivilege` real impl (P0 fix landed)
|
||||
|
||||
**Branch:** `xex-check-privilege/p0-real-impl` (no-ff merged to master).
|
||||
**Status:** LANDED 2026-05-04. Closes the priv-stub side of KRNBUG-AUDIT-005.
|
||||
|
||||
**Implementation.** Replaced `stub_return_zero` at
|
||||
`crates/xenia-kernel/src/exports.rs:193` with a real implementation
|
||||
that reads the XEX `XEX_HEADER_SYSTEM_FLAGS` (key `0x00030000`)
|
||||
bitmap. Mirrors canary's `XexCheckExecutablePrivilege_entry`
|
||||
[xboxkrnl_modules.cc:22-39](../xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc#L22-L39):
|
||||
`(flags >> priv) & 1` for `priv < 32`, else 0.
|
||||
|
||||
Plumbing:
|
||||
- `xenia-xex/src/header.rs`: added `header_keys::SYSTEM_FLAGS = 0x00030000`.
|
||||
- `xenia-xex/src/loader.rs`: added `get_system_flags(&Xex2Header) -> u32`.
|
||||
- `xenia-kernel/src/state.rs`: added `pub xex_system_flags: u32` (init 0)
|
||||
+ `xex_priv_logged: HashSet<u32>` (one-shot log gate per priv).
|
||||
- `xenia-app/src/main.rs`: wired
|
||||
`kernel.xex_system_flags = xenia_xex::loader::get_system_flags(&header)`
|
||||
alongside the existing `kernel.image_base = base` line in `cmd_exec_inner`.
|
||||
|
||||
Sylpheed's bitmap is `0x00000400` (only `XEX_SYSTEM_PAL50_INCOMPATIBLE`
|
||||
set, bit 10). So priv 10 → 1, priv 11 → 0. Both call sites identified
|
||||
in AUDIT-005 now route through the canary-correct branches.
|
||||
|
||||
**Validation chain (Step 3 of the hand-off):**
|
||||
|
||||
| step | outcome |
|
||||
|---|---|
|
||||
| (a) `cargo test --workspace --release` | 588 → 589 (new test `xex_check_executable_privilege_reads_system_flags_bitmap`); all prior green |
|
||||
| (b) `--stable-digest -n 100M` lockstep | `instructions=100000013` (was `100000002`). 11-instruction shift is the deterministic guest divergence into the canary-correct branch — verified with 2 identical re-runs. NOT nondeterminism. |
|
||||
| (c) AUDIT-005 9-PC probe at -n 500M | All 9 producer probe sites still 0×. **BUT** `kernel.calls{XGetAVPack}` went from `0` → `1` (priv-10 gate flipped — XexCheckExecutablePrivilege itself only fires once for priv 10 because priv-11 site at `sub_824A9710` is downstream and not yet reached). |
|
||||
| (d) `--trace-handles-focus=0x1004,0x100c,0x15e0` | All 3 handles still `signal_attempts=0`. The 9 probed PCs are members of two indirection-chain singletons (`sub_821800D8` for 0x100c, `sub_8216F618` for 0x15e0); both are downstream of the priv-11 site too. |
|
||||
| (e) Canary kernel-call diff | 10 of the 11 missing exports remain absent. Only `XGetAVPack` was unlocked. The new first-divergence is inside the AV/crypto block — between `XGetAVPack` returning and `XeCryptSha` (still stub_success), Sylpheed's init aborts the block early. |
|
||||
| (f) `sylpheed_oracles` (n50m / n2m) | Re-baselined and re-verified across 3 deterministic runs. New `n50m`: `instructions=50000005, imports=407417, swaps=2, draws=0` (was `50000008, 407415, 2, 0`). |
|
||||
|
||||
**Decisive interpretation.** The fix is **correct but partial**. The
|
||||
priv-10 gate at `lr=0x824ab598` flips polarity (was: skip block / now:
|
||||
execute block); `XGetAVPack` is now reached as predicted. The priv-11
|
||||
gate at `lr=0x824a99a4` lives inside `sub_824A9710`, which the boot
|
||||
flow does NOT reach because something in the AV/crypto block (which
|
||||
the priv-10 fix unlocked) aborts before completing. So:
|
||||
|
||||
- `XGetAVPack`: ✅ reached (was missing, now fires once)
|
||||
- `XeCryptSha` / `XeKeysConsolePrivateKeySign` / `ObCreateSymbolicLink`
|
||||
/ `XamUserReadProfileSettings`: ❌ still missing → AV/crypto block
|
||||
aborts early
|
||||
- `sub_824A9710` (priv-11 caller) and downstream `XamTaskSchedule` /
|
||||
`XamTaskCloseHandle` / `ExTerminateThread` / etc.: ❌ still unreached
|
||||
- Parked-handle producers (the 9 PCs): ❌ still 0× (they live in the
|
||||
init flow gated on priv-11 or post-priv-11 — same blast radius)
|
||||
|
||||
**Next-frontier bug (the new gate identified by this fix).** Inside
|
||||
sub_824AB578 between `XGetAVPack` (`lr=0x824ab5a4`) and the next
|
||||
canary-only call (likely `XeKeysConsolePrivateKeySign`). The
|
||||
candidates are:
|
||||
|
||||
1. **`XGetAVPack` returns wrong value.** Our impl returns `0x16`
|
||||
(`crates/xenia-kernel/src/xam.rs:382-384`). Canary returns
|
||||
`cvars::avpack` (default 8 = HDMI). Sylpheed comment in canary
|
||||
`xam_info.cc:250-251`: "if the result is not 3/4/6/8 they
|
||||
explode with errors". `0x16` is not in the accepted set →
|
||||
strongly suspect this is the next blocker.
|
||||
2. **`XeCryptSha` / `XeKeysConsolePrivateKeySign` are `stub_success`**
|
||||
(`exports.rs:188-189`). Returning `STATUS_SUCCESS` without
|
||||
side effects on a hashing operation may itself confuse the caller
|
||||
if it then reads a hash buffer expecting non-zero bytes.
|
||||
|
||||
Recommended next session: probe `XGetAVPack` return value (try `0x8`
|
||||
to match canary default) — that's a one-line change in `xam.rs:383`.
|
||||
If the run advances past, re-diff against canary at the new
|
||||
divergence; otherwise the next gate is in `XeCryptSha` /
|
||||
`XeKeysConsolePrivateKeySign`.
|
||||
|
||||
**Trace artifacts:** `audit-runs/post-priv-fix/ours.log` (5.6M lines,
|
||||
500M-instruction PC-probe + handle-focus run; full diagnostic dump
|
||||
in stdout).
|
||||
|
||||
Reference in New Issue
Block a user