Acting on the 2026-08-13 dependency sweep. Every claim below was re-verified against
the tree before acting on it (greps carry a positive control; the advisories were
re-checked with cargo audit 0.22.2).
SECURITY
- event-listener 5.4.1 -> 5.4.2 (RUSTSEC-2026-0221, unsound Send/Sync on StackSlot;
reaches the tray via zbus and the host via ashpd). This sat unnoticed because
`cargo audit` reports unsoundness as a WARNING and the job fails only on
vulnerabilities — audit.toml now says so out loud.
- spin 0.9.8 -> 0.9.9. 0.9.8 is YANKED and was genuinely compiled (flume via mdns-sd
and relm4, plus lazy_static).
- wayland-scanner 0.31.10 -> 0.31.11, which moves quick-xml 0.39 -> 0.41. That is the
exact trigger audit.toml documented for RUSTSEC-2026-0194/0195, so both ignores are
deleted rather than left as permanent exceptions. Only RUSTSEC-2023-0071 (rsa
Marvin, still unfixed upstream) remains.
- Corrected audit.toml's claim that `paste` arrives "via utoipa-axum": rav1d pulls it
too, so every client has it through the decode path and dropping utoipa-axum would
not have cleared it.
TWO CI GATES THAT SCANNED NOTHING
- `cargo audit` only ever reads the ROOT Cargo.lock. The drivers lock was already in
this job's `paths:` filter, so edits to it triggered a run that then ignored them.
All four secondary workspaces now get an explicit `--file` (verified: clean, bar the
known `paste` warning in drivers).
- packaging/windows/pf-vkhdr-layer had NO lockfile at all while shipping as a DLL in
the host installer, so every build resolved fresh and neither cargo-audit nor
cargo-about ever saw it. Lockfile generated and committed, and added to `paths:`.
UNUSED / DUPLICATE DECLARATIONS
- punktfunk-host: removed 13 dependencies it never references — the Wayland stack
(client, protocols{,-wlr,-misc}, scanner, backend), xkbcommon, reis, khronos-egl,
ash, usbip-sim, parking_lot, bytemuck. The code moved to pf-inject and pf-zerocopy
in the subsystem extraction and those crates declare them; only the manifest entries
and their now-false comments stayed. Also dropped four redundant re-declarations
(tokio/serde_json/futures-util in the Linux block, tower in dev-deps).
- Removed genuinely unused: bytes (punktfunk-core), anyhow (pf-win-display),
tracing (clients/cli), anyhow (clients/session), serde (clients/windows).
- Removed the high-level `wdk` crate from all five driver crates and the drivers
workspace: none of them ever referenced `wdk::` (62 `wdk_sys::` uses; pf-umdf-util
is a full WDF crate that never declared it). `tracing`/`tracing-subscriber` remain
in that lock afterwards but ONLY as wdk-sys build-dependencies, not in the DLLs.
- pf-win-display took punktfunk-core with `quic` for one type (`Mode`) that lives in
the ungated `config` module; now `default-features = false`, which keeps
quinn/tokio/rcgen/opus out of a leaf crate's declared closure.
- pf-encode declared the windows-rs feature `Wdk_Graphics_Direct3D` for a call that
lives in pf-frame and is resolved via GetProcAddress on gdi32.
LATENT BREAKAGE (compiled only by feature unification)
- pf-inject uses `tokio::select!` without declaring `macros` (borrowed from
punktfunk-core's quic feature); pf-capture uses `tokio::sync::oneshot` without
declaring `sync` (borrowed from ashpd->zbus); pf-client-core uses the `minwindef`
and `winnt` windows-rs headers without declaring them (borrowed from
clients/windows). Each now declares what it uses, so an unrelated crate changing its
features cannot break them.
- pf-console-ui took pf-client-core WITHOUT `default-features = false`, unlike every
other consumer. That default is `pyrowave`, which compiles the vendored PyroWave C++
— "fatal on Windows ARM64". Only safe today because the ARM64 leg passes
--no-default-features (which also drops `ui`).
CORRECTED A FALSE INVARIANT
- clients/windows claimed "the workspace builds ONE windows-rs". It does not: wasapi
pulls the crates.io windows 0.62.2 beside the git-rev copy. The invariant that DOES
hold is narrower (reactor and that crate share one rev, which is what makes the
IDXGISwapChain1 hand-off type-check). Comment rewritten, with a warning against
"fixing" it via a blanket [patch.crates-io] — this rev uses header-named features
while a dozen other manifests use the old Win32_* namespace ones.
Plus the safe in-compat `cargo update` sweep (no manifest edits).
Verified on macOS: punktfunk-core 385, pf-update-check 32, c_abi 1 (with
LIBRARY_PATH=/opt/homebrew/opt/opus/lib), cargo audit clean bar the two known
unmaintained warnings. Linux and Windows legs follow.
pf-xusb — virtual Xbox 360 XUSB companion (UMDF2, classic XInput)
A pure-user-mode UMDF2 driver that makes a virtual Xbox 360 controller visible to classic
XInputGetState with no kernel bus driver (no ViGEmBus) — the HIDMaestro approach. It is the
Windows counterpart to ViGEm's X360 target, owned in-tree.
Why this is not the HID driver
XInput does not use HID. xinput1_4.dll enumerates the XUSB device-interface GUID
{EC87F1E3-C13B-4100-B5F7-8B84D54260CB} (SetupDiEnumDeviceInterfaces), opens the Nth present
instance (= player slot 0–3) with CreateFile, and polls it with buffered IOCTLs. So this driver:
- is not a HID minidriver (no
MsHidUmdf) — it's a plain UMDF2 function driver underWUDFRd, System setup class; - registers the XUSB interface with
WdfDeviceCreateDeviceInterface(device, &XUSB_GUID, NULL); - answers the XUSB IOCTLs (all
METHOD_BUFFERED, delivered to user mode by the reflector) from controller state the host publishes into an unnamed shared DATA section reached over the sealed pad channel (punktfunk-planning:gamepad-channel-sealing.md): the host duplicates the section handle into this driver's WUDFHost, bootstrapped via the namedGlobal\pfxusb-boot-<index>mailbox (pf_driver_proto::gamepad::PadBootstrap); a game's rumble (SET_STATE) is published back for the host to forward to the client.
The WAIT_* IOCTLs return STATUS_INVALID_DEVICE_REQUEST, which makes xinput1_4 fall back to
synchronous GET_STATE polling — so no manual queue / timer is needed for classic XInput. (WGI/
GameInput admission additionally needs a xinputhid UpperFilters registry tripwire + the async
WAIT_FOR_INPUT pump — not implemented; classic XInput does not need it.)
Verified wire formats (source: HIDMaestro driver/companion.c, nefarius/XInputHooker XUSB.h, ViGEm)
| IOCTL | Code | Reply |
|---|---|---|
GET_INFORMATION |
0x80006000 |
12 B: [0]=ver 0x0103, [2]=count 0x01, [8]=VID 045E, [10]=PID 028E — marks the slot connected |
GET_CAPABILITIES |
0x8000E004 |
24 B (or 36 B V2 if outLen>=36): Type 0x03/SubType 0x01, motor max 0xFFFF (advertise rumble) |
GET_STATE |
0x8000E00C |
29 B: [0]ver [2]count [5]u32 packet# [0x0B]u16 wButtons [0x0D]LT [0x0E]RT [0x0F..0x16]4×i16 sticks |
SET_STATE |
0x8000A010 |
input 5 B {00, led, large, small, subcmd}: subcmd 0x02=rumble (large [2], small [3]), 0x01=player-LED |
GET_LED_STATE |
0x8000E008 |
{0,0,0x06} |
GET_BATTERY_INFORMATION |
0x8000E018 |
{0,0x01,0x03,0} |
WAIT_GUIDE_BUTTON / WAIT_FOR_INPUT |
0x8000E014 / 0x8000E3AC |
STATUS_INVALID_DEVICE_REQUEST → GET_STATE fallback |
wButtons is the XINPUT_GAMEPAD_* bitmap (DPAD_UP 0x0001 … A 0x1000 B 0x2000 X 0x4000
Y 0x8000). dwPacketNumber (GET_STATE [5]) must increment whenever the payload changes.
Shared-memory layout (unnamed DATA section, 64 B) — host writes state, driver writes rumble
pf_driver_proto::gamepad::XusbShm (the crate owns the offsets; both sides compile against it):
magic u32 @0 ("PFXU" 0x55584650) · packet u32 @4 (host bumps → dwPacketNumber) · wButtons u16 @8 · LT @10 · RT @11 · LX/LY/RX/RY i16 @12/@14/@16/@18 · rumble_seq u32 @24 (driver bumps) ·
large @28 · small @29 · health marks @32/@36 · pad_index u32 @40 (validated against the
devnode's Location index when the delivered handle is mapped).
Validated live (2026-06-22, maintainer's RTX test box)
XInputGetState(0) returns CONNECTED with the pushed buttons/sticks and an incrementing
dwPacketNumber; XInputSetState(0xC000, 0x4000) reaches the driver as 00 00 c0 40 02 → host sees
large=192 small=64. Test tools (on that box): xusbtest.exe (creates the pf_xusb
devnode + cycling state via shm) and xinputtest.exe (XInputGetState/SetState harness).
Build / sign / install (same recipe as the DualSense driver)
Built as a member of the in-tree packaging/windows/drivers/ workspace — one
cargo build --release builds all three drivers; build-gamepad-drivers.ps1 (one level up) wraps
the whole build/sign/stage flow in CI. The manual steps:
cargo build --releasein the workspace (envLIBCLANG_PATH,Version_Number=10.0.26100.0) →target\x86_64-pc-windows-msvc\release\pf_xusb.dll.- Clear the FORCE_INTEGRITY PE bit (bit
0x80ate_lfanew+0x5eofpf_xusb.dll). signtool sign /fd SHA256 /sha1 6A52984E54376C45A1C236B1A2C8A746C5AB6131 pf_xusb.dll.Inf2Cat /driver:<pkg> /os:10_X64→ re-signpf_xusb.catwith the same thumbprint.pnputil /add-driver pf_xusb.inf(no/install; the host SwDeviceCreate'spf_xusbper session).
Host integration (done)
crates/punktfunk-host/src/inject/windows/gamepad_windows.rs is the Windows GamepadManager (used by
PadBackend::Xbox360): it SwDeviceCreate's the pf_xusb companion, delivers the unnamed DATA
section over the sealed channel (PadChannel), writes
the XInput state from the client's gamepad frame (already XInput-convention) and forwards rumble. There
is no ViGEmBus dependency anymore. The driver is built + signed from source in CI
(build-gamepad-drivers.ps1) and installed by the Inno Setup installer via
punktfunk-host.exe driver install --gamepad.
Multi-pad
The host stamps each pad's index into the device Location (pszDeviceLocation); the driver reads it
via WdfDeviceAllocAndQueryProperty(DevicePropertyLocationInformation) in EvtDeviceAdd and polls its own
pfxusb-boot-<index> bootstrap mailbox (the delivered DATA section's pad_index is validated against it). UmdfHostProcessSharing=ProcessSharingDisabled (the INF) gives each pad its own
WUDFHost, so the per-pad SHM_INDEX static doesn't collide. Validated live: two pads → two distinct
XInput slots. (XInput assigns the player slot 0-3 by interface-enumeration order, independent of this
index — which only routes shared memory.)