drm: address the phase-2 split review

1- do not depend on the libdrmtap-sys crate for the pin: its build.rs statically
compiles the whole libdrmtap C tree and a CAP_SYS_ADMIN helper and links
-ldrm/-lseccomp/-lcap, which defeats the runtime-dlopen model. keep drm a pure
dlopen backend and pin the .so by the build.py DRMTAP_REF release tag, guarded by
a strict vX.Y.Z regex. drops the now-moot Cargo.lock freshness CI checks.
2- render-node-less consumers no longer lose the stream: the --server signals
need_cpu on DrmStart when it cannot open a convert context, and the --service
streams the CPU-converted frame path for that connection instead of a dma-buf fd
the consumer cannot detile (which used to fall through to a PipeWire path nobody
can approve on an unattended seat).
3- mark PipeWire initialized only after every per-display capturer is created, so
a partial failure retries instead of the flag falsely reporting a complete init.
4- reject a degenerate (zero width/height) or short CPU frame before it reaches
PixelBuffer::new (which derives stride as data.len()/height, dividing by zero).
5- keep the export-ledger epoch at DRM_DISPLAY_GENERATION so a hotplug invalidates
cached buffers (elision stays off until the recycled-fb_id inode case is handled).
6- validate the udev uevent source (kernel nl_pid, multicast) with recvmsg so a
local process cannot unicast a spoofed drm-change event to the root listener.
This commit is contained in:
Mariano Abad
2026-07-21 00:25:19 -03:00
parent 3b6914b1b2
commit 6cc426e9f5
7 changed files with 131 additions and 88 deletions

View File

@@ -11,11 +11,13 @@ edition = "2018"
[features]
wayland = ["gstreamer", "gstreamer-app", "gstreamer-video", "dbus", "tracing", "zbus"]
# `drm` pulls in the exact-pinned `libdrmtap-sys` crate (see the Linux target table below). rustdesk
# still dlopen's `libdrmtap.so.0` at runtime (`drmtap_dl.rs`) rather than link-time linking it, so the
# graceful PipeWire fallback when the .so/EGL is absent is preserved; the crate is pinned purely so its
# committed Cargo.lock checksum supply-chain-pins the vendored source that build.py bundles.
drm = ["dep:libdrmtap-sys"]
# `drm` is a pure runtime-dlopen backend: rustdesk loads `libdrmtap.so.0` at runtime (`drmtap_dl.rs`)
# and NEVER link-time links it, so the graceful PipeWire fallback when the .so or EGL is absent is
# preserved and the drm build pulls in no libdrm/seccomp/cap/EGL link-time deps. The .so is version
# pinned by build.py's `DRMTAP_REF = v0.4.13` (an exact release tag, not `main`). We deliberately do
# NOT depend on the `libdrmtap-sys` crate: its build.rs statically compiles the whole libdrmtap C tree
# and a CAP_SYS_ADMIN helper and emits `-ldrm -lseccomp -lcap`, which would defeat the dlopen model.
drm = []
mediacodec = ["ndk"]
linux-pkg-config = ["dep:pkg-config"]
hwcodec = ["dep:hwcodec"]
@@ -63,16 +65,6 @@ gstreamer = { version = "0.16", optional = true }
gstreamer-app = { version = "0.16", features = ["v1_10"], optional = true }
gstreamer-video = { version = "0.16", optional = true }
zbus = { version = "3.15", optional = true }
# libdrmtap ABI, pinned EXACTLY (the leading `=` blocks ^0.4.x semver drift). This is the ONLY
# supply-chain pin for libdrmtap: the committed Cargo.lock `checksum` for this exact version pins the
# bytes, so `cargo build --locked` refuses a tampered/republished 0.4.13. It must move in lockstep
# with build.py's `DRMTAP_REF = v0.4.13` (the bundled runtime .so) — the loader only checks ABI-major.
# NOTE for the integrator: after this edit the lockfile MUST be regenerated + committed with
# cargo update -p libdrmtap-sys --precise 0.4.13
# so Cargo.lock gains the `[[package]] libdrmtap-sys 0.4.13 checksum=<sha256>` block (this stage does
# not run cargo). `=0.4.13` alone is a version requirement, not a byte pin — the checksum is the pin.
libdrmtap-sys = { version = "=0.4.13", optional = true }
[dependencies.hwcodec]
git = "https://github.com/rustdesk-org/hwcodec"
optional = true