Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 9a02f65

Browse files
committed
Update documentation for LLVM CFI support
This commit updates the documentation for the LLVM Control Flow Integrity (CFI) support in the Rust compiler.
1 parent 004aa15 commit 9a02f65

File tree

2 files changed

+126
-17
lines changed

2 files changed

+126
-17
lines changed

src/doc/unstable-book/src/compiler-flags/sanitizer.md

Lines changed: 101 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -196,18 +196,18 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
196196
197197
# ControlFlowIntegrity
198198
199-
The LLVM Control Flow Integrity (CFI) support in the Rust compiler initially
200-
provides forward-edge control flow protection for Rust-compiled code only by
201-
aggregating function pointers in groups identified by their return and parameter
202-
types.
203-
204-
Forward-edge control flow protection for C or C++ and Rust -compiled code "mixed
205-
binaries" (i.e., for when C or C++ and Rust -compiled code share the same
206-
virtual address space) will be provided in later work by defining and using
207-
compatible type identifiers (see Type metadata in the design document in the
208-
tracking issue [#89653](https://github.com/rust-lang/rust/issues/89653)).
209-
210-
LLVM CFI can be enabled with -Zsanitizer=cfi and requires LTO (i.e., -Clto).
199+
The LLVM Control Flow Integrity (CFI) support in the Rust compiler provides
200+
forward-edge control flow protection for both Rust-compiled code only and for C
201+
or C++ and Rust -compiled code mixed-language binaries, also known as “mixed
202+
binaries” (i.e., for when C or C++ and Rust -compiled code share the same
203+
virtual address space), by aggregating function pointers in groups identified by
204+
their return and parameter types.
205+
206+
LLVM CFI can be enabled with `-Zsanitizer=cfi` and requires LTO (i.e., `-Clto`).
207+
Cross-language LLVM CFI can be enabled with `-Zsanitizer=cfi`, and requires the
208+
`-Zsanitizer-cfi-normalize-integers` option to be used with Clang
209+
`-fsanitize-cfi-icall-normalize-integers` for normalizing integer types, and
210+
proper (i.e., non-rustc) LTO (i.e., `-Clinker-plugin-lto`).
211211
212212
See the [Clang ControlFlowIntegrity documentation][clang-cfi] for more details.
213213
@@ -343,7 +343,7 @@ $
343343
Fig. 5. Build and execution of the modified example with LLVM CFI disabled.
344344
345345
```shell
346-
$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release
346+
$ RUSTFLAGS="-Cembed-bitcode=yes -Clto -Zsanitizer=cfi" cargo run --release
347347
Compiling rust-cfi-2 v0.1.0 (/home/rcvalle/rust-cfi-2)
348348
Finished release [optimized] target(s) in 3.38s
349349
Running `target/release/rust-cfi-2`
@@ -392,7 +392,7 @@ Closures][rust-book-ch19-05] chapter of the [The Rust Programming
392392
Language][rust-book] book.
393393
394394
```shell
395-
cargo run --release
395+
$ cargo run --release
396396
Compiling rust-cfi-3 v0.1.0 (/home/rcvalle/rust-cfi-3)
397397
Finished release [optimized] target(s) in 0.74s
398398
Running `target/release/rust-cfi-3`
@@ -404,7 +404,7 @@ $
404404
Fig. 8. Build and execution of the modified example with LLVM CFI disabled.
405405
406406
```shell
407-
$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release
407+
$ RUSTFLAGS="-Cembed-bitcode=yes -Clto -Zsanitizer=cfi" cargo run --release
408408
Compiling rust-cfi-3 v0.1.0 (/home/rcvalle/rust-cfi-3)
409409
Finished release [optimized] target(s) in 3.40s
410410
Running `target/release/rust-cfi-3`
@@ -420,8 +420,92 @@ flow using an indirect branch/call to a function with different return and
420420
parameter types than the return type expected and arguments intended/passed in
421421
the call/branch site, the execution is also terminated (see Fig. 9).
422422
423-
[rust-book-ch19-05]: ../../book/ch19-05-advanced-functions-and-closures.html
424-
[rust-book]: ../../book/title-page.html
423+
```ignore (cannot-test-this-because-uses-custom-build)
424+
int
425+
do_twice(int (*fn)(int), int arg) {
426+
return fn(arg) + fn(arg);
427+
}
428+
```
429+
Fig. 10. Example C library.
430+
431+
```ignore (cannot-test-this-because-uses-custom-build)
432+
use std::mem;
433+
434+
#[link(name = "foo")]
435+
extern "C" {
436+
fn do_twice(f: unsafe extern "C" fn(i32) -> i32, arg: i32) -> i32;
437+
}
438+
439+
unsafe extern "C" fn add_one(x: i32) -> i32 {
440+
x + 1
441+
}
442+
443+
unsafe extern "C" fn add_two(x: i64) -> i64 {
444+
x + 2
445+
}
446+
447+
fn main() {
448+
let answer = unsafe { do_twice(add_one, 5) };
449+
450+
println!("The answer is: {}", answer);
451+
452+
println!("With CFI enabled, you should not see the next answer");
453+
let f: unsafe extern "C" fn(i32) -> i32 = unsafe {
454+
mem::transmute::<*const u8, unsafe extern "C" fn(i32) -> i32>(add_two as *const u8)
455+
};
456+
let next_answer = unsafe { do_twice(f, 5) };
457+
458+
println!("The next answer is: {}", next_answer);
459+
}
460+
```
461+
Fig. 11. Another modified example from the [Advanced Functions and
462+
Closures][rust-book-ch19-05] chapter of the [The Rust Programming
463+
Language][rust-book] book.
464+
465+
```shell
466+
$ make
467+
mkdir -p target/debug
468+
clang -I. -Isrc -Wall -flto -fvisibility=hidden -c -emit-llvm src/foo.c -o target/debug/libfoo.bc
469+
llvm-ar rcs target/debug/libfoo.a target/debug/libfoo.bc
470+
RUSTFLAGS="-L./target/debug -Clinker-plugin-lto -Clinker=clang -Clink-arg=-fuse-ld=lld" cargo build
471+
Compiling main v0.1.0 (/home/rcvalle/rust-cross-cfi-1)
472+
Finished dev [unoptimized + debuginfo] target(s) in 0.45s
473+
$ ./target/debug/main
474+
The answer is: 12
475+
With CFI enabled, you should not see the next answer
476+
The next answer is: 14
477+
$
478+
```
479+
Fig. 12. Build and execution of the modified example with LLVM CFI disabled.
480+
481+
```shell
482+
$ make
483+
mkdir -p target/debug
484+
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
485+
llvm-ar rcs target/debug/libfoo.a target/debug/libfoo.bc
486+
RUSTFLAGS="-L./target/debug -Clinker-plugin-lto -Clinker=clang -Clink-arg=-fuse-ld=lld -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers" cargo build
487+
Compiling main v0.1.0 (/home/rcvalle/rust-cross-cfi-1)
488+
Finished dev [unoptimized + debuginfo] target(s) in 0.45s
489+
$ ./target/debug/main
490+
The answer is: 12
491+
With CFI enabled, you should not see the next answer
492+
Illegal instruction
493+
$
494+
```
495+
Fig. 13. Build and execution of the modified example with LLVM CFI enabled.
496+
497+
When LLVM CFI is enabled, if there are any attempts to change/hijack control
498+
flow using an indirect branch/call to a function with different return and
499+
parameter types than the return type expected and arguments intended/passed in
500+
the call/branch site, even across the FFI boundary and for extern "C" function
501+
types indirectly called (i.e., callbacks/function pointers) across the FFI
502+
boundary, in C or C++ and Rust -compiled code mixed-language binaries, also
503+
known as “mixed binaries” (i.e., for when C or C++ and Rust -compiled code share
504+
the same virtual address space), the execution is also terminated (see Fig. 13).
505+
506+
507+
[rust-book-ch19-05]: https://doc.rust-lang.org/book/ch19-05-advanced-functions-and-closures.html
508+
[rust-book]: https://doc.rust-lang.org/book/title-page.html
425509
426510
# HWAddressSanitizer
427511
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# `cfi_encoding`
2+
3+
The tracking issue for this feature is: [#89653]
4+
5+
[#89653]: https://github.com/rust-lang/rust/issues/89653
6+
7+
------------------------
8+
9+
The `cfi_encoding` feature allows the user to define a CFI encoding for a type.
10+
It allows the user to use a different names for types that otherwise would be
11+
required to have the same name as used in externally defined C functions.
12+
13+
## Examples
14+
15+
```rust
16+
#![feature(cfi_encoding, extern_types)]
17+
18+
#[cfi_encoding = "3Foo"]
19+
pub struct Type1(i32);
20+
21+
extern {
22+
#[cfi_encoding = "3Bar"]
23+
type Type2;
24+
}
25+
```

0 commit comments

Comments
 (0)