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:
@@ -162,9 +162,28 @@ fn install_gamepad(dir: &Path) -> Result<()> {
|
||||
eprintln!("warning: pnputil /add-driver {} failed", inf.display());
|
||||
}
|
||||
}
|
||||
// Sweep pad devnodes, INCLUDING phantoms a host crash / service stop left behind: a re-created
|
||||
// SwDevice with a known instance id REVIVES the existing devnode with its previously-bound
|
||||
// driver — it never re-ranks against the store — so after an upgrade the old driver keeps
|
||||
// serving (or, across the v1→v2 sealed-channel fence, fails closed and the pad plays dead).
|
||||
// Proven in the field on the RTX box: a v1 phantom pinned the old package through a v2
|
||||
// install. The devnodes are per-session objects the host recreates on demand, so removing
|
||||
// them at driver-install time is always safe; the next pad binds the fresh package.
|
||||
remove_pad_devnodes();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// `pnputil /remove-device` every punktfunk virtual-pad devnode (live or phantom).
|
||||
fn remove_pad_devnodes() {
|
||||
for id in pad_instance_ids() {
|
||||
if run_quiet("pnputil", &["/remove-device", &id]) {
|
||||
println!("removed stale pad devnode {id}");
|
||||
} else {
|
||||
eprintln!("warning: pnputil /remove-device {id} failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── `driver uninstall [--gamepad]` ──────────────────────────────────────────────────────────────
|
||||
// The uninstaller's cleanup counterpart (Inno [UninstallRun]) — the field report was that our
|
||||
// virtual-device drivers survived an uninstall. Removes the pf-vdisplay device node(s) + driver
|
||||
@@ -204,6 +223,9 @@ fn uninstall_pf_vdisplay() -> Result<()> {
|
||||
}
|
||||
|
||||
fn uninstall_gamepad() -> Result<()> {
|
||||
// Devnodes first (incl. phantoms — the same ghost-device complaint the vdisplay uninstall
|
||||
// fixed), then the store packages.
|
||||
remove_pad_devnodes();
|
||||
delete_store_drivers(&["pf_dualsense", "pf_dualshock4", "pf_xusb"]);
|
||||
Ok(())
|
||||
}
|
||||
@@ -235,6 +257,28 @@ fn pf_vdisplay_instance_ids() -> Vec<String> {
|
||||
ids
|
||||
}
|
||||
|
||||
/// Instance IDs of punktfunk virtual-pad devnodes (`SWD\PUNKTFUNK\…`), INCLUDING phantoms left by
|
||||
/// a host crash / service stop (`pnputil /enum-devices` lists disconnected devnodes too). Same
|
||||
/// un-localized VALUE-side parsing as [`pf_vdisplay_instance_ids`]; matched on the instance-id
|
||||
/// prefix itself — the pads span two device classes (HIDClass + System), so no `/class` filter.
|
||||
fn pad_instance_ids() -> Vec<String> {
|
||||
let out = run_capture("pnputil", &["/enum-devices"]);
|
||||
let mut ids = Vec::new();
|
||||
for block in out.split("\r\n\r\n").flat_map(|b| b.split("\n\n")) {
|
||||
let Some(first) = block.lines().find(|l| !l.trim().is_empty()) else {
|
||||
continue;
|
||||
};
|
||||
let Some((_, value)) = first.split_once(':') else {
|
||||
continue;
|
||||
};
|
||||
let id = value.trim();
|
||||
if id.to_ascii_uppercase().starts_with("SWD\\PUNKTFUNK\\") && !id.contains(' ') {
|
||||
ids.push(id.to_string());
|
||||
}
|
||||
}
|
||||
ids
|
||||
}
|
||||
|
||||
/// Delete every driver-store package (`%WINDIR%\INF\oem*.inf`) whose INF text mentions one of
|
||||
/// `needles` — our driver names are unique enough that a content match identifies the package
|
||||
/// without parsing `pnputil /enum-drivers`' localized output. `/uninstall /force` also unbinds it
|
||||
|
||||
Reference in New Issue
Block a user