about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDing Xiang Fei <dingxiangfei2009@protonmail.ch>2024-08-20 23:30:47 +0800
committerDing Xiang Fei <dingxiangfei2009@protonmail.ch>2024-08-29 21:48:48 +0800
commit9c29b33c7e6b02acc00965b0816c5cc8b4843e5e (patch)
tree16c3e177715e1f451631b9ff5707165b62442f3f
parent6cf068db566de080dfa7ed24a216ea3aed2b98ce (diff)
downloadrust-9c29b33c7e6b02acc00965b0816c5cc8b4843e5e.tar.gz
rust-9c29b33c7e6b02acc00965b0816c5cc8b4843e5e.zip
riscv64imac: allow shadow call stack sanitizer
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs2
-rw-r--r--src/doc/unstable-book/src/compiler-flags/sanitizer.md40
-rw-r--r--tests/codegen/sanitizer/riscv64-shadow-call-stack.rs17
4 files changed, 52 insertions, 9 deletions
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs
index bfd88bd042e..61226809e52 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs
@@ -28,7 +28,7 @@ pub fn target() -> Target {
             code_model: Some(CodeModel::Medium),
             emit_debug_gdb_scripts: false,
             eh_frame_header: false,
-            supported_sanitizers: SanitizerSet::KERNELADDRESS,
+            supported_sanitizers: SanitizerSet::KERNELADDRESS | SanitizerSet::SHADOWCALLSTACK,
             ..Default::default()
         },
     }
diff --git a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs
index fa3f1eff457..b7444df04cd 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs
@@ -27,7 +27,7 @@ pub fn target() -> Target {
             code_model: Some(CodeModel::Medium),
             emit_debug_gdb_scripts: false,
             eh_frame_header: false,
-            supported_sanitizers: SanitizerSet::KERNELADDRESS,
+            supported_sanitizers: SanitizerSet::KERNELADDRESS | SanitizerSet::SHADOWCALLSTACK,
             ..Default::default()
         },
     }
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index edc63a25ac1..24940f0d6fb 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -775,22 +775,47 @@ 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.
-
-ShadowCallStack requires a platform ABI which reserves `x18` as the instrumentation makes use of this register.
+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.
+AArch64 and RISC-V both have a platform register defined in their ABIs, which is `x18` and `x3`/`gp` respectively, that can optionally be reserved for this purpose.
+Software support from the operating system and runtime may be required depending on the target platform which is detailed in the remaining section.
+See the [Clang ShadowCallStack documentation][clang-scs] for more details.
 
 ShadowCallStack can be enabled with `-Zsanitizer=shadow-call-stack` option and is supported on the following targets:
 
-* `aarch64-linux-android`
+## AArch64 family
 
-A runtime must be provided by the application or operating system.
+ShadowCallStack requires the use of the ABI defined platform register, `x18`, which is required for code generation purposes.
+When `x18` is not reserved, and is instead used as a scratch register subsequently, enabling ShadowCallStack would lead to undefined behaviour
+due to corruption of return address or invalid memory access when the instrumentation restores return register to the link register `lr` from the
+already clobbered `x18` register.
+In other words, code that is calling into or called by functions instrumented with ShadowCallStack must reserve the `x18` register or preserve its value.
 
-See the [Clang ShadowCallStack documentation][clang-scs] for more details.
+### `aarch64-linux-android` and `aarch64-unknown-fuchsia`/`aarch64-fuchsia`
 
-* `aarch64-unknown-none`
+This target already reserves the `x18` register.
+A runtime must be provided by the application or operating system.
+If `bionic` is used on this target, the software support is provided.
+Otherwise, a runtime needs to prepare a memory region and points `x18` to the region which serves as the shadow call stack.
+
+### `aarch64-unknown-none`
 
 In addition to support from a runtime by the application or operating system, the `-Zfixed-x18` flag is also mandatory.
 
+## RISC-V 64 family
+
+ShadowCallStack uses either the `gp` register for software shadow stack, also known as `x3`, or the `ssp` register if [`Zicfiss`][riscv-zicfiss] extension is available.
+`gp`/`x3` is currently always reserved and available for ShadowCallStack instrumentation, and `ssp` in case of `Zicfiss` is only accessible through its dedicated shadow stack instructions.
+
+Support from the runtime and operating system is required when `gp`/`x3` is used for software shadow stack.
+A runtime must prepare a memory region and point `gp`/`x3` to the region before executing the code.
+
+The following targets support ShadowCallStack.
+
+* `riscv64imac-unknown-none-elf`
+* `riscv64gc-unknown-none-elf`
+* `riscv64gc-unknown-fuchsia`
+
 # ThreadSanitizer
 
 ThreadSanitizer is a data race detection tool. It is supported on the following
@@ -912,3 +937,4 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
 [clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html
 [linux-kasan]: https://www.kernel.org/doc/html/latest/dev-tools/kasan.html
 [llvm-memtag]: https://llvm.org/docs/MemTagSanitizer.html
+[riscv-zicfiss]: https://github.com/riscv/riscv-cfi/blob/3f8e450c481ac303bd5643444f7a89672f24476e/src/cfi_backward.adoc
diff --git a/tests/codegen/sanitizer/riscv64-shadow-call-stack.rs b/tests/codegen/sanitizer/riscv64-shadow-call-stack.rs
new file mode 100644
index 00000000000..5833b832ba4
--- /dev/null
+++ b/tests/codegen/sanitizer/riscv64-shadow-call-stack.rs
@@ -0,0 +1,17 @@
+//@ compile-flags: --target riscv64imac-unknown-none-elf -Zsanitizer=shadow-call-stack
+//@ needs-llvm-components: riscv
+
+#![allow(internal_features)]
+#![crate_type = "rlib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+// CHECK: ; Function Attrs:{{.*}}shadowcallstack
+// CHECK: define dso_local void @foo() unnamed_addr #0
+#[no_mangle]
+pub fn foo() {}
+
+// CHECK: attributes #0 = {{.*}}shadowcallstack{{.*}}