about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorWesley Wiser <wesleywiser@microsoft.com>2023-05-19 19:30:15 -0400
committerWesley Wiser <wesleywiser@microsoft.com>2023-05-26 15:18:54 -0400
commit019d75b44e3f4349495890453d2d154a8f7ba116 (patch)
tree799eb3cf43244f783683bd449231fac0b8924c52 /src
parentd22314e0f5fdb8ed1181dc1a9d1a85eb54b37c73 (diff)
downloadrust-019d75b44e3f4349495890453d2d154a8f7ba116.tar.gz
rust-019d75b44e3f4349495890453d2d154a8f7ba116.zip
Add SafeStack support to rustc
Adds support for LLVM [SafeStack] which provides backward edge control
flow protection by separating the stack into two parts: data which is
only accessed in provable safe ways is allocated on the normal stack
(the "safe stack") and all other data is placed in a separate allocation
(the "unsafe stack").

SafeStack support is enabled by passing `-Zsanitizer=safestack`.

[SafeStack]: https://clang.llvm.org/docs/SafeStack.html
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/llvm.rs2
-rw-r--r--src/doc/rustc/src/exploit-mitigations.md27
-rw-r--r--src/doc/unstable-book/src/compiler-flags/sanitizer.md14
-rw-r--r--src/tools/compiletest/src/header/needs.rs7
-rw-r--r--src/tools/compiletest/src/util.rs2
5 files changed, 43 insertions, 9 deletions
diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs
index 040a12f5d10..3fd0cca40e5 100644
--- a/src/bootstrap/llvm.rs
+++ b/src/bootstrap/llvm.rs
@@ -1017,7 +1017,7 @@ fn supported_sanitizers(
         "x86_64-unknown-illumos" => common_libs("illumos", "x86_64", &["asan"]),
         "x86_64-pc-solaris" => common_libs("solaris", "x86_64", &["asan"]),
         "x86_64-unknown-linux-gnu" => {
-            common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"])
+            common_libs("linux", "x86_64", &["asan", "lsan", "msan", "safestack", "tsan"])
         }
         "x86_64-unknown-linux-musl" => {
             common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"])
diff --git a/src/doc/rustc/src/exploit-mitigations.md b/src/doc/rustc/src/exploit-mitigations.md
index 00417b3a72f..172048704f4 100644
--- a/src/doc/rustc/src/exploit-mitigations.md
+++ b/src/doc/rustc/src/exploit-mitigations.md
@@ -66,7 +66,7 @@ equivalent.
 | Heap corruption protection | Yes | 1.32.0 (2019-01-17) (via operating system default or specified allocator) |
 | Stack smashing protection | Yes | Nightly |
 | Forward-edge control flow protection | Yes | Nightly |
-| Backward-edge control flow protection (e.g., shadow and safe stack) | No | |
+| Backward-edge control flow protection (e.g., shadow and safe stack) | Yes | Nightly |
 
 <small id="fn:1">1\. See
 <https://github.com/rust-lang/rust/tree/master/compiler/rustc_target/src/spec>
@@ -443,20 +443,21 @@ Newer processors provide hardware assistance for backward-edge control flow
 protection, such as ARM Pointer Authentication, and Intel Shadow Stack as
 part of Intel CET.
 
-The Rust compiler does not support shadow or safe stack. There is work
-currently ongoing to add support for the sanitizers[40], which may or may
-not include support for safe stack<sup id="fnref:7" role="doc-noteref"><a
-href="#fn:7" class="footnote">7</a></sup>.
+The Rust compiler supports shadow stack for aarch64 only
+<sup id="fnref:7" role="doc-noteref"><a href="#fn:7" class="footnote">7</a></sup>
+on nightly Rust compilers [43]-[44]. Safe stack is available on nightly
+Rust compilers [45]-[46].
 
 ```text
 $ readelf -s target/release/hello-rust | grep __safestack_init
+  1177: 00000000000057b0   444 FUNC    GLOBAL DEFAULT    9 __safestack_init
 ```
 Fig. 16. Checking if LLVM SafeStack is enabled for a given binary.
 
 The presence of the `__safestack_init` symbol indicates that LLVM SafeStack
-is enabled for a given binary. Conversely, the absence of the
+is enabled for a given binary (see Fig. 16). Conversely, the absence of the
 `__safestack_init` symbol indicates that LLVM SafeStack is not enabled for a
-given binary (see Fig. 16).
+given binary.
 
 <small id="fn:7">7\. The shadow stack implementation for the AMD64
 architecture and equivalent in LLVM was removed due to performance and
@@ -628,3 +629,15 @@ defaults (unrelated to `READ_IMPLIES_EXEC`).
 
 42. bbjornse. “add codegen option for using LLVM stack smash protection #84197.”
     GitHub. <https://github.com/rust-lang/rust/pull/84197>
+
+43. ivanloz. “Add support for LLVM ShadowCallStack. #98208.” GitHub.
+    <https://github.com/rust-lang/rust/pull/98208>.
+
+44. “ShadowCallStack.” The Rust Unstable Book.
+    [https://doc.rust-lang.org/unstable-book/compiler-flags/sanitizer.html#shadowcallstack](../unstable-book/compiler-flags/sanitizer.html#shadowcallstack).
+
+45. W. Wiser. “Add support for LLVM SafeStack #112000” GitHub.
+    <https://github.com/rust-lang/rust/pull/112000>
+
+46. “SafeStack.” The Rust Unstable Book.
+    [https://doc.rust-lang/org/unstable-book/compiler-flags/sanitizer.html#safestack](../unstable-book/compiler-flags/sanitizer.html#safestack).
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index aa776daf09d..49389b28c8f 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -21,7 +21,8 @@ This feature allows for use of one of following sanitizers:
 * [MemorySanitizer](#memorysanitizer) a detector of uninitialized reads.
 * [MemTagSanitizer](#memtagsanitizer) fast memory error detector based on
   Armv8.5-A Memory Tagging Extension.
-* [ShadowCallStack](#shadowcallstack) provides backward-edge control flow protection.
+* [SafeStack](#safestack) provides backward-edge control flow protection by separating the stack into safe and unsafe regions.
+* [ShadowCallStack](#shadowcallstack) provides backward-edge control flow protection (aarch64 only).
 * [ThreadSanitizer](#threadsanitizer) a fast data race detector.
 
 To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`,
@@ -712,6 +713,16 @@ To enable this target feature compile with `-C target-feature="+mte"`.
 
 See the [LLVM MemTagSanitizer documentation][llvm-memtag] for more details.
 
+# SafeStack
+
+SafeStack provides backward edge control flow protection by separating the stack into data which is only accessed safely (the safe stack) and all other data (the unsafe stack).
+
+SafeStack can be enabled with the `-Zsanitizer=safestack` option and is supported on the following targets:
+
+* `x86_64-unknown-linux-gnu`
+
+See the [Clang SafeStack documentation][clang-safestack] for more details.
+
 # ShadowCallStack
 
 ShadowCallStack provides backward edge control flow protection by storing a function's return address in a separately allocated 'shadow call stack' and loading the return address from that shadow call stack.
@@ -828,6 +839,7 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
 [clang-kcfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html#fsanitize-kcfi
 [clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html
 [clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html
+[clang-safestack]: https://clang.llvm.org/docs/SafeStack.html
 [clang-scs]: https://clang.llvm.org/docs/ShadowCallStack.html
 [clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html
 [linux-kasan]: https://www.kernel.org/doc/html/latest/dev-tools/kasan.html
diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs
index 4a57c61406c..18b3b913a68 100644
--- a/src/tools/compiletest/src/header/needs.rs
+++ b/src/tools/compiletest/src/header/needs.rs
@@ -71,6 +71,11 @@ pub(super) fn handle_needs(
             ignore_reason: "ignored on targets without shadow call stacks",
         },
         Need {
+            name: "needs-sanitizer-safestack",
+            condition: cache.sanitizer_safestack,
+            ignore_reason: "ignored on targets without SafeStack support",
+        },
+        Need {
             name: "needs-run-enabled",
             condition: config.run_enabled(),
             ignore_reason: "ignored when running the resulting test binaries is disabled",
@@ -184,6 +189,7 @@ pub(super) struct CachedNeedsConditions {
     sanitizer_hwaddress: bool,
     sanitizer_memtag: bool,
     sanitizer_shadow_call_stack: bool,
+    sanitizer_safestack: bool,
     xray: bool,
     rust_lld: bool,
     i686_dlltool: bool,
@@ -220,6 +226,7 @@ impl CachedNeedsConditions {
             sanitizer_hwaddress: util::HWASAN_SUPPORTED_TARGETS.contains(target),
             sanitizer_memtag: util::MEMTAG_SUPPORTED_TARGETS.contains(target),
             sanitizer_shadow_call_stack: util::SHADOWCALLSTACK_SUPPORTED_TARGETS.contains(target),
+            sanitizer_safestack: util::SAFESTACK_SUPPORTED_TARGETS.contains(target),
             xray: util::XRAY_SUPPORTED_TARGETS.contains(target),
 
             // For tests using the `needs-rust-lld` directive (e.g. for `-Zgcc-ld=lld`), we need to find
diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs
index 748240cc94b..17bed38b65e 100644
--- a/src/tools/compiletest/src/util.rs
+++ b/src/tools/compiletest/src/util.rs
@@ -104,6 +104,8 @@ pub const XRAY_SUPPORTED_TARGETS: &[&str] = &[
     "x86_64-unknown-openbsd",
 ];
 
+pub const SAFESTACK_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu"];
+
 pub fn make_new_path(path: &str) -> String {
     assert!(cfg!(windows));
     // Windows just uses PATH as the library search path, so we have to