about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2020-03-19 06:57:37 +0100
committerGitHub <noreply@github.com>2020-03-19 06:57:37 +0100
commit4c3a5a5da636f16ea0ada0a55960230760e4031c (patch)
treea764530065496a8b81abb2f36018dab8619b42e5 /src/libstd
parent73c3a496cc8ce261e87abbd998b36ab16dab4f4b (diff)
parent28eeea630faf1e7514da96c5eedd67e330fe8571 (diff)
Rollup merge of #69969 - iximeow:sigstack-guard-page, r=cuviper
unix: Set a guard page at the end of signal stacks

This mitigates possible issues when signal stacks overflow, which could
manifest as segfaults or in unlucky circumstances possible clobbering of
other memory values as stack overflows tend to enable.

I went ahead and made a PR for this because it's a pretty small change, though if I should open an issue/RFC for this and discuss there first I'll happily do so. I've also added some example programs that demonstrate the uncomfortably clobber-happy behavior we currently have, and the segfaults that could/should result instead, [here](https://github.com/iximeow/jubilant-train).
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/sys/unix/stack_overflow.rs23
1 files changed, 18 insertions, 5 deletions
diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs
index 9e8be550755..2626ca37cf8 100644
--- a/src/libstd/sys/unix/stack_overflow.rs
+++ b/src/libstd/sys/unix/stack_overflow.rs
@@ -45,8 +45,9 @@ mod imp {
     use libc::{mmap, munmap};
     use libc::{sigaction, sighandler_t, SA_ONSTACK, SA_SIGINFO, SIGBUS, SIG_DFL};
     use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE};
-    use libc::{MAP_ANON, MAP_PRIVATE, PROT_READ, PROT_WRITE, SIGSEGV};
+    use libc::{MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE, SIGSEGV};
 
+    use crate::sys::unix::os::page_size;
     use crate::sys_common::thread_info;
 
     #[cfg(any(target_os = "linux", target_os = "android"))]
@@ -137,12 +138,22 @@ mod imp {
     }
 
     unsafe fn get_stackp() -> *mut libc::c_void {
-        let stackp =
-            mmap(ptr::null_mut(), SIGSTKSZ, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+        let stackp = mmap(
+            ptr::null_mut(),
+            SIGSTKSZ + page_size(),
+            PROT_READ | PROT_WRITE,
+            MAP_PRIVATE | MAP_ANON,
+            -1,
+            0,
+        );
         if stackp == MAP_FAILED {
             panic!("failed to allocate an alternative stack");
         }
-        stackp
+        let guard_result = libc::mprotect(stackp, page_size(), PROT_NONE);
+        if guard_result != 0 {
+            panic!("failed to set up alternative stack guard page");
+        }
+        stackp.add(page_size())
     }
 
     #[cfg(any(
@@ -190,7 +201,9 @@ mod imp {
                 ss_size: SIGSTKSZ,
             };
             sigaltstack(&stack, ptr::null_mut());
-            munmap(handler._data, SIGSTKSZ);
+            // We know from `get_stackp` that the alternate stack we installed is part of a mapping
+            // that started one page earlier, so walk back a page and unmap from there.
+            munmap(handler._data.sub(page_size()), SIGSTKSZ + page_size());
         }
     }
 }