# Full-Scope Review 2026-06-09

Findings ledger for the full-scope review cycle completed at
2026-06-09 19:01 UTC. Eight
independent subsystem reviews covered the tree at commit `50e8eaba`
(2026-06-09) against the previous review base `bb776326e` (2026-05-23). Each
open finding below is remediated through a task record under `docs/tasks/`
whose `source` points here; severities are carried into task `priority`.
Documentation-status findings (stale status wording, landed-behavior drift)
were remediated directly in commit `3ac860dc` and are not re-listed.

## Scopes Reviewed

1. Storage on-disk formats and mount validation (kernel storage caps,
   `tools/mkstore-image`).
2. Storage services and installable-system flow (init generation/rollback,
   `storage-persist-service`, NVMe-backed `BlockDevice`).
3. Kernel core and x86_64 architecture (fault handlers, TLB shootdown, ELF
   spawn, percpu/SMP/paging/IOAPIC/ISO reader).
4. Device Driver Foundation authority (MMIO bounds, DMA-buffer release
   invariants, device-manager proof gating).
5. Remote-session Web UI and network-facing services.
6. Schema, generated bindings, and System Manual.
7. Userspace runtime and POSIX adapter (`capos-rt`, `libcapos-posix`).
8. Fuzzing, host-test harnesses, tooling, and CI workflows.

## Findings By Scope

### 1. Storage on-disk formats and mount validation

- High — `kernel/src/cap/persistent_store.rs:parse_disk_store`,
  `kernel/src/cap/writable_fs.rs:mount_volume`: live extents are validated
  only against the data region, not against `next_free_sector` or each other.
  A crafted or torn image with a live extent in the bump-allocator free region
  mounts cleanly and is silently overwritten by the next `put_blob` /
  `persist_file`; `compact_reclaim`'s shadow-generation copy into the
  data-region tail clobbers such extents mid-copy; overlapping live extents
  are accepted.
- Low — `writable_fs.rs:mount_volume` (also `readonly_fs`,
  `persistent_store`): duplicate sibling names are silently collapsed by
  `BTreeMap` insert instead of failing the mount.
- Low — `tools/mkstore-image:write_caposwf1_dir_node` /
  `write_caposwf1_file_node`: name-length assertion uses
  `WF_NODE_RECORD_BYTES - WF_NODE_OFF_NAME` (104) instead of the kernel's
  `MAX_DISK_NAME_BYTES` (88).
- Medium — `persistent_store.rs:DiskStoreCap::get_blob`: returns disk bytes
  trusting the entry table without re-verifying `content_hash(bytes) == key`;
  init fetches generation objects by hash from this store, so a disk-level
  edit swaps active system-config content undetected.

### 2. Storage services and installable-system flow

- Medium — `demos/storage-persist-service/src/bin/server.rs:commit`:
  overwrites the single payload region in place before the superblock write;
  a crash mid-payload-write destroys the previously committed snapshot and
  wedges startup. The doc comment overclaims torn-write safety; this service
  is the named production storage route.
- Medium — `init/src/main.rs:read_candidate_pointer` /
  `decide_boot_generation`: a corrupt or truncated `gen-candidate` marker
  parses to `Err` and fails boot closed (the CREATE|TRUNCATE marker rewrite
  persists a durable size-0 window), contradicting the "a bad generation can
  never permanently brick the system" guarantee.
- Medium — `kernel/src/cap/block_device.rs:NVME_ARBITRARY_NAMESPACE_BLOCKS`:
  hardcodes the 16 MiB QEMU fixture geometry (32768 blocks) on the
  always-built NVMe arm; `BlockDevice.info` and the filesystem/store
  `BlockSource::info` repeat it, so larger real namespaces are unreachable.
  `kernel/src/nvme_storage_backend.rs` "production" wording omits the
  bounded sync-io seam (64 ops/boot, wedges on CQ wrap).

### 3. Kernel core and x86_64 architecture

- High — `kernel/src/arch/x86_64/idt.rs:page_fault_handler` /
  `gp_fault_handler` / `invalid_opcode_handler`: CPL3 faults halt the whole
  machine; the "no task abstraction yet" rationale is stale now that
  `sched::exit_current_thread` and process exit cleanup exist. Any userspace
  null deref is a full-system denial of service.
- Medium — `kernel/src/arch/x86_64/tlb.rs:kernel_tlb_shootdown_all`: the
  remote ack uses a CR3-reload flush, which under CR4.PGE does not evict
  GLOBAL entries — the very kernel upper-half/MMIO mappings it exists for.
  Safe for the sole current caller (fresh non-present→present installs), but
  `tlb.rs` and `mem/paging.rs` advertise unmap/revoke reuse.
- Medium — `kernel/src/spawn.rs` PT_LOAD mapping: `PF_W|PF_X` segments map
  PRESENT|USER|WRITABLE without NX; `capos_lib::elf` does not reject W+X.
- Low (bundle) — `percpu.rs:current_cpu_id` `unwrap_or(0)` masquerades
  unknown LAPIC ids as the BSP; `smp.rs` `AP_CPUS` spin-mutex IF constraint
  undocumented; `mem/paging.rs:map_kernel_physical_range` partial failure
  leaks installed PTEs and the VA window; `ioapic.rs:write_destination`
  restores mask from the cached record, not hardware; `mem/validate.rs`
  legacy `validate_user_buffer` is dead code; `kernel/src/iso/mod.rs`
  `ISO_BOOT_SOURCE` mutex held across a full polled-PIO ELF transfer;
  `capos-rt/src/panic.rs` emergency console write can race a live SQ
  producer.

### 4. Device Driver Foundation authority

- Medium — `kernel/src/virtio_transport.rs:MmioRegion`: volatile accessor
  bounds are `debug_assert!`-only and the kernel ships release, so the
  documented "range-checks before reaching device MMIO" contract is false in
  shipped builds; some regions claim the full BAR length while only a
  `MAPPED_COMMON_CFG_LIMIT` prefix is mapped.
- Medium — `kernel/src/device_manager/stub.rs:`
  `detach_dmabuffer_record_for_cap_release_with_reason`: the
  pinned-enabled-vring refusal, RX-DMA quarantine, and autonomous-MSI-X/NVMe
  handoff blocks live in per-proof `cfg` islands, while the invariant — never
  free a frame the device may still master — is production DMA-lifetime
  behavior.

### 5. Remote-session Web UI

- Medium — `demos/remote-session-web-ui/src/main.rs:do_login`: no login rate
  limiting and no `accepted.peer_addr` check; loopback-only is enforced
  solely by topology plus forgeable Host/Origin headers, weaker than the host
  bridge sibling. `/api/probe/expire` and `/api/probe/stale-call` proof seams
  ship unconditionally in the production-named binary.

### 6. Schema, generated bindings, and System Manual

- Medium — `schema/capos.capnp` `SymmetricKey`..`CertVerifier` block uses
  leading-style doc comments; capnp attaches docs to the preceding
  declaration, so every comment shifts one method in the checked-in bindings
  and the System Manual ships misattributed descriptions. The `manualc`
  coverage gate is interface-level only, so it passes.

### 7. Userspace runtime and POSIX adapter

- Medium — `capos-rt/src/ring.rs:pack_copy_transfers`: computes
  `params_offset` from the `Vec`'s `as_ptr` before `into_boxed_slice` may
  realloc, invalidating the computed alignment; currently saved only by
  undocumented allocator behavior, and the existing alignment test passes
  vacuously under the 16-aligned host allocator.
- Medium (bundle) — `libcapos-posix`: `dup`/`dup2`/`F_DUPFD` snapshot `pos`
  per slot instead of sharing the open-file-description offset (`src/fd.rs`);
  `poll`/`select` ignore the timeout entirely so infinite timeout returns 0
  and callers busy-spin (`src/poll.rs`); `errno::clear()` on shim entry
  violates C11 §7.5; `F_SETFL` accepts-and-ignores `O_NONBLOCK` then `read`
  blocks forever. No `#[cfg(test)]` host unit tests exist in the crate.

### 8. Fuzzing, harnesses, tooling, and CI

- Medium — `fuzz/fuzz_targets/manifest_capnp.rs` fuzzes a 4096-word/16-deep
  envelope while production `default_reader_options` allows 64 Mi words and
  nesting 32; the ISO 9660 record/PVD parser, the CAPOSRO1/CAPOSST1/CAPOSWF1
  mount parsers, the `capos-tls` DER validity walk
  (`capos-tls/src/cert.rs:parse_validity`), and
  `storage-persist-service:deserialize_state`/`parse_superblock` have no
  fuzz or host coverage.
- Low (bundle) — CI Miri step soft-skips when the component is missing
  (`.github/workflows/ci.yml`); `publish-crates.yml` `cargo publish
  --no-verify` is uncommented; the `sqe_validation` fuzz `PARK_BENCH` arm is
  permanently reject-only without a measure-feature fuzz build;
  `capos-wasm/src/wasi/fs.rs:install_preopen` discards its
  `try_reserve_exact` result.

## Spawned Task Records

All records carry `source: docs/backlog/full-scope-review-2026-06-09.md`:

- `review-storage-mount-extent-placement-validation` (high)
- `review-storage-store-get-hash-verification`
- `review-storage-persist-service-crash-safe-commit`
- `review-installable-torn-candidate-fallback`
- `review-storage-nvme-identify-geometry`
- `review-kernel-user-fault-containment` (high)
- `review-kernel-tlb-global-shootdown-ack`
- `review-spawn-wx-segment-rejection`
- `review-ddf-mmio-region-release-bounds`
- `review-ddf-dmabuffer-detach-invariant-hoist`
- `review-webui-inguest-login-hardening`
- `review-schema-crypto-doc-attribution`
- `review-fuzz-parser-coverage`
- `review-capos-rt-transfer-pack-alignment`
- `review-posix-fd-semantics`
- `review-kernel-arch-hardening-lows` (low bundle)
- `review-tooling-ci-lows` (low bundle)
