{"record":{"id":"b7174fafacd06340","repo":"rustdesk/rustdesk","slug":"drm-truncated-scm-rights-control-message-msg-ctr","errorCode":null,"errorMessage":"drm: truncated SCM_RIGHTS control message (MSG_CTRUNC)","messagePattern":"drm: truncated SCM_RIGHTS control message \\(MSG_CTRUNC\\)","errorType":"exception","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"src/ipc/drm.rs","lineNumber":1239,"sourceCode":"                let mut rawfd: libc::c_int = -1;\n                std::ptr::copy_nonoverlapping(\n                    data.add(i * std::mem::size_of::<libc::c_int>()),\n                    &mut rawfd as *mut libc::c_int as *mut u8,\n                    std::mem::size_of::<libc::c_int>(),\n                );\n                if rawfd >= 0 {\n                    let owned = OwnedFd::from_raw_fd(rawfd);\n                    if got.is_none() {\n                        got = Some(owned);\n                    } // else: surplus fd, dropped here -> closed\n                }\n            }\n        }\n        cmsg = libc::CMSG_NXTHDR(&msg, cmsg);\n    }\n    if msg.msg_flags & libc::MSG_CTRUNC != 0 {\n        drop(got);\n        return Err(std::io::Error::new(\n            std::io::ErrorKind::Other,\n            \"drm: truncated SCM_RIGHTS control message (MSG_CTRUNC)\",\n        ));\n    }\n    Ok((n as usize, got))\n}\n\nasync fn drm_write_all(\n    stream: &tokio::net::UnixStream,\n    mut buf: &[u8],\n    mut pass_fd: Option<RawFd>,\n) -> ResultType<()> {\n    // ONE deadline for the whole write: arming it per readiness wait lets a dripping peer re-arm it.\n    let deadline =\n        tokio::time::Instant::now() + std::time::Duration::from_millis(DRM_SEND_TIMEOUT_MS);\n    while !buf.is_empty() {\n        match tokio::time::timeout_at(deadline, stream.writable()).await {\n            Ok(r) => r?,","sourceCodeStart":1221,"sourceCodeEnd":1257,"githubUrl":"https://github.com/rustdesk/rustdesk/blob/91c9fccbb0f7bfe5f11644d5fbdec9b23fa10540/src/ipc/drm.rs#L1221-L1257","documentation":"drm_recvmsg reads from the _drm Unix socket expecting at most one fd via SCM_RIGHTS. If the kernel sets MSG_CTRUNC on the msghdr, the ancillary data did not fit in the control buffer and file descriptors were silently dropped; the function drops any received fd and returns this error because proceeding would leak or misattribute fds.","triggerScenarios":"Calling drm_read_full -> drm_recvmsg when the peer attaches ancillary data larger than DRM_CMSG_CAP (e.g. multiple fds via SCM_RIGHTS) so the kernel truncates the control message (msg_flags & MSG_CTRUNC != 0).","commonSituations":"Protocol version mismatch where a peer sends several fds per frame but this side only allocates CMSG_SPACE for one; a buffer-size regression shrinking DRM_CMSG_CAP; a malicious/mismatched peer flooding the socket with fd-passing messages.","solutions":["Ensure both ends use the same protocol: the sender must pass exactly one fd per frame (drm_sendmsg only supports one)","Enlarge the receive control buffer so it can hold the maximum expected ancillary data","Treat MSG_CTRUNC as fatal for the connection and reconnect, closing the received fds first (this code already drops them)","Verify no other component on the same socket (proxy, forwarder) is batching multiple SCM_RIGHTS messages together"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"match read_result {\n    Err(e) if e.to_string().contains(\"MSG_CTRUNC\") => {\n        log::warn!(\"truncated ancillary data; closing and reconnecting\");\n        reconnect_drm_channel();\n    }\n    other => other.map_err(|e| e.into()),\n}","preventionTips":["Keep the one-fd-per-frame protocol identical on both ends; never batch multiple fds","Recompute the control buffer size if the protocol ever carries more ancillary data","Drop received fds before closing on any truncation to avoid fd leaks","Integration-test fd passing between mismatched versions to catch buffer regressions"],"tags":["drm","unix-socket","scm-rights","file-descriptor"],"backgroundTag":"scm-rights-truncated","analyzedSha":"91c9fccbb0f7bfe5f11644d5fbdec9b23fa10540","analyzedAt":"2026-09-10T19:53:44.083Z","contentChangedAt":"2026-09-10T19:53:44.083Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}