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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user