Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 5 pull requests #72948

Merged
merged 13 commits into from
Jun 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 31 additions & 7 deletions src/doc/unstable-book/src/compiler-flags/control-flow-guard.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,54 @@ The tracking issue for this feature is: [#68793](https://github.com/rust-lang/ru

------------------------

The `-Zcontrol_flow_guard=checks` compiler flag enables the Windows [Control Flow Guard][cfguard-docs] platform security feature. When enabled, the compiler outputs a list of valid indirect call targets, and inserts runtime checks on all indirect jump instructions to ensure that the destination is in the list of valid call targets.
The rustc flag `-Z control_flow_guard=checks` enables the Windows [Control Flow Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard) (CFG) platform security feature.

[cfguard-docs]: https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard
CFG is an exploit mitigation designed to enforce control-flow integrity for software running on supported Windows platforms (Windows 8.1 onwards). Specifically, CFG uses runtime checks to validate the target address of every indirect call/jump before allowing the call to complete.

For testing purposes, the `-Zcontrol_flow_guard=nochecks` compiler flag can be used to emit only the list of valid call targets, but not the runtime checks.
During compilation, the compiler identifies all indirect calls/jumps and adds CFG checks. It also emits metadata containing the relative addresses of all address-taken functions. At runtime, if the binary is run on a CFG-aware operating system, the loader uses the CFG metadata to generate a bitmap of the address space and marks those addresses that contain valid targets. On each indirect call, the inserted check determines whether the target address is marked in this bitmap. If the target is not valid, the process is terminated.

It is strongly recommended to also enable Control Flow Guard checks in all linked libraries, including the standard library.
In terms of interoperability:
- Code compiled with CFG enabled can be linked with libraries and object files that are not compiled with CFG. In this case, a CFG-aware linker can identify address-taken functions in the non-CFG libraries.
- Libraries compiled with CFG can linked into non-CFG programs. In this case, the CFG runtime checks in the libraries are not used (i.e. the mitigation is completely disabled).

To enable Control Flow Guard in the standard library, you can use the [cargo `-Zbuild-std` functionality][build-std] to recompile the standard library with the same configuration options as the main program.
CFG functionality is completely implemented in the LLVM backend and is supported for X86 (32-bit and 64-bit), ARM, and Aarch64 targets. The rustc flag adds the relevant LLVM module flags to enable the feature. This flag will be ignored for all non-Windows targets.


## When to use Control Flow Guard

The primary motivation for enabling CFG in Rust is to enhance security when linking against non-Rust code, especially C/C++ code. To achieve full CFG protection, all indirect calls (including any from Rust code) must have the appropriate CFG checks, as added by this flag. CFG can also improve security for Rust code that uses the `unsafe` keyword


## Overhead of Control Flow Guard

The CFG checks and metadata can potentially increase binary size and runtime overhead. The magnitude of any increase depends on the number and frequency of indirect calls. For example, enabling CFG for the Rust standard library increases binary size by approximately 0.14%. Enabling CFG in the SPEC CPU 2017 Integer Speed benchmark suite (compiled with Clang/LLVM) incurs approximate runtime overheads of between 0% and 8%, with a geometric mean of 2.9%.


## Testing Control Flow Guard

The rustc flag `-Z control_flow_guard=nochecks` instructs LLVM to emit the list of valid call targets without inserting runtime checks. This flag should only be used for testing purposes as it does not provide security enforcement.


## Control Flow Guard in libraries

It is strongly recommended to also enable CFG checks for all linked libraries, including the standard library.

To enable CFG in the standard library, use the [cargo `-Z build-std` functionality][build-std] to recompile the standard library with the same configuration options as the main program.

[build-std]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std

For example:
```cmd
rustup toolchain install --force nightly
rustup component add rust-src
SET RUSTFLAGS=-Zcontrol_flow_guard=checks
SET RUSTFLAGS=-Z control_flow_guard=checks
cargo +nightly build -Z build-std --target x86_64-pc-windows-msvc
```

```PowerShell
rustup toolchain install --force nightly
rustup component add rust-src
$Env:RUSTFLAGS = "-Zcontrol_flow_guard=checks"
$Env:RUSTFLAGS = "-Z control_flow_guard=checks"
cargo +nightly build -Z build-std --target x86_64-pc-windows-msvc
```

Expand Down
12 changes: 6 additions & 6 deletions src/librustc_error_codes/error_codes/E0641.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
Attempted to cast to/from a pointer with an unknown kind.

Erroneous code examples:
Erroneous code example:

```compile_fail,E0641
let b = 0 as *const _; // error
```

Must give information for type of pointer that is being cast from/to if the
type cannot be inferred.
Type information must be provided if a pointer type being cast from/into another
type which cannot be inferred:

```
// Creating a pointer from reference: type can be inferred
let a = &(String::from("Hello world!")) as *const _; // Ok
let a = &(String::from("Hello world!")) as *const _; // ok!

let b = 0 as *const i32; // Ok
let b = 0 as *const i32; // ok!

let c: *const i32 = 0 as *const _; // Ok
let c: *const i32 = 0 as *const _; // ok!
```
8 changes: 6 additions & 2 deletions src/librustc_metadata/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use rustc_middle::middle::cstore::{
CrateSource, ExternCrate, ExternCrateSource, MetadataLoaderDyn,
};
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{self, CrateType};
use rustc_session::config::{self, CrateType, ExternLocation};
use rustc_session::lint;
use rustc_session::output::validate_crate_name;
use rustc_session::search_paths::PathKind;
Expand Down Expand Up @@ -850,7 +850,11 @@ impl<'a> CrateLoader<'a> {
// Make a point span rather than covering the whole file
let span = krate.span.shrink_to_lo();
// Complain about anything left over
for (name, _) in self.sess.opts.externs.iter() {
for (name, entry) in self.sess.opts.externs.iter() {
if let ExternLocation::FoundInLibrarySearchDirectories = entry.location {
// Don't worry about pathless `--extern foo` sysroot references
continue;
}
if !self.used_extern_options.contains(&Symbol::intern(name)) {
self.sess.parse_sess.buffer_lint(
lint::builtin::UNUSED_CRATE_DEPENDENCIES,
Expand Down
Loading