From b9ac2a98ee2529c14b7292ce65a0aa38b8a2497e Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Fri, 20 Feb 2026 04:38:51 +0000 Subject: [PATCH] pr5.3.2 --- crates/console/prometeu-hal/src/syscalls.rs | 122 ++++++++++++++++++++ files/TODOs.md | 50 -------- 2 files changed, 122 insertions(+), 50 deletions(-) diff --git a/crates/console/prometeu-hal/src/syscalls.rs b/crates/console/prometeu-hal/src/syscalls.rs index b864d903..afa518cc 100644 --- a/crates/console/prometeu-hal/src/syscalls.rs +++ b/crates/console/prometeu-hal/src/syscalls.rs @@ -212,6 +212,77 @@ impl SyscallIdentity { } } +/// Resolved syscall information provided to the loader/VM. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct SyscallResolved { + /// Numeric syscall id used at runtime (VM executes `SYSCALL ` only). + pub id: u32, + /// Associated metadata for verification/runtime checks. + pub meta: SyscallMeta, +} + +/// Load-time error for syscall resolution. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum LoadError { + /// The (module, name, version) triple is not known by the host. + UnknownSyscall { + module: &'static str, + name: &'static str, + version: u16, + }, + /// The cartridge lacks required capabilities for the syscall. + MissingCapability { + required: CapFlags, + provided: CapFlags, + module: &'static str, + name: &'static str, + version: u16, + }, +} + +/// Resolve a canonical syscall identity to its numeric id and metadata. +/// +/// Returns `None` if the identity is unknown. +pub fn resolve_syscall(module: &'static str, name: &'static str, version: u16) -> Option { + for entry in SYSCALL_TABLE { + if entry.meta.module == module && entry.meta.name == name && entry.meta.version == version { + return Some(SyscallResolved { id: entry.meta.id, meta: entry.meta }); + } + } + None +} + +/// Resolve all declared program syscalls and enforce capability gating. +/// +/// - `declared`: list of canonical identities required by the program. +/// - `caps`: capabilities granted to the cartridge/program. +/// +/// Fails deterministically if any syscall is unknown or requires missing caps. +pub fn resolve_program_syscalls( + declared: &[SyscallIdentity], + caps: CapFlags, +) -> Result, LoadError> { + let mut out = Vec::with_capacity(declared.len()); + for ident in declared { + let Some(res) = resolve_syscall(ident.module, ident.name, ident.version) else { + return Err(LoadError::UnknownSyscall { module: ident.module, name: ident.name, version: ident.version }); + }; + // Capability gating: required must be subset of provided + let missing = res.meta.caps & !caps; + if missing != 0 { + return Err(LoadError::MissingCapability { + required: res.meta.caps, + provided: caps, + module: ident.module, + name: ident.name, + version: ident.version, + }); + } + out.push(res); + } + Ok(out) +} + /// Canonical registry of all syscalls and their metadata. /// /// IMPORTANT: This table is the single authoritative source for the slot-based @@ -528,4 +599,55 @@ mod tests { // 3) Table and explicit list sizes must match (guard against omissions). assert_eq!(SYSCALL_TABLE.len(), all_syscalls().len()); } + + #[test] + fn resolver_returns_expected_id_for_known_identity() { + // Pick a stable entry from the table + let id = resolve_syscall("gfx", "clear", 1).expect("known identity must resolve"); + assert_eq!(id.id, 0x1001); + assert_eq!(id.meta.module, "gfx"); + assert_eq!(id.meta.name, "clear"); + assert_eq!(id.meta.version, 1); + } + + #[test] + fn resolver_rejects_unknown_identity() { + let res = resolve_syscall("gfx", "nonexistent", 1); + assert!(res.is_none()); + + // And via the program-level resolver + let requested = [SyscallIdentity { module: "gfx", name: "nonexistent", version: 1 }]; + let err = resolve_program_syscalls(&requested, 0).unwrap_err(); + match err { + LoadError::UnknownSyscall { module, name, version } => { + assert_eq!(module, "gfx"); + assert_eq!(name, "nonexistent"); + assert_eq!(version, 1); + } + _ => panic!("expected UnknownSyscall error"), + } + } + + #[test] + fn resolver_enforces_capabilities() { + // Choose a syscall that requires GFX caps. + let requested = [SyscallIdentity { module: "gfx", name: "clear", version: 1 }]; + // Provide no caps → should fail. + let err = resolve_program_syscalls(&requested, 0).unwrap_err(); + match err { + LoadError::MissingCapability { required, provided, module, name, version } => { + assert_eq!(module, "gfx"); + assert_eq!(name, "clear"); + assert_eq!(version, 1); + assert_ne!(required, 0); + assert_eq!(provided, 0); + } + _ => panic!("expected MissingCapability error"), + } + + // Provide correct caps → should pass. + let ok = resolve_program_syscalls(&requested, caps::GFX).expect("must resolve with caps"); + assert_eq!(ok.len(), 1); + assert_eq!(ok[0].id, 0x1001); + } } diff --git a/files/TODOs.md b/files/TODOs.md index f4a3d28a..66c3bdc4 100644 --- a/files/TODOs.md +++ b/files/TODOs.md @@ -1,53 +1,3 @@ -# PR-5.4 — Verifier Integration for Syscall Slot Rules - -### Briefing - -The verifier must ensure that syscall calls respect argument and return slot counts before runtime. - -### Target - -* Extend verifier to validate syscall usage. - -### Work items - -* At syscall call sites: - - * Look up `SyscallMeta`. - * Ensure enough argument slots are available. - * Ensure stack shape after call matches `ret_slots`. -* Emit verifier errors for mismatches. - -### Acceptance checklist - -* [ ] Verifier rejects incorrect syscall slot usage. -* [ ] Correct programs pass. -* [ ] Runtime traps are not required for verifier-detectable cases. -* [ ] `cargo test` passes. - -### Tests - -* Add tests: - - * Too few args for syscall → verifier error. - * Correct args/returns → passes. - -### Junie instructions - -**You MAY:** - -* Extend verifier with syscall checks. - -**You MUST NOT:** - -* Change runtime trap logic. -* Add new trap categories. - -**If unclear:** - -* Ask before enforcing slot rules. - ---- - # PR-5.5 — Remove Legacy Syscall Entry Paths ### Briefing