Skip to content

Commit abece4f

Browse files
committed
Update documentation for LLVM CFI support
Updates documentation for LLVM CFI support with recommended information since the user can now rebuild and use both core and std with CFI enabled using the Cargo build-std feature.
1 parent 7b45674 commit abece4f

File tree

1 file changed

+85
-76
lines changed

1 file changed

+85
-76
lines changed

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

+85-76
Original file line numberDiff line numberDiff line change
@@ -197,22 +197,26 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
197197
198198
# ControlFlowIntegrity
199199
200-
The LLVM Control Flow Integrity (CFI) support in the Rust compiler provides
201-
forward-edge control flow protection for both Rust-compiled code only and for C
202-
or C++ and Rust -compiled code mixed-language binaries, also known as “mixed
203-
binaries” (i.e., for when C or C++ and Rust -compiled code share the same
204-
virtual address space), by aggregating function pointers in groups identified by
205-
their return and parameter types.
206-
207-
LLVM CFI can be enabled with `-Zsanitizer=cfi` and requires LTO (i.e., `-Clto`).
208-
Cross-language LLVM CFI can be enabled with `-Zsanitizer=cfi`, and requires the
209-
`-Zsanitizer-cfi-normalize-integers` option to be used with Clang
210-
`-fsanitize-cfi-icall-normalize-integers` for normalizing integer types, and
211-
proper (i.e., non-rustc) LTO (i.e., `-Clinker-plugin-lto`).
200+
The LLVM CFI support in the Rust compiler provides forward-edge control flow
201+
protection for both Rust-compiled code only and for C or C++ and Rust -compiled
202+
code mixed-language binaries, also known as “mixed binaries” (i.e., for when C
203+
or C++ and Rust -compiled code share the same virtual address space), by
204+
aggregating function pointers in groups identified by their return and parameter
205+
types.
206+
207+
LLVM CFI can be enabled with `-Zsanitizer=cfi` and requires LTO (i.e.,
208+
`-Clinker-plugin-lto` or `-Clto`). Cross-language LLVM CFI can be enabled with
209+
`-Zsanitizer=cfi`, and requires the `-Zsanitizer-cfi-normalize-integers` option
210+
to be used with Clang `-fsanitize-cfi-icall-experimental-normalize-integers`
211+
option for cross-language LLVM CFI support, and proper (i.e., non-rustc) LTO
212+
(i.e., `-Clinker-plugin-lto`).
213+
214+
It is recommended to rebuild the standard library with CFI enabled by using the
215+
Cargo build-std feature (i.e., `-Zbuild-std`) when enabling CFI.
212216
213217
See the [Clang ControlFlowIntegrity documentation][clang-cfi] for more details.
214218
215-
## Example
219+
## Example 1: Redirecting control flow using an indirect branch/call to an invalid destination
216220
217221
```rust,ignore (making doc tests pass cross-platform is hard)
218222
#![feature(naked_functions)]
@@ -239,7 +243,7 @@ pub extern "C" fn add_two(x: i32) {
239243
nop
240244
nop
241245
nop
242-
lea eax, [edi+2]
246+
lea eax, [rdi+2]
243247
ret
244248
",
245249
options(noreturn)
@@ -258,47 +262,50 @@ fn main() {
258262

259263
println!("With CFI enabled, you should not see the next answer");
260264
let f: fn(i32) -> i32 = unsafe {
261-
// Offsets 0-8 make it land in the landing pad/nop block, and offsets 1-8 are
262-
// invalid branch/call destinations (i.e., within the body of the function).
265+
// Offset 0 is a valid branch/call destination (i.e., the function entry
266+
// point), but offsets 1-8 within the landing pad/nop block are invalid
267+
// branch/call destinations (i.e., within the body of the function).
263268
mem::transmute::<*const u8, fn(i32) -> i32>((add_two as *const u8).offset(5))
264269
};
265270
let next_answer = do_twice(f, 5);
266271

267272
println!("The next answer is: {}", next_answer);
268273
}
269274
```
270-
Fig. 1. Modified example from the [Advanced Functions and
271-
Closures][rust-book-ch19-05] chapter of the [The Rust Programming
272-
Language][rust-book] book.
275+
Fig. 1. Redirecting control flow using an indirect branch/call to an invalid
276+
destination (i.e., within the body of the function).
273277
274278
```shell
275279
$ cargo run --release
276280
Compiling rust-cfi-1 v0.1.0 (/home/rcvalle/rust-cfi-1)
277-
Finished release [optimized] target(s) in 0.76s
281+
Finished release [optimized] target(s) in 0.42s
278282
Running `target/release/rust-cfi-1`
279283
The answer is: 12
280284
With CFI enabled, you should not see the next answer
281285
The next answer is: 14
282286
$
283287
```
284-
Fig. 2. Build and execution of the modified example with LLVM CFI disabled.
288+
Fig. 2. Build and execution of Fig. 1 with LLVM CFI disabled.
285289
286290
```shell
287-
$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release
291+
$ RUSTFLAGS="-Clinker-plugin-lto -Clinker=clang -Clink-arg=-fuse-ld=lld -Zsanitizer=cfi" cargo run -Zbuild-std -Zbuild-std-features --release --target x86_64-unknown-linux-gnu
292+
...
288293
Compiling rust-cfi-1 v0.1.0 (/home/rcvalle/rust-cfi-1)
289-
Finished release [optimized] target(s) in 3.39s
290-
Running `target/release/rust-cfi-1`
294+
Finished release [optimized] target(s) in 1m 08s
295+
Running `target/x86_64-unknown-linux-gnu/release/rust-cfi-1`
291296
The answer is: 12
292297
With CFI enabled, you should not see the next answer
293298
Illegal instruction
294299
$
295300
```
296-
Fig. 3. Build and execution of the modified example with LLVM CFI enabled.
301+
Fig. 3. Build and execution of Fig. 1 with LLVM CFI enabled.
297302
298303
When LLVM CFI is enabled, if there are any attempts to change/hijack control
299304
flow using an indirect branch/call to an invalid destination, the execution is
300305
terminated (see Fig. 3).
301306
307+
## Example 2: Redirecting control flow using an indirect branch/call to a function with a different number of parameters
308+
302309
```rust
303310
use std::mem;
304311
@@ -327,39 +334,42 @@ fn main() {
327334
println!("The next answer is: {}", next_answer);
328335
}
329336
```
330-
Fig. 4. Another modified example from the [Advanced Functions and
331-
Closures][rust-book-ch19-05] chapter of the [The Rust Programming
332-
Language][rust-book] book.
337+
Fig. 4. Redirecting control flow using an indirect branch/call to a function
338+
with a different number of parameters than arguments intended/passed in the
339+
call/branch site.
333340
334341
```shell
335342
$ cargo run --release
336343
Compiling rust-cfi-2 v0.1.0 (/home/rcvalle/rust-cfi-2)
337-
Finished release [optimized] target(s) in 0.76s
344+
Finished release [optimized] target(s) in 0.43s
338345
Running `target/release/rust-cfi-2`
339346
The answer is: 12
340347
With CFI enabled, you should not see the next answer
341348
The next answer is: 14
342349
$
343350
```
344-
Fig. 5. Build and execution of the modified example with LLVM CFI disabled.
351+
Fig. 5. Build and execution of Fig. 4 with LLVM CFI disabled.
345352
346353
```shell
347-
$ RUSTFLAGS="-Cembed-bitcode=yes -Clto -Zsanitizer=cfi" cargo run --release
354+
$ RUSTFLAGS="-Clinker-plugin-lto -Clinker=clang -Clink-arg=-fuse-ld=lld -Zsanitizer=cfi" cargo run -Zbuild-std -Zbuild-std-features --release --target x86_64-unknown-linux-gnu
355+
...
348356
Compiling rust-cfi-2 v0.1.0 (/home/rcvalle/rust-cfi-2)
349-
Finished release [optimized] target(s) in 3.38s
350-
Running `target/release/rust-cfi-2`
357+
Finished release [optimized] target(s) in 1m 08s
358+
Running `target/x86_64-unknown-linux-gnu/release/rust-cfi-2`
351359
The answer is: 12
352360
With CFI enabled, you should not see the next answer
353361
Illegal instruction
354362
$
355363
```
356-
Fig. 6. Build and execution of the modified example with LLVM CFI enabled.
364+
Fig. 6. Build and execution of Fig. 4 with LLVM CFI enabled.
357365
358366
When LLVM CFI is enabled, if there are any attempts to change/hijack control
359367
flow using an indirect branch/call to a function with different number of
360368
parameters than arguments intended/passed in the call/branch site, the
361369
execution is also terminated (see Fig. 6).
362370
371+
## Example 3: Redirecting control flow using an indirect branch/call to a function with different return and parameter types
372+
363373
```rust
364374
use std::mem;
365375
@@ -388,42 +398,46 @@ fn main() {
388398
println!("The next answer is: {}", next_answer);
389399
}
390400
```
391-
Fig. 7. Another modified example from the [Advanced Functions and
392-
Closures][rust-book-ch19-05] chapter of the [The Rust Programming
393-
Language][rust-book] book.
401+
Fig. 7. Redirecting control flow using an indirect branch/call to a function
402+
with different return and parameter types than the return type expected and
403+
arguments intended/passed at the call/branch site.
394404
395405
```shell
396406
$ cargo run --release
397407
Compiling rust-cfi-3 v0.1.0 (/home/rcvalle/rust-cfi-3)
398-
Finished release [optimized] target(s) in 0.74s
408+
Finished release [optimized] target(s) in 0.44s
399409
Running `target/release/rust-cfi-3`
400410
The answer is: 12
401411
With CFI enabled, you should not see the next answer
402412
The next answer is: 14
403413
$
404414
```
405-
Fig. 8. Build and execution of the modified example with LLVM CFI disabled.
415+
Fig. 8. Build and execution of Fig. 7 with LLVM CFI disabled.
406416
407417
```shell
408-
$ RUSTFLAGS="-Cembed-bitcode=yes -Clto -Zsanitizer=cfi" cargo run --release
418+
$ RUSTFLAGS="-Clinker-plugin-lto -Clinker=clang -Clink-arg=-fuse-ld=lld -Zsanitizer=cfi" cargo run -Zbuild-std -Zbuild-std-features --release --target x86_64-unknown-linux-gnu
419+
...
409420
Compiling rust-cfi-3 v0.1.0 (/home/rcvalle/rust-cfi-3)
410-
Finished release [optimized] target(s) in 3.40s
411-
Running `target/release/rust-cfi-3`
421+
Finished release [optimized] target(s) in 1m 07s
422+
Running `target/x86_64-unknown-linux-gnu/release/rust-cfi-3`
412423
The answer is: 12
413424
With CFI enabled, you should not see the next answer
414425
Illegal instruction
415426
$
416427
```
417-
Fig. 9. Build and execution of the modified example with LLVM CFI enabled.
428+
Fig. 9. Build and execution of Fig. 7 with LLVM CFI enabled.
418429
419430
When LLVM CFI is enabled, if there are any attempts to change/hijack control
420431
flow using an indirect branch/call to a function with different return and
421432
parameter types than the return type expected and arguments intended/passed in
422433
the call/branch site, the execution is also terminated (see Fig. 9).
423434
435+
## Example 4: Redirecting control flow using an indirect branch/call to a function with different return and parameter types across the FFI boundary
436+
424437
```ignore (cannot-test-this-because-uses-custom-build)
425438
int
426-
do_twice(int (*fn)(int), int arg) {
439+
do_twice(int (*fn)(int), int arg)
440+
{
427441
return fn(arg) + fn(arg);
428442
}
429443
```
@@ -459,54 +473,49 @@ fn main() {
459473
println!("The next answer is: {}", next_answer);
460474
}
461475
```
462-
Fig. 11. Another modified example from the [Advanced Functions and
463-
Closures][rust-book-ch19-05] chapter of the [The Rust Programming
464-
Language][rust-book] book.
476+
Fig. 11. Redirecting control flow using an indirect branch/call to a function
477+
with different return and parameter types than the return type expected and
478+
arguments intended/passed in the call/branch site, across the FFI boundary.
465479
466480
```shell
467481
$ make
468-
mkdir -p target/debug
469-
clang -I. -Isrc -Wall -flto -fvisibility=hidden -c -emit-llvm src/foo.c -o target/debug/libfoo.bc
470-
llvm-ar rcs target/debug/libfoo.a target/debug/libfoo.bc
471-
RUSTFLAGS="-L./target/debug -Clinker-plugin-lto -Clinker=clang -Clink-arg=-fuse-ld=lld" cargo build
472-
Compiling main v0.1.0 (/home/rcvalle/rust-cross-cfi-1)
473-
Finished dev [unoptimized + debuginfo] target(s) in 0.45s
474-
$ ./target/debug/main
482+
mkdir -p target/release
483+
clang -I. -Isrc -Wall -c src/foo.c -o target/release/libfoo.o
484+
llvm-ar rcs target/release/libfoo.a target/release/libfoo.o
485+
RUSTFLAGS="-L./target/release -Clinker=clang -Clink-arg=-fuse-ld=lld" cargo build --release
486+
Compiling rust-cfi-4 v0.1.0 (/home/rcvalle/rust-cfi-4)
487+
Finished release [optimized] target(s) in 0.49s
488+
$ ./target/release/rust-cfi-4
475489
The answer is: 12
476490
With CFI enabled, you should not see the next answer
477491
The next answer is: 14
478492
$
479493
```
480-
Fig. 12. Build and execution of the modified example with LLVM CFI disabled.
494+
Fig. 12. Build and execution of Figs. 10–11 with LLVM CFI disabled.
481495
482496
```shell
483497
$ make
484-
mkdir -p target/debug
485-
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
486-
llvm-ar rcs target/debug/libfoo.a target/debug/libfoo.bc
487-
RUSTFLAGS="-L./target/debug -Clinker-plugin-lto -Clinker=clang -Clink-arg=-fuse-ld=lld -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers" cargo build
488-
Compiling main v0.1.0 (/home/rcvalle/rust-cross-cfi-1)
489-
Finished dev [unoptimized + debuginfo] target(s) in 0.45s
490-
$ ./target/debug/main
498+
mkdir -p target/release
499+
clang -I. -Isrc -Wall -flto -fsanitize=cfi -fsanitize-cfi-icall-experimental-normalize-integers -fvisibility=hidden -c -emit-llvm src/foo.c -o target/release/libfoo.bc
500+
llvm-ar rcs target/release/libfoo.a target/release/libfoo.bc
501+
RUSTFLAGS="-L./target/release -Clinker-plugin-lto -Clinker=clang -Clink-arg=-fuse-ld=lld -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers" cargo build -Zbuild-std -Zbuild-std-features --release --target x86_64-unknown-linux-gnu
502+
...
503+
Compiling rust-cfi-4 v0.1.0 (/home/rcvalle/rust-cfi-4)
504+
Finished release [optimized] target(s) in 1m 06s
505+
$ ./target/x86_64-unknown-linux-gnu/release/rust-cfi-4
491506
The answer is: 12
492507
With CFI enabled, you should not see the next answer
493508
Illegal instruction
494509
$
495510
```
496-
Fig. 13. Build and execution of the modified example with LLVM CFI enabled.
497-
498-
When LLVM CFI is enabled, if there are any attempts to change/hijack control
499-
flow using an indirect branch/call to a function with different return and
500-
parameter types than the return type expected and arguments intended/passed in
501-
the call/branch site, even across the FFI boundary and for extern "C" function
502-
types indirectly called (i.e., callbacks/function pointers) across the FFI
503-
boundary, in C or C++ and Rust -compiled code mixed-language binaries, also
504-
known as “mixed binaries” (i.e., for when C or C++ and Rust -compiled code share
505-
the same virtual address space), the execution is also terminated (see Fig. 13).
506-
507-
508-
[rust-book-ch19-05]: https://doc.rust-lang.org/book/ch19-05-advanced-functions-and-closures.html
509-
[rust-book]: https://doc.rust-lang.org/book/title-page.html
511+
Fig. 13. Build and execution of FIgs. 10–11 with LLVM CFI enabled.
512+
513+
When LLVM CFI is enabled, if there are any attempts to redirect control flow
514+
using an indirect branch/call to a function with different return and parameter
515+
types than the return type expected and arguments intended/passed in the
516+
call/branch site, even across the FFI boundary and for extern "C" function types
517+
indirectly called (i.e., callbacks/function pointers) across the FFI boundary,
518+
the execution is also terminated (see Fig. 13).
510519
511520
# HWAddressSanitizer
512521

0 commit comments

Comments
 (0)