Panic-Surface Inventory
Scope: panic!, assert!, debug_assert!, .unwrap(), .expect(),
todo!, and unreachable! surfaces relevant to boot manifest loading, ELF
loading, SQE handling, params/result buffers, IPC, and future spawn inputs.
Classification terms:
trusted-internal: depends on kernel/shared-code invariants, static ABI layout, or host build/test code; not directly controlled by a service.boot-fatal: reached during boot/package setup before mutually untrusted services run. Bad platform/package state can halt the system.untrusted-input reachable: reachable from userspace-controlled SQEs, Cap’n Proto params/result buffers, IPC state, manifest/package data, or future spawn-controlled service/binary data.
Summary
No current panic!/assert!/unwrap()/expect() site found in the
kernel ring dispatch path directly consumes raw SQE fields or user
params/result-buffer pointers. Those paths mostly return CQE errors through
kernel/src/cap/ring.rs.
The remaining relevant surfaces are boot-fatal setup assumptions, scheduler internal invariants that would become more exposed once untrusted spawn/lifecycle inputs can create or destroy processes dynamically, and IPC rollback queue capacity assumptions.
Locations use path::function anchors rather than line numbers; line numbers
drift on every refactor. Grep the path plus the quoted surface text to
re-locate a site.
Manifest And Future Spawn Inputs
| Location | Surface | Reachability | Classification | Notes |
|---|---|---|---|---|
kernel/src/main.rs run_init | MODULES.response().expect("no modules from bootloader") | Boot package/module table | boot-fatal | Missing Limine modules abort before manifest validation. |
kernel/src/main.rs run_init | elf_cache.get(service.binary.as_str()).ok_or_else(...) | Manifest service binary reference | untrusted-input reachable, controlled error | Not a panic surface. Included because it is the future spawn shape to preserve: unknown or unparsed binaries return an error. |
kernel/src/spawn.rs spawn_service | Process::new(...).map_err(...) | Manifest-spawned process creation | untrusted-input reachable, controlled error | Current boot path converts allocation/mapping failures into boot errors. Future ProcessSpawner should keep this shape instead of adding unwraps. |
ELF Inputs
| Location | Surface | Reachability | Classification | Notes |
|---|---|---|---|---|
kernel/src/spawn.rs load_elf | debug_assert!(stack_top % 16 == 0, ...) | ELF load path | trusted-internal | Constant stack layout invariant, not ELF-controlled. |
kernel/src/spawn.rs align_up | debug_assert!(align.is_power_of_two()) | TLS mapping from parsed ELF | trusted-internal | elf::parse rejects non-power-of-two TLS alignment; load_tls also caps the size before calling align_up. |
capos-lib/src/elf.rs parser | no runtime panic surfaces outside tests/Kani | Boot manifest ELF bytes; future spawn ELF bytes | untrusted-input reachable, controlled error | Parser uses checked offsets/ranges and returns Err(&'static str). Test-only assertions/unwraps are excluded from runtime classification. |
kernel/src/spawn.rs load_elf | slice init_data[src_offset..] | Parsed ELF PT_LOAD file range | untrusted-input reachable, guarded | Not matched by the panic-token grep, but it is an index panic candidate if parser invariants are bypassed. elf::parse checks segment file ranges before load_elf. |
kernel/src/spawn.rs load_tls | slice &init_data[init_start..init_end] | Parsed ELF TLS file range | untrusted-input reachable, guarded | Not matched by the panic-token grep, but it is an index panic candidate if parser invariants are bypassed. elf::parse checks TLS file bounds before load_tls. |
SQE And Params/Result Buffers
| Location | Surface | Reachability | Classification | Notes |
|---|---|---|---|---|
kernel/src/cap/ring.rs process_ring / dispatch_call / dispatch_recv / dispatch_return | no matched panic-like surfaces | Userspace SQEs, params, result buffers | untrusted-input reachable, controlled error | SQ corruption, unsupported fields/opcodes, oversized buffers, invalid user buffers, and CQ pressure return transport errors or defer consumption. |
capos-config/src/ring.rs const _: () = assert!(...) ABI size checks | const assert! layout checks | Shared ring ABI | trusted-internal | Compile-time ABI guard; not runtime input reachable. |
capos-config/src/capset.rs const _: () = assert!(...) ABI size checks | const assert! layout checks | Shared CapSet ABI | trusted-internal | Compile-time ABI/page-fit guard; not runtime input reachable. |
capos-lib/src/frame_bitmap.rs (alloc_frame and alloc_contiguous) | .try_into().unwrap() on 8-byte bitmap windows | Frame allocation, including work triggered by manifest/process creation and capability methods | trusted-internal | Guarded by frame + 64 <= total or i + 64 <= to, assuming the caller-provided bitmap covers total_frames. Kernel constructs that bitmap at boot. |
IPC
| Location | Surface | Reachability | Classification | Notes |
|---|---|---|---|---|
kernel/src/cap/endpoint.rs Endpoint::endpoint_call | pending receive pop on CALL delivery | Cross-process CALL delivered to pending RECV | untrusted-input reachable, controlled error | The former guarded pending_recvs.pop_front().unwrap() now returns a failed capnp error if the queue is inconsistent. Endpoint pending-RECV exhaustion has QEMU coverage in endpoint-roundtrip. |
kernel/src/cap/endpoint.rs endpoint_restore_recv_front | rollback push_front growth | IPC rollback path | untrusted-input reachable, controlled error | CALL delivery reserves the popped pending-RECV slot until rollback restores the RECV or receiver completion releases the reservation, so concurrent receives cannot consume rollback capacity. Recovery helpers resolve the original endpoint object through revoked cap epochs and wrapper recovery methods bypass liveness checks, without reopening ordinary CALL/RECV/RETURN authority. If restore still fails after reaching the endpoint, the ring path posts or defers an explicit receiver cancellation instead of silently dropping the popped RECV. endpoint-roundtrip includes QEMU coverage for same-process CQ-pressure rollback with both available and saturated pending-RECV capacity, then consuming the restored undersized RECV through the controlled receiver-error path; capos-lib host coverage checks revoked-cap recovery lookup. |
Scheduler And Process Lifecycle
| Location | Surface | Reachability | Classification | Notes |
|---|---|---|---|---|
kernel/src/sched.rs register_idle_process_locked | Process::new_idle().expect("failed to create idle process") | Boot scheduler init (sched_init, slot 0) and lazy per-CPU registration (current_cpu_idle_thread_locked) | boot-fatal at slot 0; per-CPU-fatal on first AP idle | Synthetic idle Process creation OOM panics. There is no fallback idle path after the user-mode idle process removal, so this panic is the deliberate unrecoverable-OOM behavior. |
kernel/src/sched.rs sched_init | CPL0 idle kernel stack .expect, idle-context registry try_reserve_exact().expect, per-CPU CpuContext Box::try_new panic! | Boot scheduler init | boot-fatal | CPL0 idle-context infrastructure OOM panics before services run. Same rationale as the synthetic idle records: no fallback idle path exists, so the failure is deliberately unrecoverable. |
kernel/src/sched.rs block_current_on_cap_enter | current.expect, idle assert!, process-table expect | cap_enter(min_complete > 0) path | untrusted-input reachable, internal invariant | Userspace can request blocking, but these unwraps assert scheduler state, not user values. Future process lifecycle/spawn changes increase this exposure. |
kernel/src/sched.rs capos_block_current_syscall | current.expect, idle assert!, table expect, panic! if not blocked | Blocking syscall continuation | untrusted-input reachable, internal invariant | Triggered after cap_enter chooses to block. User controls the request, but panic requires kernel state inconsistency. |
kernel/src/sched.rs run_queue references missing process expect (context-switch + start paths) | run-queue/process-table consistency | Scheduling after queue selection | trusted-internal now; future spawn/lifecycle sensitive | A stale run-queue PID panics. Dynamic spawn/exit must preserve run-queue/process-table invariants. |
kernel/src/sched.rs exit_current | current.expect, idle assert!, processes.remove(...).unwrap(), next-process unwrap() | Ambient exit syscall and future process exit | untrusted-input reachable, internal invariant | Any service can exit itself. Panic requires scheduler corruption or idle misuse, but future spawn/process APIs should harden this boundary. |
kernel/src/sched.rs current_ring_and_caps | current.expect, process-table expect | cap_enter flush path | untrusted-input reachable, internal invariant | User can call cap_enter; panic requires no current process or missing table entry. |
kernel/src/sched.rs start | initial run-queue expect, process-table unwrap, CR3 expect | Boot service start | boot-fatal | Manifest with zero services is rejected earlier, and process creation errors out; panics indicate scheduler/CR3 invariant breakage. |
kernel/src/arch/x86_64/context.rs timer context restore | CR3 expect("invalid CR3 from scheduler") | Timer interrupt scheduling | trusted-internal; future lifecycle sensitive | Scheduler should only return page-aligned CR3s from AddressSpace. |
Boot Platform And Memory Setup
| Location | Surface | Reachability | Classification | Notes |
|---|---|---|---|---|
kernel/src/main.rs kmain | assert!(BASE_REVISION.is_supported()) | Limine boot protocol | boot-fatal | Platform/bootloader contract check. |
kernel/src/main.rs kmain | memory-map and HHDM expect | Limine boot protocol | boot-fatal | Missing bootloader responses halt before untrusted services. |
kernel/src/main.rs kmain | cap::init().expect("failed to initialize kernel capabilities") | Kernel cap table bootstrap | boot-fatal | Fails on kernel-internal cap-table exhaustion. |
kernel/src/mem/frame.rs init | frame-bitmap region expect("no region large enough for frame bitmap") | Boot memory map | boot-fatal | Bad or too-small memory map halts. |
kernel/src/mem/frame.rs free_frame | try_free_frame(...).expect("free_frame failed") | Kernel-owned frame teardown | trusted-internal | Capability handlers use try_free_frame; this panic surface is for kernel-owned frames and rollback/Drop paths. |
kernel/src/mem/frame.rs HHDM cache helper | assert!(offset != 0, "frame allocator not initialized") | HHDM cache use before frame init | trusted-internal | Initialization-order invariant. |
kernel/src/mem/heap.rs init | alloc_contiguous(HEAP_FRAMES).expect("out of memory for heap") | Boot heap init | boot-fatal | Fails if the frame allocator cannot provide the fixed kernel heap. |
kernel/src/mem/paging.rs alloc_page_table_frame / kernel_pml4_frame / assert!(addr != 0, "paging not initialized") | page-alignment .unwrap() / paging initialized assert! | Kernel frame/page-table internals | trusted-internal | frame::alloc_frame returns page-aligned addresses. |
kernel/src/mem/paging.rs init_kernel_page_tables | kernel PML4 expect("failed to allocate kernel PML4"), page-lookup and map expects | Kernel page-table setup | boot-fatal | Assumes kernel image is mapped in bootloader tables and enough frames exist. |
kernel/src/arch/x86_64/syscall.rs init | STAR selector expect("invalid STAR segment configuration") | Syscall init | boot-fatal | GDT selector layout invariant. |
kernel/src/sched.rs context-switch / exit_current / start | CR3 expect("invalid CR3") | Context switch/exit/start | trusted-internal; future lifecycle sensitive | Scheduler should only carry page-aligned address-space roots. |
Audit Method
Candidate sites come from panic-token searches over runtime source plus manual review of nearby indexing and allocation paths on untrusted-input boundaries. The table excludes test-only assertions unless they enforce runtime ABI or layout contracts. Re-run the searches after code changes and classify new sites by reachability, not by token alone.
Search commands:
rg -n "\b(panic!|assert!|assert_eq!|assert_ne!|debug_assert!|debug_assert_eq!|debug_assert_ne!|unwrap\(|expect\(|todo!|unreachable!)" kernel capos-lib capos-config init demos tools schema system.cue Makefile docs -g '*.rs' -g '*.cue' -g '*.md' -g 'Makefile'
rg -n "\b(panic!|assert!|assert_eq!|assert_ne!|debug_assert!|debug_assert_eq!|debug_assert_ne!|unwrap\(|expect\(|todo!|unreachable!)" kernel/src capos-lib/src capos-config/src init/src demos/capos-demo-support/src demos/*/src tools/mkmanifest/src -g '*.rs'