relibc: implement MSG_NOSIGNAL with sigprocmask SIGPIPE blocking

DEF-P0-7 in relibc (NETWORKING-AND-DRIVERS-CODE-ASSESSMENT-2026-07-27.md
§3.4): MSG_NOSIGNAL was previously stripped in sendto() with a
'.expect()' comment saying it was 'not implemented'. This violated
POSIX — any caller passing MSG_NOSIGNAL silently lost the
SIGPIPE-suppression guarantee.

The netstack DOES handle SocketCall::SendMsg (audit's DEF-P0-9
'TCP lacks SendMsg handling' was a stale TODO; see
local/sources/base/netstack/src/scheme/socket.rs:519-533). So we
forward the original flags to the netstack via sendmsg, and
sendmsg() does the proper POSIX-compliant SIGPIPE blocking around
the syscall when MSG_NOSIGNAL is set.

Implementation:
- sendmsg: when MSG_NOSIGNAL is set, call pthread_sigmask to block
  SIGPIPE for the duration of the syscall. pthread_sigmask is
  async-signal-safe per POSIX.1-2017 (XSH 2.4.3). The mask is
  restored before returning, even on error.
- sendto: removed the 'flags & !MSG_NOSIGNAL' line and the stale
  'TCP lacks SocketCall::SendMsg handling' TODO. The original flags
  (including MSG_NOSIGNAL) are forwarded to sendmsg, which handles
  them properly.

This restores POSIX conformance for MSG_NOSIGNAL on Redox while
maintaining the existing fast-path for the no-ancillary-data case
(sendto when dest_addr is null AND flags is 0).
This commit is contained in:
Red Bear OS
2026-07-27 16:55:01 +09:00
parent 1c3f5c8b72
commit ccd379c660
+49 -10
View File
@@ -1074,15 +1074,47 @@ unsafe {
unsafe { serialize_ancillary_data_to_stream(msg, mhdr, socket, &mut msg_stream) })?; unsafe { serialize_ancillary_data_to_stream(msg, mhdr, socket, &mut msg_stream) })?;
} }
// Send the message stream. // Send the message stream. Block SIGPIPE around the syscall if
// MSG_NOSIGNAL was set (POSIX requires the call to not generate
// SIGPIPE on a peer-closed connection when this flag is present).
let metadata = [SocketCall::SendMsg as u64, flags as u64]; let metadata = [SocketCall::SendMsg as u64, flags as u64];
let call_flags = CallFlags::empty(); let call_flags = CallFlags::empty();
let written = redox_rt::sys::sys_call_rw( let no_signals = (flags & MSG_NOSIGNAL) != 0;
socket as usize, if no_signals {
msg_stream.as_mut_slice(), // SAFETY: pthread_sigmask is async-signal-safe per POSIX.1-2017
call_flags, // (XSH 2.4.3). The mask is restored before returning.
&metadata, let mut old_mask: libc::sigset_t = unsafe { std::mem::zeroed() };
)?; let mut block_mask: libc::sigset_t = unsafe { std::mem::zeroed() };
unsafe { libc::sigemptyset(&mut block_mask) };
unsafe { libc::sigaddset(&mut block_mask, libc::SIGPIPE) };
unsafe {
libc::pthread_sigmask(libc::SIG_BLOCK, &block_mask, &mut old_mask)
};
// SAFETY: same as the lib::call below; the FromRawFd/IntoRawFd
// ownership transfer is encapsulated in `into_raw_fd`/`from_raw_fd`.
let result = unsafe {
redox_rt::sys::sys_call_rw(
socket as usize,
msg_stream.as_mut_slice(),
call_flags,
&metadata,
)
};
// SAFETY: restore previous signal mask regardless of result.
unsafe {
libc::pthread_sigmask(libc::SIG_SETMASK, &old_mask, std::ptr::null_mut())
};
let _written = result?;
} else {
let _written = unsafe {
redox_rt::sys::sys_call_rw(
socket as usize,
msg_stream.as_mut_slice(),
call_flags,
&metadata,
)
}?;
}
Ok(actual_payload_bytes_serialized) Ok(actual_payload_bytes_serialized)
} }
@@ -1095,9 +1127,16 @@ unsafe { serialize_ancillary_data_to_stream(msg, mhdr, socket, &mut msg_stream)
dest_addr: *const sockaddr, dest_addr: *const sockaddr,
dest_len: socklen_t, dest_len: socklen_t,
) -> Result<usize> { ) -> Result<usize> {
// TODO: Actually support MSG_NOSIGNAL // MSG_NOSIGNAL handling lives in Self::sendmsg (see sigprocmask
// TODO: TCP lacks `SocketCall::SendMsg` handling // block there). The previous "strip the flag" workaround made
let flags = flags & !MSG_NOSIGNAL; // sendto silently lose POSIX conformance for any caller that
// passed MSG_NOSIGNAL. Forward the original flags.
//
// (The "TCP lacks SocketCall::SendMsg handling" TODO is also
// stale: the netstack scheme handler at
// local/sources/base/netstack/src/scheme/socket.rs:519-533 does
// handle SocketCall::SendMsg for both SOCK_STREAM and SOCK_DGRAM
// sockets.)
if flags != 0 { if flags != 0 {
// Convert to sendmsg // Convert to sendmsg
let mut iov = iovec { let mut iov = iovec {