about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJubilee Young <workingjubilee@gmail.com>2024-07-16 20:19:16 -0700
committerJubilee Young <workingjubilee@gmail.com>2024-07-18 15:18:38 -0700
commit357ba1f8ec0326b9f285224fee8a97691485475f (patch)
tree78f5c95c71ac6cdf57d3f5b3ca27d004dbf3ec10
parent9e354daf7b3ef64740fe2ecf3c5aae9563b68189 (diff)
downloadrust-357ba1f8ec0326b9f285224fee8a97691485475f.tar.gz
rust-357ba1f8ec0326b9f285224fee8a97691485475f.zip
unix: lift init of sigaltstack before sigaction
This is technically "not necessary", as we will "just" segfault instead
if we e.g. arrive inside the handler fn with the null altstack. However,
it seems incorrect to go about this hoping that segfaulting is okay,
seeing as how our purpose here is to mitigate stack overflow problems.

Make sure NEED_ALTSTACK syncs with PAGE_SIZE when we do.

Co-authored-by: Jonas Böttiger <jonasboettiger@icloud.com>
-rw-r--r--library/std/src/sys/pal/unix/stack_overflow.rs26
1 files changed, 17 insertions, 9 deletions
diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs
index 0886624160c..160e58e16a5 100644
--- a/library/std/src/sys/pal/unix/stack_overflow.rs
+++ b/library/std/src/sys/pal/unix/stack_overflow.rs
@@ -123,28 +123,36 @@ mod imp {
     static MAIN_ALTSTACK: AtomicPtr<libc::c_void> = AtomicPtr::new(ptr::null_mut());
     static NEED_ALTSTACK: AtomicBool = AtomicBool::new(false);
 
+    /// # Safety
+    /// Must be called only once
+    #[forbid(unsafe_op_in_unsafe_fn)]
     pub unsafe fn init() {
         PAGE_SIZE.store(os::page_size(), Ordering::Relaxed);
 
         // Always write to GUARD to ensure the TLS variable is allocated.
-        let guard = install_main_guard().unwrap_or(0..0);
+        let guard = unsafe { install_main_guard().unwrap_or(0..0) };
         GUARD.set((guard.start, guard.end));
 
-        let mut action: sigaction = mem::zeroed();
+        // SAFETY: assuming all platforms define struct sigaction as "zero-initializable"
+        let mut action: sigaction = unsafe { mem::zeroed() };
         for &signal in &[SIGSEGV, SIGBUS] {
-            sigaction(signal, ptr::null_mut(), &mut action);
+            // SAFETY: just fetches the current signal handler into action
+            unsafe { sigaction(signal, ptr::null_mut(), &mut action) };
             // Configure our signal handler if one is not already set.
             if action.sa_sigaction == SIG_DFL {
+                if !NEED_ALTSTACK.load(Ordering::Relaxed) {
+                    // haven't set up our sigaltstack yet
+                    NEED_ALTSTACK.store(true, Ordering::Release);
+                    let handler = unsafe { make_handler(true) };
+                    MAIN_ALTSTACK.store(handler.data, Ordering::Relaxed);
+                    mem::forget(handler);
+                }
                 action.sa_flags = SA_SIGINFO | SA_ONSTACK;
                 action.sa_sigaction = signal_handler as sighandler_t;
-                sigaction(signal, &action, ptr::null_mut());
-                NEED_ALTSTACK.store(true, Ordering::Relaxed);
+                // SAFETY: only overriding signals if the default is set
+                unsafe { sigaction(signal, &action, ptr::null_mut()) };
             }
         }
-
-        let handler = make_handler(true);
-        MAIN_ALTSTACK.store(handler.data, Ordering::Relaxed);
-        mem::forget(handler);
     }
 
     pub unsafe fn cleanup() {