Skip to content

Commit 56c6abc

Browse files
Adam Fordslp
authored andcommitted
muvm-guest: pwbridge: forward fds on send
Any outgoing Pipewire message with num_fd > 0 previously hit unimplemented!(), which in practice crashed the guest on the first ClientNode.PortBuffers that any pw-stream / pw-filter client emits. Handle fd-bearing send messages by draining the expected fds from request_fds, converting each via vgpu_id_from_prime into a CrossDomainResource + GemHandleFinalizer, and attaching them to the StreamSendResult. If request_fds is short of what the header claims, warn and return EIO instead of panicking. Only ClientNode.PortBuffers is treated as fd-bearing on the send path. Per the PipeWire 1.6 native protocol that is the only client->server method whose fds are dma-buf candidates — each fd corresponds to an SPA_Data in the submitted buffer pool. SecurityContext.Create is the only other send-side method that carries fds (a unix socket + an eventfd, neither of which are dma-bufs); it is not supported by this bridge. Any other fd-bearing send message — a future protocol addition, an unsupported interface, or a malformed client — warns and returns EIO rather than blindly handing the fd to DRM_IOCTL_PRIME_FD_TO_HANDLE, which would EINVAL on anything that isn't a dma-buf and yield an opaque failure. Replace the unreachable!() PipeWireResourceFinalizer stub with an enum that dispatches to GemHandleFinalizer, so the finalizers produced here actually run. Signed-off-by: Adam Ford <[email protected]>
1 parent c24672a commit 56c6abc

1 file changed

Lines changed: 42 additions & 9 deletions

File tree

crates/muvm/src/guest/bridge/pipewire.rs

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ use std::os::fd::{AsFd, AsRawFd, OwnedFd};
44
use std::{env, mem};
55

66
use anyhow::Result;
7-
use log::debug;
7+
use log::{debug, warn};
88
use nix::errno::Errno;
99
use nix::sys::epoll::EpollFlags;
1010
use nix::sys::eventfd::{EfdFlags, EventFd};
1111

1212
use crate::guest::bridge::common;
1313
use crate::guest::bridge::common::{
14-
Client, CrossDomainHeader, CrossDomainResource, MessageResourceFinalizer, ProtocolHandler,
15-
StreamRecvResult, StreamSendResult,
14+
Client, CrossDomainHeader, CrossDomainResource, GemHandleFinalizer, MessageResourceFinalizer,
15+
ProtocolHandler, StreamRecvResult, StreamSendResult,
1616
};
1717

1818
const CROSS_DOMAIN_CHANNEL_TYPE_PW: u32 = 0x10;
@@ -27,6 +27,7 @@ const PW_OPC_CORE_CREATE_OBJECT: u8 = 6;
2727
const PW_OPC_CORE_ADD_MEM: u8 = 6;
2828
const PW_OPC_CLIENT_UPDATE_PROPERTIES: u8 = 2;
2929
const PW_OPC_CLIENT_NODE_TRANSPORT: u8 = 0;
30+
const PW_OPC_CLIENT_NODE_PORT_BUFFERS: u8 = 5;
3031
const PW_OPC_CLIENT_NODE_SET_ACTIVATION: u8 = 10;
3132

3233
#[repr(C)]
@@ -165,13 +166,17 @@ impl PipeWireHeader {
165166
}
166167
}
167168

168-
struct PipeWireResourceFinalizer;
169+
enum PipeWireResourceFinalizer {
170+
Gem(GemHandleFinalizer),
171+
}
169172

170173
impl MessageResourceFinalizer for PipeWireResourceFinalizer {
171174
type Handler = PipeWireProtocolHandler;
172175

173-
fn finalize(self, _: &mut Client<Self::Handler>) -> Result<()> {
174-
unreachable!()
176+
fn finalize(self, client: &mut Client<Self::Handler>) -> Result<()> {
177+
match self {
178+
Self::Gem(fin) => fin.finalize(client),
179+
}
175180
}
176181
}
177182

@@ -349,13 +354,41 @@ impl ProtocolHandler for PipeWireProtocolHandler {
349354
.insert(msg.new_id, ClientNodeData::new());
350355
}
351356
}
357+
let mut resources = Vec::with_capacity(hdr.num_fd);
358+
let mut finalizers = Vec::with_capacity(hdr.num_fd);
352359
if hdr.num_fd != 0 {
353-
unimplemented!();
360+
let is_port_buffers = hdr.opcode == PW_OPC_CLIENT_NODE_PORT_BUFFERS
361+
&& this.protocol_handler.client_nodes.contains_key(&hdr.id);
362+
if !is_port_buffers {
363+
warn!(
364+
id = hdr.id,
365+
opcode = hdr.opcode,
366+
num_fd = hdr.num_fd;
367+
"Pipewire send: unexpected fd-bearing message",
368+
);
369+
return Err(Errno::EIO.into());
370+
}
371+
if this.request_fds.len() < hdr.num_fd {
372+
warn!(
373+
id = hdr.id,
374+
opcode = hdr.opcode,
375+
expected_fds = hdr.num_fd,
376+
queued_fds = this.request_fds.len();
377+
"Pipewire send: short fd queue",
378+
);
379+
return Err(Errno::EIO.into());
380+
}
381+
let fds: Vec<OwnedFd> = this.request_fds.drain(..hdr.num_fd).collect();
382+
for fd in fds {
383+
let (res, finalizer) = this.vgpu_id_from_prime(fd)?;
384+
resources.push(res);
385+
finalizers.push(PipeWireResourceFinalizer::Gem(finalizer));
386+
}
354387
};
355388
Ok(StreamSendResult::Processed {
356389
consumed_bytes: hdr.size,
357-
resources: Vec::new(),
358-
finalizers: Vec::new(),
390+
resources,
391+
finalizers,
359392
})
360393
}
361394

0 commit comments

Comments
 (0)