feat(host/windows): seal the host↔driver channels (frame + gamepad, proto v2)

Frame ring (pf-vdisplay) and both gamepad SHM channels move off named Global\
objects (openable by any sibling LocalService) to UNNAMED sections/events whose
handles the host DuplicateHandles into the driver's verified WUDFHost with least
access — frame delivery over the SYSTEM+admins-only IOCTL_SET_FRAME_CHANNEL,
pads over a 32-byte named bootstrap mailbox (pid + handle value only, DoS-bounded;
HID minidrivers have no control device). Driver-validated pad_index kills
cross-pad redirects; v1↔v2 mixes fail closed with diagnosis logs on both sides.
Sibling-LocalService denial proven empirically (design/idd-push-security.md,
design/gamepad-channel-sealing.md).

Driver-side raw ops now live behind pf-umdf-util (checked shm accessors, the
forbid(unsafe_code) ChannelClient state machine, WDF request tokens) — the pad
drivers' logic is 100% safe Rust; whole drivers workspace clippy-gated in CI.

driver install --gamepad now sweeps SWD\punktfunk phantom devnodes: a re-created
SwDevice REVIVES the old devnode with its previously-bound driver (never
re-ranks), so an upgrade otherwise leaves the old driver serving — or, across
the v1→v2 fence, a dead pad (found live on the RTX box).

On-glass validated on the RTX 4090 box: frame path 7007 frames p50 2.06 ms
cross-machine; DualSense + XUSB "sealed pad channel mapped"/proto=2 attach via
both the test harness and a real streaming session; phantom-sweep repro.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-03 12:08:56 +00:00
parent 16a7991cea
commit 8b47be668f
35 changed files with 2604 additions and 1174 deletions
@@ -53,6 +53,11 @@ pub struct MonitorObject {
/// The live swap-chain drain worker, set by `assign_swap_chain` and dropped (RAII-joins the worker
/// thread) by `unassign_swap_chain` / departure (STEP 5).
pub swap_chain_processor: Option<crate::swap_chain_processor::SwapChainProcessor>,
/// The host's sealed-channel delivery (`IOCTL_SET_FRAME_CHANNEL`) awaiting pickup by the swap-chain
/// worker ([`take_frame_channel`]). Exactly one owner per delivery: replacing or dropping the entry
/// closes an unconsumed channel's handles via [`FrameChannel`]'s `Drop`, so no delivery can leak
/// handles in the WUDFHost table whatever the monitor's fate.
pub frame_channel: Option<crate::frame_transport::FrameChannel>,
/// When the entry was created — the watchdog skips still-initializing monitors.
pub created_at: Instant,
}
@@ -256,8 +261,8 @@ pub fn modes_for_object(object: iddcx::IDDCX_MONITOR) -> Option<Vec<Mode>> {
.map(|m| m.modes.clone())
}
/// The OS target id stamped on the monitor whose handle matches (used by `assign_swap_chain` to name the
/// shared-ring objects). `None` if the monitor isn't found.
/// The OS target id stamped on the monitor whose handle matches (used by `assign_swap_chain` to key the
/// frame-channel stash for its worker). `None` if the monitor isn't found.
pub fn target_id_for_object(object: iddcx::IDDCX_MONITOR) -> Option<u32> {
MONITOR_MODES
.lock()
@@ -267,6 +272,52 @@ pub fn target_id_for_object(object: iddcx::IDDCX_MONITOR) -> Option<u32> {
.map(|m| m.target_id)
}
/// Stash a host frame-channel delivery on the monitor with `target_id` (an ARRIVED monitor — a pending
/// entry's `target_id` is still 0, which the host can never send since OS target ids are non-zero).
/// Replacing an unconsumed delivery drops it → its handles close (it WAS adopted by a prior success).
/// `Err(ch)` if no such monitor exists — the caller must NOT close those handles (the host only sees
/// the error status and reaps its remote duplicates itself; closing here too would double-close values
/// the OS may have reused).
pub fn set_frame_channel(
target_id: u32,
ch: crate::frame_transport::FrameChannel,
) -> Result<(), crate::frame_transport::FrameChannel> {
if target_id == 0 {
return Err(ch);
}
let mut lock = lock_monitors();
if let Some(m) = lock.iter_mut().find(|m| m.target_id == target_id) {
m.frame_channel = Some(ch);
Ok(())
} else {
Err(ch)
}
}
/// Take (remove) the pending frame-channel delivery for `target_id`, transferring handle ownership to
/// the caller (the swap-chain worker's attach). `None` until the host delivers one.
pub fn take_frame_channel(target_id: u32) -> Option<crate::frame_transport::FrameChannel> {
if target_id == 0 {
return None;
}
lock_monitors()
.iter_mut()
.find(|m| m.target_id == target_id)?
.frame_channel
.take()
}
/// Is a frame-channel delivery pending for `target_id`? The swap-chain worker treats a pending
/// delivery as NEWEST-WINS: it supersedes an attached publisher, because the host only re-delivers
/// after (re)creating the ring — and a retry-created ring is a DIFFERENT header mapping, whose
/// generation bump an old publisher (mapped to the previous header) can never observe.
pub fn has_frame_channel(target_id: u32) -> bool {
target_id != 0
&& lock_monitors()
.iter()
.any(|m| m.target_id == target_id && m.frame_channel.is_some())
}
/// Install a swap-chain processor on the monitor whose handle matches, returning any PREVIOUS processor
/// for the caller to drop OUTSIDE the lock. Dropping a processor RAII-joins its worker thread, so it must
/// never happen while holding `MONITOR_MODES` (the worker would block the whole control plane / risk a
@@ -351,6 +402,7 @@ pub fn create_monitor(
adapter_luid_low: 0,
adapter_luid_high: 0,
swap_chain_processor: None,
frame_channel: None,
created_at: Instant::now(),
});
id