1
Fork 0

Update documentation for LLVM CFI support

This commit updates the documentation for the LLVM Control Flow
Integrity (CFI) support in the Rust compiler (see #95548 and #89653).
This commit is contained in:
Ramon de C Valle 2022-03-31 22:51:37 -07:00
parent 5ad7a646a5
commit f792f26a38

View file

@ -191,7 +191,8 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
The LLVM Control Flow Integrity (CFI) support in the Rust compiler initially The LLVM Control Flow Integrity (CFI) support in the Rust compiler initially
provides forward-edge control flow protection for Rust-compiled code only by provides forward-edge control flow protection for Rust-compiled code only by
aggregating function pointers in groups identified by their number of arguments. 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 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 binaries" (i.e., for when C or C++ and Rust -compiled code share the same
@ -243,7 +244,7 @@ fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
fn main() { fn main() {
let answer = do_twice(add_one, 5); let answer = do_twice(add_one, 5);
println!("The answer is: {answer}"); println!("The answer is: {}", answer);
println!("With CFI enabled, you should not see the next answer"); println!("With CFI enabled, you should not see the next answer");
let f: fn(i32) -> i32 = unsafe { let f: fn(i32) -> i32 = unsafe {
@ -253,18 +254,18 @@ fn main() {
}; };
let next_answer = do_twice(f, 5); let next_answer = do_twice(f, 5);
println!("The next answer is: {next_answer}"); println!("The next answer is: {}", next_answer);
} }
``` ```
Fig. 1.Modified example from the [Advanced Functions and Fig. 1.Modified example from the [Advanced Functions and
Closures][rust-book-ch19-05] chapter of the [The Rust Programming Closures][rust-book-ch19-05] chapter of the [The Rust Programming
Language][rust-book] book. Language][rust-book] book.
[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
```shell ```shell
$ rustc rust_cfi.rs -o rust_cfi $ cargo run --release
$ ./rust_cfi Compiling rust-cfi-1 v0.1.0 (/home/rcvalle/rust-cfi-1)
Finished release [optimized] target(s) in 0.76s
Running `target/release/rust-cfi-1`
The answer is: 12 The answer is: 12
With CFI enabled, you should not see the next answer With CFI enabled, you should not see the next answer
The next answer is: 14 The next answer is: 14
@ -272,11 +273,11 @@ $
``` ```
Fig. 2.Build and execution of the modified example with LLVM CFI disabled. Fig. 2.Build and execution of the modified example with LLVM CFI disabled.
[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
```shell ```shell
$ rustc -Clto -Zsanitizer=cfi rust_cfi.rs -o rust_cfi $ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release
$ ./rust_cfi Compiling rust-cfi-1 v0.1.0 (/home/rcvalle/rust-cfi-1)
Finished release [optimized] target(s) in 3.39s
Running `target/release/rust-cfi-1`
The answer is: 12 The answer is: 12
With CFI enabled, you should not see the next answer With CFI enabled, you should not see the next answer
Illegal instruction Illegal instruction
@ -306,25 +307,25 @@ fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
fn main() { fn main() {
let answer = do_twice(add_one, 5); let answer = do_twice(add_one, 5);
println!("The answer is: {answer}"); println!("The answer is: {}", answer);
println!("With CFI enabled, you should not see the next answer"); println!("With CFI enabled, you should not see the next answer");
let f: fn(i32) -> i32 = let f: fn(i32) -> i32 =
unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) }; unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) };
let next_answer = do_twice(f, 5); let next_answer = do_twice(f, 5);
println!("The next answer is: {next_answer}"); println!("The next answer is: {}", next_answer);
} }
``` ```
Fig. 4.Another modified example from the [Advanced Functions and Fig. 4.Another modified example from the [Advanced Functions and
Closures][rust-book-ch19-05] chapter of the [The Rust Programming Closures][rust-book-ch19-05] chapter of the [The Rust Programming
Language][rust-book] book. Language][rust-book] book.
[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
```shell ```shell
$ rustc rust_cfi.rs -o rust_cfi $ cargo run --release
$ ./rust_cfi Compiling rust-cfi-2 v0.1.0 (/home/rcvalle/rust-cfi-2)
Finished release [optimized] target(s) in 0.76s
Running `target/release/rust-cfi-2`
The answer is: 12 The answer is: 12
With CFI enabled, you should not see the next answer With CFI enabled, you should not see the next answer
The next answer is: 14 The next answer is: 14
@ -332,11 +333,11 @@ $
``` ```
Fig. 5.Build and execution of the modified example with LLVM CFI disabled. Fig. 5.Build and execution of the modified example with LLVM CFI disabled.
[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
```shell ```shell
$ rustc -Clto -Zsanitizer=cfi rust_cfi.rs -o rust_cfi $ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release
$ ./rust_cfi 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`
The answer is: 12 The answer is: 12
With CFI enabled, you should not see the next answer With CFI enabled, you should not see the next answer
Illegal instruction Illegal instruction
@ -346,14 +347,69 @@ Fig. 6.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 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 number of flow using an indirect branch/call to a function with different number of
arguments than intended/passed in the call/branch site, the execution is also parameters than arguments intended/passed in the call/branch site, the
terminated (see Fig. 6). execution is also terminated (see Fig. 6).
Forward-edge control flow protection not only by aggregating function pointers ```rust
in groups identified by their number of arguments, but also their argument use std::mem;
types, will also be provided in later work by defining and using compatible type
identifiers (see Type metadata in the design document in the tracking fn add_one(x: i32) -> i32 {
issue [#89653](https://github.com/rust-lang/rust/issues/89653)). x + 1
}
fn add_two(x: i64) -> i64 {
x + 2
}
fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
f(arg) + f(arg)
}
fn main() {
let answer = do_twice(add_one, 5);
println!("The answer is: {}", answer);
println!("With CFI enabled, you should not see the next answer");
let f: fn(i32) -> i32 =
unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) };
let next_answer = do_twice(f, 5);
println!("The next answer is: {}", next_answer);
}
```
Fig. 7.Another modified example from the [Advanced Functions and
Closures][rust-book-ch19-05] chapter of the [The Rust Programming
Language][rust-book] book.
```shell
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`
The answer is: 12
With CFI enabled, you should not see the next answer
The next answer is: 14
$
```
Fig. 8.Build and execution of the modified example with LLVM CFI disabled.
```shell
$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" 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`
The answer is: 12
With CFI enabled, you should not see the next answer
Illegal instruction
$
```
Fig. 9.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, the execution is also terminated (see Fig. 9).
[rust-book-ch19-05]: https://doc.rust-lang.org/book/ch19-05-advanced-functions-and-closures.html [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 [rust-book]: https://doc.rust-lang.org/book/title-page.html