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:
MechaCat02
2026-05-04 18:32:51 +02:00
parent 451b3b28fe
commit 1a892d4641
8 changed files with 163 additions and 11 deletions

View File

@@ -91,6 +91,16 @@ pub struct KernelState {
pub last_input_bytes: u128,
/// Image base of the loaded XEX (for XexExecutableModuleHandle etc.)
pub image_base: u32,
/// `XEX_HEADER_SYSTEM_FLAGS` (key `0x00030000`) parsed from the loaded
/// XEX header. Queried by `XexCheckExecutablePrivilege`: privilege bit
/// `n` is set iff `(xex_system_flags & (1 << n)) != 0`. Zero before the
/// app installs the loaded image — that matches canary's behavior when
/// no executable module is registered (returns 0).
pub xex_system_flags: u32,
/// One-shot log gate for `XexCheckExecutablePrivilege`: tracks which
/// privilege numbers have already produced a `tracing::info!` line so
/// the import-hot path doesn't spam at -n 500M.
pub xex_priv_logged: std::collections::HashSet<u32>,
/// Next thread ID. M2.4: atomic.
pub next_thread_id: std::sync::atomic::AtomicU32,
/// Virtual file system for NtCreateFile/NtReadFile/etc. The app mounts
@@ -248,6 +258,8 @@ impl KernelState {
input_packet_number: 0,
last_input_bytes: 0,
image_base: 0,
xex_system_flags: 0,
xex_priv_logged: std::collections::HashSet::new(),
next_thread_id: AtomicU32::new(1),
vfs: None,
ui: None,