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

Support x86_64-unknown-uefi #30

Merged
merged 6 commits into from
Jun 17, 2019
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
5 changes: 5 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ matrix:
- rustup target add x86_64-unknown-netbsd
- rustup target add x86_64-unknown-redox
- rustup target add x86_64-fortanix-unknown-sgx
# For no_std targets
- rustup component add rust-src
- cargo install cargo-xbuild || true
script:
- cargo build --target=x86_64-sun-solaris --all-features
- cargo build --target=x86_64-unknown-cloudabi --all-features
Expand All @@ -114,6 +117,7 @@ matrix:
- cargo build --target=x86_64-unknown-netbsd --all-features
- cargo build --target=x86_64-unknown-redox --all-features
- cargo build --target=x86_64-fortanix-unknown-sgx --all-features
- cargo xbuild --target=x86_64-unknown-uefi
# also test minimum dependency versions are usable
- cargo generate-lockfile -Z minimal-versions
- cargo build --target=x86_64-sun-solaris --all-features
Expand All @@ -123,6 +127,7 @@ matrix:
- cargo build --target=x86_64-unknown-netbsd --all-features
- cargo build --target=x86_64-unknown-redox --all-features
- cargo build --target=x86_64-fortanix-unknown-sgx --all-features
- cargo xbuild --target=x86_64-unknown-uefi

# Trust cross-built/emulated targets. We must repeat all non-default values.
- rust: stable
Expand Down
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,8 @@ stdweb = { version = "0.4.9", optional = true }
[target.wasm32-wasi.dependencies]
libc = "0.2.54"

[target.'cfg(any(target_env = "sgx", target_os = "uefi"))'.dependencies]
lazy_static = { version = "1.3.0", features = ["spin_no_std"] }
newpavlov marked this conversation as resolved.
Show resolved Hide resolved

[features]
std = []
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ mod_use!(cfg(target_os = "redox"), use_file);
mod_use!(cfg(target_os = "solaris"), solaris_illumos);
mod_use!(cfg(windows), windows);
mod_use!(cfg(target_env = "sgx"), rdrand);
mod_use!(cfg(all(target_arch = "x86_64", target_os = "uefi")), rdrand);
mod_use!(cfg(target_os = "wasi"), wasi);

mod_use!(
Expand Down Expand Up @@ -231,6 +232,7 @@ mod_use!(
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
all(target_arch = "x86_64", target_os = "uefi"),
target_env = "sgx",
windows,
all(
Expand Down
52 changes: 40 additions & 12 deletions src/rdrand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,61 @@
//! Implementation for SGX using RDRAND instruction
use crate::Error;
use core::mem;
use core::arch::x86_64::_rdrand64_step;
use core::arch::x86_64::{__cpuid, _rdrand64_step};
use core::num::NonZeroU32;

#[cfg(not(target_feature = "rdrand"))]
compile_error!("enable rdrand target feature!");
use lazy_static::lazy_static;

// Recommendation from "Intel® Digital Random Number Generator (DRNG) Software
// Implementation Guide" - Section 5.2.1 and "Intel® 64 and IA-32 Architectures
// Software Developer’s Manual" - Volume 1 - Section 7.3.17.1.
const RETRY_LIMIT: usize = 10;
const WORD_SIZE: usize = mem::size_of::<u64>();

fn rdrand() -> Result<[u8; WORD_SIZE], Error> {
#[target_feature(enable = "rdrand")]
unsafe fn rdrand() -> Result<[u8; WORD_SIZE], Error> {
for _ in 0..RETRY_LIMIT {
unsafe {
// SAFETY: we've checked RDRAND support, and u64 can have any value.
let mut el = mem::uninitialized();
if _rdrand64_step(&mut el) == 1 {
return Ok(el.to_ne_bytes());
}
};
let mut el = mem::uninitialized();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit late to the party here, but I was curious why this uses mem::uninitialized() instead of mem::zeroed().

Zeroing seems relatively lightweight compared to RDRAND itself, would make RNG failures more obvious, and eliminates the potential risk of using attacker-controlled values which appear plausibly random at first glance as e.g. cryptographic keys.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, zeroed could be a better choice. Although in practice it does not matter, as both zeroed and uninitialized get optimized out.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tarcieri good catch! It also gets rid of a deprecation warning on the latest nightly.

if _rdrand64_step(&mut el) == 1 {
return Ok(el.to_ne_bytes());
}
}
error!("RDRAND failed, CPU issue likely");
Err(Error::UNKNOWN)
}

// "rdrand" target feature requires "+rdrnd" flag, see https://github.com/rust-lang/rust/issues/49653.
#[cfg(all(target_env = "sgx", not(target_feature = "rdrand")))]
compile_error!(
"SGX targets require 'rdrand' target feature. Enable by using -C target-feature=+rdrnd."
);

// TODO use is_x86_feature_detected!("rdrand") when that works in core. See:
// https://github.com/rust-lang-nursery/stdsimd/issues/464
fn is_rdrand_supported() -> bool {
if cfg!(target_feature = "rdrand") {
true
} else {
// SAFETY: All x86_64 CPUs support CPUID leaf 1
const FLAG: u32 = 1 << 30;
lazy_static! {
static ref HAS_RDRAND: bool = unsafe { __cpuid(1).ecx & FLAG != 0 };
}
*HAS_RDRAND
}
}

pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
if !is_rdrand_supported() {
return Err(Error::UNAVAILABLE);
}

// SAFETY: After this point, rdrand is supported, so calling the rdrand
// functions is not undefined behavior.
unsafe { rdrand_exact(dest) }
}

#[target_feature(enable = "rdrand")]
unsafe fn rdrand_exact(dest: &mut [u8]) -> Result<(), Error> {
// We use chunks_exact_mut instead of chunks_mut as it allows almost all
// calls to memcpy to be elided by the compiler.
let mut chunks = dest.chunks_exact_mut(WORD_SIZE);
Expand Down