From 383bd436d843dc54a5075dea312f4ee97c39d125 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Tue, 16 Dec 2025 21:19:53 +1100 Subject: [PATCH 1/2] fix(ipcd/uds/stream): handle zero-byte payload * sendmsg(2) on `SOCK_STREAM` with zero-byte payload is a no-op even if ancillary data is present. Note that this does not apply to `SOCK_DGRAM`. * Pass the `msg_flags` to `get_connected_pear` as non-blocking behaviour may be requested. Signed-off-by: Anhad Singh --- ipcd/src/uds/stream.rs | 74 ++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 43 deletions(-) diff --git a/ipcd/src/uds/stream.rs b/ipcd/src/uds/stream.rs index 8b084b12a1..337a2a3b7a 100644 --- a/ipcd/src/uds/stream.rs +++ b/ipcd/src/uds/stream.rs @@ -405,12 +405,14 @@ impl<'sock> UdsStreamScheme<'sock> { self.sockets.get(&id).ok_or(Error::new(EBADF)) } - fn get_connected_peer(&self, id: usize) -> Result<(usize, Rc>), Error> { + fn get_connected_peer( + &self, + id: usize, + flags: MsgFlags, + ) -> Result<(usize, Rc>), Error> { let mut socket = self.get_socket(id)?.borrow_mut(); - let remote_id = socket - .require_connected_connection(MsgFlags::default())? - .peer; + let remote_id = socket.require_connected_connection(flags)?.peer; let remote_rc = self.get_socket(remote_id).map_err(|e| { eprintln!("get_connected_peer(id: {}): Peer socket (id: {}) has vanished. Original error: {:?}", id, remote_id, e); Error::new(EPIPE) @@ -652,7 +654,7 @@ impl<'sock> UdsStreamScheme<'sock> { match option { libc::SO_DOMAIN => write_value(&AF_UNIX.to_le_bytes()), libc::SO_PEERCRED => { - let (_, remote_rc) = self.get_connected_peer(id)?; + let (_, remote_rc) = self.get_connected_peer(id, MsgFlags::default())?; let remote = remote_rc.borrow(); write_value(unsafe { slice::from_raw_parts( @@ -690,49 +692,35 @@ impl<'sock> UdsStreamScheme<'sock> { let (bytes_written, remote_id) = { let name = self.get_socket(id)?.borrow().path.clone(); - let (remote_id, remote_rc) = self.get_connected_peer(id)?; + let (pid, uid, gid) = get_uid_gid_from_pid(self.proc_creds_capability, ctx.pid)?; - let bytes_written = Self::sendmsg_inner( - self.proc_creds_capability, - &mut remote_rc.borrow_mut(), - name, - msg_flags, + let packet = DataPacket::from_stream( msg_stream, - ctx, + name, + Credential::new(pid as i32, uid as i32, gid as i32), )?; - (bytes_written, remote_id) + + let payload_len = packet.len(); + // sendmsg(2) on `SOCK_STREAM` with zero-byte payload is a no-op + // even if ancillary data is present. Note that this does not apply + // to `SOCK_DGRAM`. + if payload_len == 0 { + return Ok(0); + } + + let (remote_id, remote_rc) = self.get_connected_peer(id, msg_flags)?; + + let mut socket = remote_rc.borrow_mut(); + let connection = socket.require_connected_connection(msg_flags)?; + + connection.packets.push_back(packet); + (payload_len, remote_id) }; + self.post_fevent(remote_id, EVENT_READ)?; Ok(bytes_written) } - fn sendmsg_inner( - cap_fd: usize, - socket: &mut Socket, - name: Option, - msg_flags: MsgFlags, - msg_stream: &[u8], - ctx: &CallerCtx, - ) -> Result { - if msg_stream.is_empty() { - eprintln!("sendmsg_inner: msg_stream is empty."); - return Err(Error::new(EINVAL)); - } - - let connection = socket.require_connected_connection(msg_flags)?; - - let (pid, uid, gid) = get_uid_gid_from_pid(cap_fd, ctx.pid)?; - let packet = DataPacket::from_stream( - msg_stream, - name, - Credential::new(pid as i32, uid as i32, gid as i32), - )?; - let payload_len = packet.len(); - connection.packets.push_back(packet); - - Ok(payload_len) - } - fn handle_recvmsg( &mut self, id: usize, @@ -834,7 +822,7 @@ impl<'sock> UdsStreamScheme<'sock> { } fn handle_get_peer_name(&self, id: usize, payload: &mut [u8]) -> Result { - let (_, socket_rc) = self.get_connected_peer(id)?; + let (_, socket_rc) = self.get_connected_peer(id, MsgFlags::default())?; let socket_borrow = socket_rc.borrow(); match socket_borrow.path.as_ref() { Some(path_string) => Self::fpath_inner(path_string, payload), @@ -1246,7 +1234,7 @@ impl<'sock> SchemeSync for UdsStreamScheme<'sock> { _flags: u32, ctx: &CallerCtx, ) -> Result { - let (receiver_id, _) = self.get_connected_peer(id)?; + let (receiver_id, _) = self.get_connected_peer(id, MsgFlags::default())?; self.write_inner(receiver_id, buf, ctx) } @@ -1286,7 +1274,7 @@ impl<'sock> SchemeSync for UdsStreamScheme<'sock> { fn on_sendfd(&mut self, sendfd_request: &SendFdRequest) -> Result { let id = sendfd_request.id(); - let (receiver_id, _) = self.get_connected_peer(id)?; + let (receiver_id, _) = self.get_connected_peer(id, MsgFlags::default())?; self.sendfd_inner(receiver_id, sendfd_request) } From 9496f6f4865474a4242bd89f322fd4766f67c795 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Tue, 16 Dec 2025 22:14:40 +1100 Subject: [PATCH 2/2] fix(ipcd/uds/steam): perform checks before `get_uid_gid_from_pid` Fix https://gitlab.redox-os.org/redox-os/base/-/merge_requests/69#note_47265 Signed-off-by: Anhad Singh --- ipcd/src/uds/stream.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ipcd/src/uds/stream.rs b/ipcd/src/uds/stream.rs index 337a2a3b7a..27f3c762b4 100644 --- a/ipcd/src/uds/stream.rs +++ b/ipcd/src/uds/stream.rs @@ -692,6 +692,9 @@ impl<'sock> UdsStreamScheme<'sock> { let (bytes_written, remote_id) = { let name = self.get_socket(id)?.borrow().path.clone(); + let (remote_id, remote_rc) = self.get_connected_peer(id, msg_flags)?; + let mut socket = remote_rc.borrow_mut(); + let connection = socket.require_connected_connection(msg_flags)?; let (pid, uid, gid) = get_uid_gid_from_pid(self.proc_creds_capability, ctx.pid)?; let packet = DataPacket::from_stream( @@ -701,6 +704,7 @@ impl<'sock> UdsStreamScheme<'sock> { )?; let payload_len = packet.len(); + // sendmsg(2) on `SOCK_STREAM` with zero-byte payload is a no-op // even if ancillary data is present. Note that this does not apply // to `SOCK_DGRAM`. @@ -708,11 +712,6 @@ impl<'sock> UdsStreamScheme<'sock> { return Ok(0); } - let (remote_id, remote_rc) = self.get_connected_peer(id, msg_flags)?; - - let mut socket = remote_rc.borrow_mut(); - let connection = socket.require_connected_connection(msg_flags)?; - connection.packets.push_back(packet); (payload_len, remote_id) };