about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRamon de C Valle <rcvalle@users.noreply.github.com>2022-12-12 22:42:53 -0800
committerRamon de C Valle <rcvalle@users.noreply.github.com>2023-05-03 22:41:31 +0000
commit9a02f65a226349affec0c8e1480b3b6468572e70 (patch)
tree6649903cdb55ac668c767249e0c9229cc61a3b85
parent004aa15b4718c34ca367f77c6d57c63d670c4f56 (diff)
downloadrust-9a02f65a226349affec0c8e1480b3b6468572e70.tar.gz
rust-9a02f65a226349affec0c8e1480b3b6468572e70.zip
Update documentation for LLVM CFI support
This commit updates the documentation for the LLVM Control Flow
Integrity (CFI) support in the Rust compiler.
-rw-r--r--src/doc/unstable-book/src/compiler-flags/sanitizer.md118
-rw-r--r--src/doc/unstable-book/src/language-features/cfi-encoding.md25
2 files changed, 126 insertions, 17 deletions
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index b55348b7889..aa776daf09d 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -196,18 +196,18 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
 
 # ControlFlowIntegrity
 
-The LLVM Control Flow Integrity (CFI) support in the Rust compiler initially
-provides forward-edge control flow protection for Rust-compiled code only by
-aggregating function pointers in groups identified by their return and parameter
-types.
-
-Forward-edge control flow protection for C or C++ and Rust -compiled code "mixed
-binaries" (i.e., for when C or C++ and Rust -compiled code share the same
-virtual address space) will be provided in later work by defining and using
-compatible type identifiers (see Type metadata in the design document in the
-tracking issue [#89653](https://github.com/rust-lang/rust/issues/89653)).
-
-LLVM CFI can be enabled with -Zsanitizer=cfi and requires LTO (i.e., -Clto).
+The LLVM Control Flow Integrity (CFI) support in the Rust compiler provides
+forward-edge control flow protection for both Rust-compiled code only and for C
+or C++ and Rust -compiled code mixed-language binaries, also known as “mixed
+binaries” (i.e., for when C or C++ and Rust -compiled code share the same
+virtual address space), by aggregating function pointers in groups identified by
+their return and parameter types.
+
+LLVM CFI can be enabled with `-Zsanitizer=cfi` and requires LTO (i.e., `-Clto`).
+Cross-language LLVM CFI can be enabled with `-Zsanitizer=cfi`, and requires the
+`-Zsanitizer-cfi-normalize-integers` option to be used with Clang
+`-fsanitize-cfi-icall-normalize-integers` for normalizing integer types, and
+proper (i.e., non-rustc) LTO (i.e., `-Clinker-plugin-lto`).
 
 See the [Clang ControlFlowIntegrity documentation][clang-cfi] for more details.
 
@@ -343,7 +343,7 @@ $
 Fig. 5. Build and execution of the modified example with LLVM CFI disabled.
 
 ```shell
-$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release
+$ RUSTFLAGS="-Cembed-bitcode=yes -Clto -Zsanitizer=cfi" cargo run --release
    Compiling rust-cfi-2 v0.1.0 (/home/rcvalle/rust-cfi-2)
     Finished release [optimized] target(s) in 3.38s
      Running `target/release/rust-cfi-2`
@@ -392,7 +392,7 @@ Closures][rust-book-ch19-05] chapter of the [The Rust Programming
 Language][rust-book] book.
 
 ```shell
- cargo run --release
+$ cargo run --release
    Compiling rust-cfi-3 v0.1.0 (/home/rcvalle/rust-cfi-3)
     Finished release [optimized] target(s) in 0.74s
      Running `target/release/rust-cfi-3`
@@ -404,7 +404,7 @@ $
 Fig. 8. Build and execution of the modified example with LLVM CFI disabled.
 
 ```shell
-$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release
+$ RUSTFLAGS="-Cembed-bitcode=yes -Clto -Zsanitizer=cfi" cargo run --release
    Compiling rust-cfi-3 v0.1.0 (/home/rcvalle/rust-cfi-3)
     Finished release [optimized] target(s) in 3.40s
      Running `target/release/rust-cfi-3`
@@ -420,8 +420,92 @@ flow using an indirect branch/call to a function with different return and
 parameter types than the return type expected and arguments intended/passed in
 the call/branch site, the execution is also terminated (see Fig. 9).
 
-[rust-book-ch19-05]: ../../book/ch19-05-advanced-functions-and-closures.html
-[rust-book]: ../../book/title-page.html
+```ignore (cannot-test-this-because-uses-custom-build)
+int
+do_twice(int (*fn)(int), int arg) {
+    return fn(arg) + fn(arg);
+}
+```
+Fig. 10. Example C library.
+
+```ignore (cannot-test-this-because-uses-custom-build)
+use std::mem;
+
+#[link(name = "foo")]
+extern "C" {
+    fn do_twice(f: unsafe extern "C" fn(i32) -> i32, arg: i32) -> i32;
+}
+
+unsafe extern "C" fn add_one(x: i32) -> i32 {
+    x + 1
+}
+
+unsafe extern "C" fn add_two(x: i64) -> i64 {
+    x + 2
+}
+
+fn main() {
+    let answer = unsafe { do_twice(add_one, 5) };
+
+    println!("The answer is: {}", answer);
+
+    println!("With CFI enabled, you should not see the next answer");
+    let f: unsafe extern "C" fn(i32) -> i32 = unsafe {
+        mem::transmute::<*const u8, unsafe extern "C" fn(i32) -> i32>(add_two as *const u8)
+    };
+    let next_answer = unsafe { do_twice(f, 5) };
+
+    println!("The next answer is: {}", next_answer);
+}
+```
+Fig. 11. Another modified example from the [Advanced Functions and
+Closures][rust-book-ch19-05] chapter of the [The Rust Programming
+Language][rust-book] book.
+
+```shell
+$ make
+mkdir -p target/debug
+clang -I. -Isrc -Wall -flto -fvisibility=hidden -c -emit-llvm src/foo.c -o target/debug/libfoo.bc
+llvm-ar rcs target/debug/libfoo.a target/debug/libfoo.bc
+RUSTFLAGS="-L./target/debug -Clinker-plugin-lto -Clinker=clang -Clink-arg=-fuse-ld=lld" cargo build
+   Compiling main v0.1.0 (/home/rcvalle/rust-cross-cfi-1)
+    Finished dev [unoptimized + debuginfo] target(s) in 0.45s
+$ ./target/debug/main
+The answer is: 12
+With CFI enabled, you should not see the next answer
+The next answer is: 14
+$
+```
+Fig. 12. Build and execution of the modified example with LLVM CFI disabled.
+
+```shell
+$ make
+mkdir -p target/debug
+clang -I. -Isrc -Wall -flto -fvisibility=hidden -fsanitize=cfi -fsanitize-cfi-icall-normalize-integers -c -emit-llvm src/foo.c -o target/debug/libfoo.bc
+llvm-ar rcs target/debug/libfoo.a target/debug/libfoo.bc
+RUSTFLAGS="-L./target/debug -Clinker-plugin-lto -Clinker=clang -Clink-arg=-fuse-ld=lld -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers" cargo build
+   Compiling main v0.1.0 (/home/rcvalle/rust-cross-cfi-1)
+    Finished dev [unoptimized + debuginfo] target(s) in 0.45s
+$ ./target/debug/main
+The answer is: 12
+With CFI enabled, you should not see the next answer
+Illegal instruction
+$
+```
+Fig. 13. Build and execution of the modified example with LLVM CFI enabled.
+
+When LLVM CFI is enabled, if there are any attempts to change/hijack control
+flow using an indirect branch/call to a function with different return and
+parameter types than the return type expected and arguments intended/passed in
+the call/branch site, even across the FFI boundary and for extern "C" function
+types indirectly called (i.e., callbacks/function pointers) across the FFI
+boundary, in C or C++ and Rust -compiled code mixed-language binaries, also
+known as “mixed binaries” (i.e., for when C or C++ and Rust -compiled code share
+the same virtual address space), the execution is also terminated (see Fig. 13).
+
+
+[rust-book-ch19-05]: https://doc.rust-lang.org/book/ch19-05-advanced-functions-and-closures.html
+[rust-book]: https://doc.rust-lang.org/book/title-page.html
 
 # HWAddressSanitizer
 
diff --git a/src/doc/unstable-book/src/language-features/cfi-encoding.md b/src/doc/unstable-book/src/language-features/cfi-encoding.md
new file mode 100644
index 00000000000..f2f74cc17b3
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/cfi-encoding.md
@@ -0,0 +1,25 @@
+# `cfi_encoding`
+
+The tracking issue for this feature is: [#89653]
+
+[#89653]: https://github.com/rust-lang/rust/issues/89653
+
+------------------------
+
+The `cfi_encoding` feature allows the user to define a CFI encoding for a type.
+It allows the user to use a different names for types that otherwise would be
+required to have the same name as used in externally defined C functions.
+
+## Examples
+
+```rust
+#![feature(cfi_encoding, extern_types)]
+
+#[cfi_encoding = "3Foo"]
+pub struct Type1(i32);
+
+extern {
+    #[cfi_encoding = "3Bar"]
+    type Type2;
+}
+```