From e5b8416a21fa7507b023ccf4806433a65ebfd2e7 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 7 Nov 2025 04:07:18 -0300 Subject: [PATCH] muvm-guest: pwbridge: actually read fd indexes in the Transport msg The message payload contains indexes for the attached file descriptors. We must use them instead of relying on the order, which was never guaranteed, and *actually* differs in practice between architectures in compilers because current PipeWire code calls the fd-attaching function inside of function call arguments, which *don't* have a defined evaluation order in the C language standard. Signed-off-by: Val Packett --- crates/muvm/src/guest/bridge/pipewire.rs | 45 +++++++++++++++++++++--- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/crates/muvm/src/guest/bridge/pipewire.rs b/crates/muvm/src/guest/bridge/pipewire.rs index 25fbe4fb..343dd211 100644 --- a/crates/muvm/src/guest/bridge/pipewire.rs +++ b/crates/muvm/src/guest/bridge/pipewire.rs @@ -21,6 +21,7 @@ const CROSS_DOMAIN_CMD_READ: u8 = 6; const CROSS_DOMAIN_CMD_WRITE: u8 = 7; const SPA_TYPE_STRUCT: u32 = 14; +const SPA_TYPE_FD: u32 = 18; const PW_OPC_CORE_CREATE_OBJECT: u8 = 6; const PW_OPC_CORE_ADD_MEM: u8 = 6; @@ -53,6 +54,10 @@ fn read_u32(data: &[u8], at: usize) -> u32 { u32::from_ne_bytes(data[at..(at + 4)].try_into().unwrap()) } +fn read_u64(data: &[u8], at: usize) -> u64 { + u64::from_ne_bytes(data[at..(at + 8)].try_into().unwrap()) +} + #[derive(Debug)] struct CoreCreateObject<'a> { obj_type: &'a CStr, @@ -115,6 +120,27 @@ impl<'a> ClientUpdateProperties<'a> { } } +#[derive(Debug)] +struct ClientNodeTransport { + readfd: u64, + writefd: u64, + // .. don't care about the remaining ones +} + +impl ClientNodeTransport { + fn new(data: &[u8]) -> Self { + let ty = read_u32(data, 4); + assert_eq!(ty, SPA_TYPE_STRUCT); + let readfd_ty = read_u32(data, 12); + assert_eq!(readfd_ty, SPA_TYPE_FD); + let readfd = read_u64(data, 16); + let writefd_ty = read_u32(data, 28); + assert_eq!(writefd_ty, SPA_TYPE_FD); + let writefd = read_u64(data, 32); + ClientNodeTransport { readfd, writefd } + } +} + struct PipeWireHeader { id: u32, opcode: u8, @@ -267,10 +293,21 @@ impl ProtocolHandler for PipeWireProtocolHandler { let rsc = resources.pop_front().ok_or(Errno::EIO)?; fds.push(Self::create_guest_to_host_eventfd(this, hdr.id, rsc)?); } else if hdr.opcode == PW_OPC_CLIENT_NODE_TRANSPORT { - let rsc1 = resources.pop_front().ok_or(Errno::EIO)?; - fds.push(Self::create_host_to_guest_eventfd(this, hdr.id, rsc1)?); - let rsc2 = resources.pop_front().ok_or(Errno::EIO)?; - fds.push(Self::create_guest_to_host_eventfd(this, hdr.id, rsc2)?); + let msg = ClientNodeTransport::new(&data[PipeWireHeader::SIZE..]); + // We need to take elements out by index without shifting the indices. + let mut resources: Vec<_> = resources.drain(..hdr.num_fd).map(Some).collect(); + let writefd_rsc = resources.get_mut(msg.writefd as usize).ok_or(Errno::EIO)?; + fds.push(Self::create_guest_to_host_eventfd( + this, + hdr.id, + writefd_rsc.take().ok_or(Errno::EIO)?, + )?); + let readfd_rsc = resources.get_mut(msg.readfd as usize).ok_or(Errno::EIO)?; + fds.push(Self::create_host_to_guest_eventfd( + this, + hdr.id, + readfd_rsc.take().ok_or(Errno::EIO)?, + )?); } else { unimplemented!() }