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:
@@ -1074,15 +1074,47 @@ unsafe {
|
||||
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 call_flags = CallFlags::empty();
|
||||
let written = redox_rt::sys::sys_call_rw(
|
||||
socket as usize,
|
||||
msg_stream.as_mut_slice(),
|
||||
call_flags,
|
||||
&metadata,
|
||||
)?;
|
||||
let no_signals = (flags & MSG_NOSIGNAL) != 0;
|
||||
if no_signals {
|
||||
// SAFETY: pthread_sigmask is async-signal-safe per POSIX.1-2017
|
||||
// (XSH 2.4.3). The mask is restored before returning.
|
||||
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)
|
||||
}
|
||||
@@ -1095,9 +1127,16 @@ unsafe { serialize_ancillary_data_to_stream(msg, mhdr, socket, &mut msg_stream)
|
||||
dest_addr: *const sockaddr,
|
||||
dest_len: socklen_t,
|
||||
) -> Result<usize> {
|
||||
// TODO: Actually support MSG_NOSIGNAL
|
||||
// TODO: TCP lacks `SocketCall::SendMsg` handling
|
||||
let flags = flags & !MSG_NOSIGNAL;
|
||||
// MSG_NOSIGNAL handling lives in Self::sendmsg (see sigprocmask
|
||||
// block there). The previous "strip the flag" workaround made
|
||||
// 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 {
|
||||
// Convert to sendmsg
|
||||
let mut iov = iovec {
|
||||
|
||||
Reference in New Issue
Block a user