@@ -196,18 +196,18 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
196
196
197
197
# ControlFlowIntegrity
198
198
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 ` ).
211
211
212
212
See the [Clang ControlFlowIntegrity documentation][clang-cfi] for more details.
213
213
343
343
Fig. 5. Build and execution of the modified example with LLVM CFI disabled.
344
344
345
345
` ` ` shell
346
- $ RUSTFLAGS=" -Zsanitizer=cfi - Cembed-bitcode=yes -Clto" cargo run --release
346
+ $ RUSTFLAGS=" -Cembed-bitcode=yes -Clto -Zsanitizer=cfi " cargo run --release
347
347
Compiling rust-cfi-2 v0.1.0 (/home/rcvalle/rust-cfi-2)
348
348
Finished release [optimized] target(s) in 3.38s
349
349
Running ` target/release/rust-cfi-2`
@@ -392,7 +392,7 @@ Closures][rust-book-ch19-05] chapter of the [The Rust Programming
392
392
Language][rust-book] book.
393
393
394
394
` ` ` shell
395
- cargo run --release
395
+ $ cargo run --release
396
396
Compiling rust-cfi-3 v0.1.0 (/home/rcvalle/rust-cfi-3)
397
397
Finished release [optimized] target(s) in 0.74s
398
398
Running ` target/release/rust-cfi-3`
404
404
Fig. 8. Build and execution of the modified example with LLVM CFI disabled.
405
405
406
406
` ` ` shell
407
- $ RUSTFLAGS=" -Zsanitizer=cfi - Cembed-bitcode=yes -Clto" cargo run --release
407
+ $ RUSTFLAGS=" -Cembed-bitcode=yes -Clto -Zsanitizer=cfi " cargo run --release
408
408
Compiling rust-cfi-3 v0.1.0 (/home/rcvalle/rust-cfi-3)
409
409
Finished release [optimized] target(s) in 3.40s
410
410
Running ` target/release/rust-cfi-3`
@@ -420,8 +420,92 @@ flow using an indirect branch/call to a function with different return and
420
420
parameter types than the return type expected and arguments intended/passed in
421
421
the call/branch site, the execution is also terminated (see Fig. 9).
422
422
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
425
509
426
510
# HWAddressSanitizer
427
511
0 commit comments