mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-09-11 15:01:02 +03:00
drm: close the full-review findings (a third latched flag, and two escapees)
The one that matters: the display-cache refresh worker was the THIRD copy of the wedged-flag hazard. catch_unwind covered only the enumeration, and thread::spawn panics on EAGAIN after RUNNING was already swapped true, so either path parked the flag for the process lifetime and every later refresh - including every udev hotplug - returned early forever. Same ownership guard as UINPUT_REFRESH_BUSY (the flag is handed back and re-taken mid-loop, so an unconditional RAII release would clear a replacement worker's flag), plus a fallible spawn whose failure drops the closure and releases the slot. DRM_PROBE_IN_FLIGHT, UINPUT_REFRESH_BUSY, now this: the lesson stays 'grep for every site with the shape', and twice was not enough. Two findings had been flagged in an earlier round and escaped the ledger: - an unrecognized convert-output fourcc fell through to 'present as BGRA' with a debug log, where every sibling validation in that function is a hard error that lets the caller fall back to PipeWire. A 64bpp output passes the stride check and encodes garbage. Hard error now. - the trust-boundary validation constants (fourccs, MAX_DIM, MAX_FRAME_BYTES) were declared independently on both sides of the split. Hoisted into drm_reader, imported by the converter, so the two halves cannot drift apart about what data they will touch. The rest: - the CI symbol extraction dropped any loader symbol containing a digit and degraded to a pass-with-zero-iterations no-op if the b"..." literals were ever refactored; digits allowed, count asserted, notice de-hardcoded. - 'drm' in features was a substring test on the comma-joined string, so a future drm-lease feature would have shipped the consent-bypass deb without --drm. Exact membership now. - the security doc claimed the deb is built on an ubuntu18.04 container; the only deb job runs on ubuntu-24.04. The 18.04 sentence now says what is true: 2.4.95 is an API floor, the binary floor is the build host's. - DRM_DISPLAY_CACHE poison handling was recover-in-the-writer, panic-in-the-readers; both readers now recover like the writer. - the producer prewarm ran on X11 where no consumer can connect, the same inconsistency just fixed for warm_availability. The listener still starts (the service outlives sessions; a later Wayland login must find the socket), only the prewarm is skipped.
This commit is contained in:
@@ -18,9 +18,22 @@ use std::ffi::CString;
|
||||
use std::io;
|
||||
use std::os::fd::{FromRawFd, OwnedFd};
|
||||
|
||||
// The validation limits and pixel formats BOTH halves of the split rely on to agree about what data
|
||||
// they will touch. They live here, once, and `drm_render` (the unprivileged converter) imports them:
|
||||
// these are trust-boundary guards, so two independently-edited copies that drift apart would silently
|
||||
// weaken validation on one side of the boundary.
|
||||
//
|
||||
// Largest scanout we will copy; also bounds w*4*h against overflow. 16384 covers
|
||||
// 8K+ with headroom; anything larger is rejected as a bogus/hostile geometry.
|
||||
const MAX_DIM: u32 = 16384;
|
||||
pub(crate) const MAX_DIM: u32 = 16384;
|
||||
// 256 MiB covers an 8K BGRA frame (7680x4320x4 ~= 127 MiB) with margin.
|
||||
pub(crate) const MAX_FRAME_BYTES: usize = 256 * 1024 * 1024;
|
||||
// DRM fourccs of the 32-bit linear formats the split can carry. XRGB/ARGB are little-endian
|
||||
// B,G,R,{X,A} in memory == `Pixfmt::BGRA`; XBGR/ABGR are R,G,B,{X,A} == `Pixfmt::RGBA`.
|
||||
pub(crate) const DRM_FORMAT_XRGB8888: u32 = 0x3432_5258; // 'XR24'
|
||||
pub(crate) const DRM_FORMAT_ARGB8888: u32 = 0x3432_5241; // 'AR24'
|
||||
pub(crate) const DRM_FORMAT_XBGR8888: u32 = 0x3432_4258; // 'XB24'
|
||||
pub(crate) const DRM_FORMAT_ABGR8888: u32 = 0x3432_4241; // 'AB24'
|
||||
|
||||
/// Sentinel cursor id published when the plane reports the cursor hidden, so the
|
||||
/// id changes and the client drops the last shape. Distinct from any real hash.
|
||||
@@ -220,8 +233,6 @@ impl DrmReader {
|
||||
// XBGR8888 passes the stride check above but, labeled BGRA downstream, would ship with red
|
||||
// and blue swapped — so reject any fourcc we cannot present as BGRA. A zero/unknown fourcc
|
||||
// falls through to the stride invariant (kept for libdrmtap builds that do not set it).
|
||||
const DRM_FORMAT_XRGB8888: u32 = 0x3432_5258; // 'XR24'
|
||||
const DRM_FORMAT_ARGB8888: u32 = 0x3432_5241; // 'AR24'
|
||||
if frame.format != 0
|
||||
&& frame.format != DRM_FORMAT_XRGB8888
|
||||
&& frame.format != DRM_FORMAT_ARGB8888
|
||||
@@ -241,8 +252,8 @@ impl DrmReader {
|
||||
// would otherwise resize to gigabytes and, with several concurrent readers, OOM the root
|
||||
// --service. 256 MiB covers an 8K BGRA scanout (7680x4320x4 ~= 127 MiB) with margin;
|
||||
// anything larger (or an overflow) is rejected as unsupported. checked_mul guards the
|
||||
// multiply on 32-bit usize too.
|
||||
const MAX_FRAME_BYTES: usize = 256 * 1024 * 1024;
|
||||
// multiply on 32-bit usize too. MAX_FRAME_BYTES is the file-level shared limit, the
|
||||
// same one the converter enforces on its side of the boundary.
|
||||
let frame_size = match w.checked_mul(4).and_then(|x| x.checked_mul(h)) {
|
||||
Some(sz) if sz > 0 && sz <= MAX_FRAME_BYTES => sz,
|
||||
other => {
|
||||
|
||||
@@ -22,22 +22,15 @@ use std::ffi::CString;
|
||||
use std::io;
|
||||
use std::os::fd::RawFd;
|
||||
|
||||
// DRM fourccs of the 32-bit linear formats libdrmtap's convert can emit. XRGB/ARGB
|
||||
// are little-endian B,G,R,{X,A} in memory == our `Pixfmt::BGRA`; XBGR/ABGR are
|
||||
// R,G,B,{X,A} == `Pixfmt::RGBA`. libdrmtap normalizes the EGL path to XRGB8888, but
|
||||
// we read `frame.format` per frame so a CPU-fallback convert that keeps the source
|
||||
// channel order is still presented correctly (not hardcoded BGRA).
|
||||
const DRM_FORMAT_XRGB8888: u32 = 0x3432_5258; // 'XR24'
|
||||
const DRM_FORMAT_ARGB8888: u32 = 0x3432_5241; // 'AR24'
|
||||
const DRM_FORMAT_XBGR8888: u32 = 0x3432_4258; // 'XB24'
|
||||
const DRM_FORMAT_ABGR8888: u32 = 0x3432_4241; // 'AB24'
|
||||
|
||||
// Same geometry / size guards as the export side (`drm_reader`), applied to the
|
||||
// convert OUTPUT so a malformed `frame_info` cannot make us build an out-of-range
|
||||
// slice from the context-owned pointer. 16384 covers 8K+; 256 MiB covers an 8K
|
||||
// BGRA frame (7680x4320x4 ~= 127 MiB) with margin.
|
||||
const MAX_DIM: u32 = 16384;
|
||||
const MAX_FRAME_BYTES: usize = 256 * 1024 * 1024;
|
||||
// The geometry/size limits and pixel fourccs are SHARED with the export side, declared once in
|
||||
// `drm_reader`: they are the guards both halves of the trust boundary rely on to agree about what
|
||||
// data they will touch, so a private copy here could silently drift from the privileged side's.
|
||||
// libdrmtap normalizes the EGL path to XRGB8888, but we read `frame.format` per frame so a
|
||||
// CPU-fallback convert that keeps the source channel order is still presented correctly.
|
||||
use super::drm_reader::{
|
||||
DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB8888,
|
||||
MAX_DIM, MAX_FRAME_BYTES,
|
||||
};
|
||||
|
||||
/// An unprivileged DRM render-node convert context (`drmtap_open_render`). Imports a
|
||||
/// scanout dma-buf (received over SCM_RIGHTS) and EGL-detiles it to linear pixels.
|
||||
@@ -187,11 +180,16 @@ impl RenderConverter {
|
||||
DRM_FORMAT_XBGR8888 | DRM_FORMAT_ABGR8888 => Pixfmt::RGBA,
|
||||
// Unset by an older convert -> libdrmtap's normalized BGRA.
|
||||
0 => Pixfmt::BGRA,
|
||||
// Every other invalid frame_info property in this function is a hard error
|
||||
// that lets the caller fall back to PipeWire; an output format this build
|
||||
// cannot interpret must be one too. Presenting it as BGRA would pass the
|
||||
// stride checks (a 64bpp output still satisfies stride >= w*4) and encode
|
||||
// garbage instead of degrading.
|
||||
other => {
|
||||
log::debug!(
|
||||
"drm: convert output fourcc {other:#010x} unrecognized; presenting as BGRA"
|
||||
);
|
||||
Pixfmt::BGRA
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("drmtap_convert_dmabuf produced an unsupported output fourcc {other:#010x}"),
|
||||
));
|
||||
}
|
||||
};
|
||||
// Borrow the context-owned pixels. The returned lifetime is tied to `&mut self`
|
||||
|
||||
Reference in New Issue
Block a user