drm: refuse a libdrmtap that cannot do the split export

The root --service must never load libEGL/libGLESv2: the point of the split is
that it exports the scanout dma-buf and the unprivileged --server converts. Two
paths could still break that, both because the loader accepted a library too
old to export.

drm_prewarm() called grab() when the loaded .so had no drmtap_grab_desc, and
grab() maps and detiles, so the privileged process pulled in the vendor GL stack
at startup, before any consumer had asked for a frame. The per-connection
capture loop then did the same for every frame, through the CPU fallback.

The version guard could not prevent it: it compared the ABI major only, and this
library is still 0.x, so every release it has ever made passed. Add a floor at
0.4.9, where the split entry points landed, and require the three split symbols,
which also rejects a build that reports a new enough version without carrying
them. That is not hypothetical: a pre-release stamped 0.4.15 shipped without the
multi-GPU accessors. Both refusals fall back to PipeWire/portal and say which
file and which symbols, at warn level.

The split symbols are no longer Options, so the type system carries the
guarantee instead of a convention. What is left of the CPU path is only what it
was meant to be: the consumer has no render node of its own, or the seat exports
no transferable dma-buf. Both are facts about the hardware, with no alternative
that keeps the stream, and neither is a property of which file was on the load
path.

Verified against the real library on i915. With 0.4.15 the export path captures
a tiled XR30 scanout and libEGL stays out of /proc/self/maps, while the old
grab() branch maps it, so the finding reproduces. A stub reporting 0.4.8 and a
stub reporting 0.4.15 without the split symbols are both refused, each with its
own diagnostic. The mirrored repr(C) layouts are unchanged across 0.4.9 to
0.4.15, checked field by field against include/drmtap.h at both ends, so the
floor costs no compatibility that was real.
This commit is contained in:
Mariano Abad
2026-07-28 08:28:53 -03:00
parent ec8e3a3caf
commit eec14a0592
7 changed files with 188 additions and 81 deletions

View File

@@ -102,6 +102,13 @@ jobs:
cargo test --locked --target x86_64-unknown-linux-gnu -p rustdesk --features drm \
--no-fail-fast -- --skip test_get_cursor_pos --skip test_get_key_state
# The capture backend itself lives in the scrap crate, so its unit tests are a separate
# package. `--lib` keeps this to unit tests; none of them touch a device or a display server.
- name: Run scrap crate tests with the drm feature
shell: bash
run: |
cargo test --locked --target x86_64-unknown-linux-gnu -p scrap --features drm --lib
libdrmtap:
name: libdrmtap pin, build and .so contract
runs-on: ubuntu-24.04