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

Commit f792f26

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 (see rust-lang#95548 and rust-lang#89653).
1 parent 5ad7a64 commit f792f26

File tree

1 file changed

+85
-29
lines changed

1 file changed

+85
-29
lines changed

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

Lines changed: 85 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,8 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
191191
192192
The LLVM Control Flow Integrity (CFI) support in the Rust compiler initially
193193
provides forward-edge control flow protection for Rust-compiled code only by
194-
aggregating function pointers in groups identified by their number of arguments.
194+
aggregating function pointers in groups identified by their return and parameter
195+
types.
195196
196197
Forward-edge control flow protection for C or C++ and Rust -compiled code "mixed
197198
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 {
243244
fn main() {
244245
let answer = do_twice(add_one, 5);
245246
246-
println!("The answer is: {answer}");
247+
println!("The answer is: {}", answer);
247248
248249
println!("With CFI enabled, you should not see the next answer");
249250
let f: fn(i32) -> i32 = unsafe {
@@ -253,30 +254,30 @@ fn main() {
253254
};
254255
let next_answer = do_twice(f, 5);
255256
256-
println!("The next answer is: {next_answer}");
257+
println!("The next answer is: {}", next_answer);
257258
}
258259
```
259260
Fig. 1. Modified example from the [Advanced Functions and
260261
Closures][rust-book-ch19-05] chapter of the [The Rust Programming
261262
Language][rust-book] book.
262263
263-
[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
264-
265264
```shell
266-
$ rustc rust_cfi.rs -o rust_cfi
267-
$ ./rust_cfi
265+
$ cargo run --release
266+
Compiling rust-cfi-1 v0.1.0 (/home/rcvalle/rust-cfi-1)
267+
Finished release [optimized] target(s) in 0.76s
268+
Running `target/release/rust-cfi-1`
268269
The answer is: 12
269270
With CFI enabled, you should not see the next answer
270271
The next answer is: 14
271272
$
272273
```
273274
Fig. 2. Build and execution of the modified example with LLVM CFI disabled.
274275
275-
[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
276-
277276
```shell
278-
$ rustc -Clto -Zsanitizer=cfi rust_cfi.rs -o rust_cfi
279-
$ ./rust_cfi
277+
$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release
278+
Compiling rust-cfi-1 v0.1.0 (/home/rcvalle/rust-cfi-1)
279+
Finished release [optimized] target(s) in 3.39s
280+
Running `target/release/rust-cfi-1`
280281
The answer is: 12
281282
With CFI enabled, you should not see the next answer
282283
Illegal instruction
@@ -306,37 +307,37 @@ fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
306307
fn main() {
307308
let answer = do_twice(add_one, 5);
308309
309-
println!("The answer is: {answer}");
310+
println!("The answer is: {}", answer);
310311
311312
println!("With CFI enabled, you should not see the next answer");
312313
let f: fn(i32) -> i32 =
313314
unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) };
314315
let next_answer = do_twice(f, 5);
315316
316-
println!("The next answer is: {next_answer}");
317+
println!("The next answer is: {}", next_answer);
317318
}
318319
```
319320
Fig. 4. Another modified example from the [Advanced Functions and
320321
Closures][rust-book-ch19-05] chapter of the [The Rust Programming
321322
Language][rust-book] book.
322323
323-
[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
324-
325324
```shell
326-
$ rustc rust_cfi.rs -o rust_cfi
327-
$ ./rust_cfi
325+
$ cargo run --release
326+
Compiling rust-cfi-2 v0.1.0 (/home/rcvalle/rust-cfi-2)
327+
Finished release [optimized] target(s) in 0.76s
328+
Running `target/release/rust-cfi-2`
328329
The answer is: 12
329330
With CFI enabled, you should not see the next answer
330331
The next answer is: 14
331332
$
332333
```
333334
Fig. 5. Build and execution of the modified example with LLVM CFI disabled.
334335
335-
[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
336-
337336
```shell
338-
$ rustc -Clto -Zsanitizer=cfi rust_cfi.rs -o rust_cfi
339-
$ ./rust_cfi
337+
$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release
338+
Compiling rust-cfi-2 v0.1.0 (/home/rcvalle/rust-cfi-2)
339+
Finished release [optimized] target(s) in 3.38s
340+
Running `target/release/rust-cfi-2`
340341
The answer is: 12
341342
With CFI enabled, you should not see the next answer
342343
Illegal instruction
@@ -346,14 +347,69 @@ Fig. 6. Build and execution of the modified example with LLVM CFI enabled.
346347
347348
When LLVM CFI is enabled, if there are any attempts to change/hijack control
348349
flow using an indirect branch/call to a function with different number of
349-
arguments than intended/passed in the call/branch site, the execution is also
350-
terminated (see Fig. 6).
351-
352-
Forward-edge control flow protection not only by aggregating function pointers
353-
in groups identified by their number of arguments, but also their argument
354-
types, will also be provided in later work by defining and using compatible type
355-
identifiers (see Type metadata in the design document in the tracking
356-
issue [#89653](https://github.com/rust-lang/rust/issues/89653)).
350+
parameters than arguments intended/passed in the call/branch site, the
351+
execution is also terminated (see Fig. 6).
352+
353+
```rust
354+
use std::mem;
355+
356+
fn add_one(x: i32) -> i32 {
357+
x + 1
358+
}
359+
360+
fn add_two(x: i64) -> i64 {
361+
x + 2
362+
}
363+
364+
fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
365+
f(arg) + f(arg)
366+
}
367+
368+
fn main() {
369+
let answer = do_twice(add_one, 5);
370+
371+
println!("The answer is: {}", answer);
372+
373+
println!("With CFI enabled, you should not see the next answer");
374+
let f: fn(i32) -> i32 =
375+
unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) };
376+
let next_answer = do_twice(f, 5);
377+
378+
println!("The next answer is: {}", next_answer);
379+
}
380+
```
381+
Fig. 7. Another modified example from the [Advanced Functions and
382+
Closures][rust-book-ch19-05] chapter of the [The Rust Programming
383+
Language][rust-book] book.
384+
385+
```shell
386+
cargo run --release
387+
Compiling rust-cfi-3 v0.1.0 (/home/rcvalle/rust-cfi-3)
388+
Finished release [optimized] target(s) in 0.74s
389+
Running `target/release/rust-cfi-3`
390+
The answer is: 12
391+
With CFI enabled, you should not see the next answer
392+
The next answer is: 14
393+
$
394+
```
395+
Fig. 8. Build and execution of the modified example with LLVM CFI disabled.
396+
397+
```shell
398+
$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release
399+
Compiling rust-cfi-3 v0.1.0 (/home/rcvalle/rust-cfi-3)
400+
Finished release [optimized] target(s) in 3.40s
401+
Running `target/release/rust-cfi-3`
402+
The answer is: 12
403+
With CFI enabled, you should not see the next answer
404+
Illegal instruction
405+
$
406+
```
407+
Fig. 9. Build and execution of the modified example with LLVM CFI enabled.
408+
409+
When LLVM CFI is enabled, if there are any attempts to change/hijack control
410+
flow using an indirect branch/call to a function with different return and
411+
parameter types than the return type expected and arguments intended/passed in
412+
the call/branch site, the execution is also terminated (see Fig. 9).
357413
358414
[rust-book-ch19-05]: https://doc.rust-lang.org/book/ch19-05-advanced-functions-and-closures.html
359415
[rust-book]: https://doc.rust-lang.org/book/title-page.html

0 commit comments

Comments
 (0)