about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/lib.rs6
-rw-r--r--library/std/src/net/tcp.rs6
-rw-r--r--library/std/src/os/unix/net/stream.rs23
-rw-r--r--library/std/src/prelude/v1.rs3
-rw-r--r--library/std/src/sys/net/connection/socket/unix.rs8
-rw-r--r--library/std/src/sys/random/uefi.rs169
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 }
+    }
 }