Our virtual DualSense wakes Bazzite's ds_inhibit into an SELinux audit storm that freezes the stream #248

Merged
enricobuehler merged 1 commits from worktree-ds-inhibit-storm into main 2026-08-15 13:08:06 +00:00
Owner

Field-diagnosed on Bazzite 43 (2026-08-15): the virtual DualSense/DualShock 4 binds hid-playstation, and Valve's ds_inhibit (steamos-manager) reacts to every open/close of any such hidraw by walking /proc/*/fd — it has no VID/PID or virtual filtering. Bazzite's SELinux policy denies steamos_manager_t that walk (sys_ptrace, dac_read_search, dac_override) at ~324 AVCs/sec, and setroubleshootd amplifies the flood into a box-wide fork storm (267+ procs/sec, a core burned, RSS climbing 15+ min after the denials stop) that starves the stream: gamescope 0 fps, encode submit ~150 ms/frame, tx 300 → 1 Mbps, session death. punktfunk is the trigger, not the defect — but we ship the trigger. The root cause is Bazzite's policy gap (reproducible with a physical DualSense too); this PR is the containment we can ship, and the upstream report is tracked separately.

  • packaging/bazzite/punktfunk-ds-inhibit.cil — a dontaudit drop-in (dontaudit, not allow: granting another vendor's daemon ptrace-class capabilities is Bazzite's security decision, not ours; the scan keeps failing quietly and ds_inhibit simply leaves the pad uninhibited, which is what we want anyway). The RPM ships the source under /usr/share/punktfunk/selinux/ — the policy store is host state, so a sysext image can only carry source; punktfunk-sysext post_merge/reapply inserts it idempotently and the RPM %post does the same best-effort, both keyed on the steamos-manager binary and on the module name (rename the .cil if its rules ever change, or existing installs never converge).
  • native/gamepad.rswarn_if_ds_inhibit_storm in the resolve_gamepad funnel: one-shot, warn-only (a per-pad degrade has no wire channel back to the client and would strip the DS5 feature set exactly where users want it). Fires on steamos-manager running + SELinux enforcing, and puts the cause in our logs — the AVC lines read comm="tokio-rt-worker" and look exactly like us.
  • packaging/bazzite/README.md — the failure chain, both diagnosis traps, and the setroubleshootd mask as general hardening (any AVC burst reproduces the amplifier; nothing depends on that daemon).

Not pursued: suppressing the touchpad mouse* node to duck ds_inhibit's selection — hid-playstation registers the touchpad from hardcoded driver code (ps_touchpad_create in dualsense_create/dualshock4_create), not from our HID descriptor.

Verified: gamepad tests incl. the new detection test pass on linux-gnu (punktfunk-rust-ci container); clippy --all-targets -D warnings clean; the CIL compiles under secilc against a stub base (planted-error negative control caught); shellcheck clean on punktfunk-sysext.sh; cargo fmt run.

Field-diagnosed on Bazzite 43 (2026-08-15): the virtual DualSense/DualShock 4 binds `hid-playstation`, and Valve's `ds_inhibit` (steamos-manager) reacts to every open/close of any such hidraw by walking `/proc/*/fd` — it has no VID/PID or virtual filtering. Bazzite's SELinux policy denies `steamos_manager_t` that walk (`sys_ptrace`, `dac_read_search`, `dac_override`) at ~324 AVCs/sec, and `setroubleshootd` amplifies the flood into a box-wide fork storm (267+ procs/sec, a core burned, RSS climbing 15+ min **after** the denials stop) that starves the stream: gamescope 0 fps, encode submit ~150 ms/frame, tx 300 → 1 Mbps, session death. punktfunk is the trigger, not the defect — but we ship the trigger. The root cause is Bazzite's policy gap (reproducible with a *physical* DualSense too); this PR is the containment we can ship, and the upstream report is tracked separately. - **`packaging/bazzite/punktfunk-ds-inhibit.cil`** — a `dontaudit` drop-in (dontaudit, not allow: granting another vendor's daemon ptrace-class capabilities is Bazzite's security decision, not ours; the scan keeps failing quietly and ds_inhibit simply leaves the pad uninhibited, which is what we want anyway). The RPM ships the source under `/usr/share/punktfunk/selinux/` — the policy *store* is host state, so a sysext image can only carry source; `punktfunk-sysext` `post_merge`/`reapply` inserts it idempotently and the RPM `%post` does the same best-effort, both keyed on the steamos-manager binary and on the module name (rename the `.cil` if its rules ever change, or existing installs never converge). - **`native/gamepad.rs`** — `warn_if_ds_inhibit_storm` in the `resolve_gamepad` funnel: one-shot, warn-only (a per-pad degrade has no wire channel back to the client and would strip the DS5 feature set exactly where users want it). Fires on steamos-manager running + SELinux enforcing, and puts the cause in **our** logs — the AVC lines read `comm="tokio-rt-worker"` and look exactly like us. - **`packaging/bazzite/README.md`** — the failure chain, both diagnosis traps, and the `setroubleshootd` mask as general hardening (any AVC burst reproduces the amplifier; nothing depends on that daemon). Not pursued: suppressing the touchpad `mouse*` node to duck ds_inhibit's selection — `hid-playstation` registers the touchpad from hardcoded driver code (`ps_touchpad_create` in `dualsense_create`/`dualshock4_create`), not from our HID descriptor. Verified: gamepad tests incl. the new detection test pass on linux-gnu (punktfunk-rust-ci container); `clippy --all-targets -D warnings` clean; the CIL compiles under secilc against a stub base (planted-error negative control caught); shellcheck clean on `punktfunk-sysext.sh`; `cargo fmt` run.
enricobuehler added 1 commit 2026-08-15 13:07:13 +00:00
fix(gamepad): our virtual DualSense wakes Bazzite's ds_inhibit into an SELinux audit storm that freezes the stream
ci / rust-arm64 (pull_request) Successful in 1m23s
ci / bun-nix (pull_request) Successful in 1m26s
ci / web (pull_request) Successful in 4m22s
ci / docs-site (pull_request) Successful in 4m32s
ci / rust (pull_request) Failing after 4m57s
android / android (pull_request) Successful in 13m27s
2e753fd84d
Field-diagnosed on Bazzite 43 (2026-08-15): the virtual DualSense/DualShock 4
binds hid-playstation, and Valve's ds_inhibit (steamos-manager) reacts to every
open/close of any such hidraw by walking /proc/*/fd — it has no VID/PID or
virtual filtering. SELinux denies steamos_manager_t that walk (sys_ptrace,
dac_read_search, dac_override) at ~324 AVCs/sec, and setroubleshootd amplifies
the flood into a box-wide fork storm (267+ procs/sec, a core burned, RSS
climbing for 15+ min AFTER the denials stop) that starves the stream: gamescope
0 fps, encode submit ~150 ms/frame, tx 300 -> 1 Mbps, session death. punktfunk
is the trigger, not the defect — but we ship the trigger.

- packaging/bazzite/punktfunk-ds-inhibit.cil: a dontaudit drop-in (dontaudit,
  not allow — granting another vendor's daemon sys_ptrace/dac_* is not ours to
  do; the scan keeps failing quietly and ds_inhibit leaves the pad
  uninhibited, which is what we want anyway). The RPM ships the source under
  /usr/share/punktfunk/selinux/ (the policy STORE is host state, so a sysext
  image can only carry source); inserted idempotently by punktfunk-sysext
  post_merge / reapply and best-effort by the RPM %post, both keyed on the
  steamos-manager binary and on the module name — rename the .cil if its rules
  ever change, or existing installs never converge.
- native/gamepad.rs: warn_if_ds_inhibit_storm in the resolve_gamepad funnel —
  one-shot, warn-only (a per-pad degrade has no wire channel back to the
  client and would strip the DS5 feature set exactly where users want it).
  Fires on steamos-manager running + SELinux enforcing, and puts the cause in
  OUR logs: the AVC lines read comm="tokio-rt-worker" and look like us.
- packaging/bazzite/README.md: the failure chain, both diagnosis traps, and
  the setroubleshootd mask as general hardening (any AVC burst reproduces the
  amplifier; nothing depends on that daemon).

Not pursued: suppressing the touchpad mouse node to duck ds_inhibit's
selection — hid-playstation registers the touchpad from hardcoded driver code
(ps_touchpad_create in dualsense_create/dualshock4_create), not from our HID
descriptor, so no descriptor shaping can remove it.

Verified: gamepad tests incl. the new detection test pass on linux-gnu
(punktfunk-rust-ci container); clippy --all-targets -D warnings clean; the CIL
compiles under secilc against a stub base (planted-error control caught);
shellcheck clean on punktfunk-sysext.sh.
enricobuehler scheduled this pull request to auto merge when all checks succeed 2026-08-15 13:07:58 +00:00
enricobuehler merged commit 0e8149fa9c into main 2026-08-15 13:08:06 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: unom/punktfunk#248