diff options
Diffstat (limited to 'library/std/src')
| -rw-r--r-- | library/std/src/lib.rs | 6 | ||||
| -rw-r--r-- | library/std/src/net/tcp.rs | 6 | ||||
| -rw-r--r-- | library/std/src/os/unix/net/stream.rs | 23 | ||||
| -rw-r--r-- | library/std/src/prelude/v1.rs | 3 | ||||
| -rw-r--r-- | library/std/src/sys/net/connection/socket/unix.rs | 8 | ||||
| -rw-r--r-- | library/std/src/sys/random/uefi.rs | 169 | 
6 files changed, 189 insertions, 26 deletions
| diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 2bb7a63772d..13fb08a9210 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -281,7 +281,6 @@ #![feature(cfg_target_thread_local)] #![feature(cfi_encoding)] #![feature(char_max_len)] -#![feature(concat_idents)] #![feature(core_float_math)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] @@ -717,10 +716,9 @@ pub use core::primitive; pub use core::todo; // Re-export built-in macros defined through core. #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -#[allow(deprecated)] pub use core::{ - assert, assert_matches, cfg, column, compile_error, concat, concat_idents, const_format_args, - env, file, format_args, format_args_nl, include, include_bytes, include_str, line, log_syntax, + assert, assert_matches, cfg, column, compile_error, concat, const_format_args, env, file, + format_args, format_args_nl, include, include_bytes, include_str, line, log_syntax, module_path, option_env, stringify, trace_macros, }; // Re-export macros defined in core. diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 6a951426407..10685b49319 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -53,6 +53,12 @@ use crate::time::Duration; /// Ok(()) /// } // the stream is closed here /// ``` +/// +/// # Platform-specific Behavior +/// +/// On Unix, writes to the underlying socket in `SOCK_STREAM` mode are made with +/// `MSG_NOSIGNAL` flag. This suppresses the emission of the `SIGPIPE` signal when writing +/// to disconnected socket. In some cases, getting a `SIGPIPE` would trigger process termination. #[stable(feature = "rust1", since = "1.0.0")] pub struct TcpStream(net_imp::TcpStream); diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index 1bd3bab5e37..035768a6fab 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -1,3 +1,18 @@ +cfg_if::cfg_if! { + if #[cfg(any( + target_os = "linux", target_os = "android", + target_os = "hurd", + target_os = "dragonfly", target_os = "freebsd", + target_os = "openbsd", target_os = "netbsd", + target_os = "solaris", target_os = "illumos", + target_os = "haiku", target_os = "nto", + target_os = "cygwin"))] { + use libc::MSG_NOSIGNAL; + } else { + const MSG_NOSIGNAL: core::ffi::c_int = 0x0; + } +} + use super::{SocketAddr, sockaddr_un}; #[cfg(any(doc, target_os = "android", target_os = "linux"))] use super::{SocketAncillary, recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to}; @@ -41,6 +56,12 @@ use crate::time::Duration; /// Ok(()) /// } /// ``` +/// +/// # `SIGPIPE` +/// +/// Writes to the underlying socket in `SOCK_STREAM` mode are made with `MSG_NOSIGNAL` flag. +/// This suppresses the emission of the `SIGPIPE` signal when writing to disconnected socket. +/// In some cases getting a `SIGPIPE` would trigger process termination. #[stable(feature = "unix_socket", since = "1.10.0")] pub struct UnixStream(pub(super) Socket); @@ -633,7 +654,7 @@ impl io::Write for UnixStream { #[stable(feature = "unix_socket", since = "1.10.0")] impl<'a> io::Write for &'a UnixStream { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - self.0.write(buf) + self.0.send_with_flags(buf, MSG_NOSIGNAL) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index c15d8c40085..69f03353153 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -45,10 +45,9 @@ pub use crate::result::Result::{self, Err, Ok}; // Re-exported built-in macros #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -#[allow(deprecated)] #[doc(no_inline)] pub use core::prelude::v1::{ - assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args, + assert, cfg, column, compile_error, concat, env, file, format_args, format_args_nl, include, include_bytes, include_str, line, log_syntax, module_path, option_env, stringify, trace_macros, Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, }; diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs index b35d5d2aa84..b2a4961c3c5 100644 --- a/library/std/src/sys/net/connection/socket/unix.rs +++ b/library/std/src/sys/net/connection/socket/unix.rs @@ -281,6 +281,14 @@ impl Socket { self.0.duplicate().map(Socket) } + pub fn send_with_flags(&self, buf: &[u8], flags: c_int) -> io::Result<usize> { + let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t; + let ret = cvt(unsafe { + libc::send(self.as_raw_fd(), buf.as_ptr() as *const c_void, len, flags) + })?; + Ok(ret as usize) + } + fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> { let ret = cvt(unsafe { libc::recv( diff --git a/library/std/src/sys/random/uefi.rs b/library/std/src/sys/random/uefi.rs index a4d29e66f38..5f001f0f532 100644 --- a/library/std/src/sys/random/uefi.rs +++ b/library/std/src/sys/random/uefi.rs @@ -1,27 +1,158 @@ -use r_efi::protocols::rng; +pub fn fill_bytes(bytes: &mut [u8]) { + // Handle zero-byte request + if bytes.is_empty() { + return; + } + + // Try EFI_RNG_PROTOCOL + if rng_protocol::fill_bytes(bytes) { + return; + } -use crate::sys::pal::helpers; + // Fallback to rdrand if rng protocol missing. + // + // For real-world example, see [issue-13825](https://github.com/rust-lang/rust/issues/138252#issuecomment-2891270323) + #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] + if rdrand::fill_bytes(bytes) { + return; + } -pub fn fill_bytes(bytes: &mut [u8]) { - let handles = - helpers::locate_handles(rng::PROTOCOL_GUID).expect("failed to generate random data"); - for handle in handles { - if let Ok(protocol) = helpers::open_protocol::<rng::Protocol>(handle, rng::PROTOCOL_GUID) { - let r = unsafe { - ((*protocol.as_ptr()).get_rng)( - protocol.as_ptr(), - crate::ptr::null_mut(), - bytes.len(), - bytes.as_mut_ptr(), - ) + panic!("failed to generate random data"); +} + +mod rng_protocol { + use r_efi::protocols::rng; + + use crate::sys::pal::helpers; + + pub(crate) fn fill_bytes(bytes: &mut [u8]) -> bool { + if let Ok(handles) = helpers::locate_handles(rng::PROTOCOL_GUID) { + for handle in handles { + if let Ok(protocol) = + helpers::open_protocol::<rng::Protocol>(handle, rng::PROTOCOL_GUID) + { + let r = unsafe { + ((*protocol.as_ptr()).get_rng)( + protocol.as_ptr(), + crate::ptr::null_mut(), + bytes.len(), + bytes.as_mut_ptr(), + ) + }; + if r.is_error() { + continue; + } else { + return true; + } + } + } + } + + false + } +} + +/// Port from [getrandom](https://github.com/rust-random/getrandom/blob/master/src/backends/rdrand.rs) +#[cfg(any(target_arch = "x86_64", target_arch = "x86"))] +mod rdrand { + cfg_if::cfg_if! { + if #[cfg(target_arch = "x86_64")] { + use crate::arch::x86_64 as arch; + use arch::_rdrand64_step as rdrand_step; + type Word = u64; + } else if #[cfg(target_arch = "x86")] { + use crate::arch::x86 as arch; + use arch::_rdrand32_step as rdrand_step; + type Word = u32; + } + } + + static RDRAND_GOOD: crate::sync::LazyLock<bool> = crate::sync::LazyLock::new(is_rdrand_good); + + // Recommendation from "Intel® Digital Random Number Generator (DRNG) Software + // Implementation Guide" - Section 5.2.1 and "Intel® 64 and IA-32 Architectures + // Software Developer’s Manual" - Volume 1 - Section 7.3.17.1. + const RETRY_LIMIT: usize = 10; + + unsafe fn rdrand() -> Option<Word> { + for _ in 0..RETRY_LIMIT { + let mut val = 0; + if unsafe { rdrand_step(&mut val) } == 1 { + return Some(val); + } + } + None + } + + // Run a small self-test to make sure we aren't repeating values + // Adapted from Linux's test in arch/x86/kernel/cpu/rdrand.c + // Fails with probability < 2^(-90) on 32-bit systems + unsafe fn self_test() -> bool { + // On AMD, RDRAND returns 0xFF...FF on failure, count it as a collision. + let mut prev = Word::MAX; + let mut fails = 0; + for _ in 0..8 { + match unsafe { rdrand() } { + Some(val) if val == prev => fails += 1, + Some(val) => prev = val, + None => return false, }; - if r.is_error() { - continue; - } else { - return; + } + fails <= 2 + } + + fn is_rdrand_good() -> bool { + #[cfg(not(target_feature = "rdrand"))] + { + // SAFETY: All Rust x86 targets are new enough to have CPUID, and we + // check that leaf 1 is supported before using it. + let cpuid0 = unsafe { arch::__cpuid(0) }; + if cpuid0.eax < 1 { + return false; + } + let cpuid1 = unsafe { arch::__cpuid(1) }; + + let vendor_id = + [cpuid0.ebx.to_le_bytes(), cpuid0.edx.to_le_bytes(), cpuid0.ecx.to_le_bytes()]; + if vendor_id == [*b"Auth", *b"enti", *b"cAMD"] { + let mut family = (cpuid1.eax >> 8) & 0xF; + if family == 0xF { + family += (cpuid1.eax >> 20) & 0xFF; + } + // AMD CPUs families before 17h (Zen) sometimes fail to set CF when + // RDRAND fails after suspend. Don't use RDRAND on those families. + // See https://bugzilla.redhat.com/show_bug.cgi?id=1150286 + if family < 0x17 { + return false; + } + } + + const RDRAND_FLAG: u32 = 1 << 30; + if cpuid1.ecx & RDRAND_FLAG == 0 { + return false; } } + + // SAFETY: We have already checked that rdrand is available. + unsafe { self_test() } } - panic!("failed to generate random data"); + unsafe fn rdrand_exact(dest: &mut [u8]) -> Option<()> { + let mut chunks = dest.array_chunks_mut(); + for chunk in &mut chunks { + *chunk = unsafe { rdrand() }?.to_ne_bytes(); + } + + let tail = chunks.into_remainder(); + let n = tail.len(); + if n > 0 { + let src = unsafe { rdrand() }?.to_ne_bytes(); + tail.copy_from_slice(&src[..n]); + } + Some(()) + } + + pub(crate) fn fill_bytes(bytes: &mut [u8]) -> bool { + if *RDRAND_GOOD { unsafe { rdrand_exact(bytes).is_some() } } else { false } + } } | 
