@@ -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
212212See the [Clang ControlFlowIntegrity documentation][clang-cfi] for more details.
213213
343343Fig. 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
392392Language][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`
404404Fig. 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
420420parameter types than the return type expected and arguments intended/passed in
421421the 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
0 commit comments