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

Add VxWorks support #86

Merged
merged 14 commits into from
Oct 23, 2019
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ matrix:
- cargo xbuild --target=x86_64-unknown-uefi
- cargo xbuild --target=x86_64-unknown-hermit
- cargo xbuild --target=x86_64-unknown-l4re-uclibc
- cargo xbuild --target=x86_64-wrs-vxworks
# also test minimum dependency versions are usable
- cargo generate-lockfile -Z minimal-versions
- cargo build --target=x86_64-sun-solaris
Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ cfg-if = "0.1"
compiler_builtins = { version = "0.1", optional = true }
core = { version = "1.0", optional = true, package = "rustc-std-workspace-core" }

[target.'cfg(any(unix, target_os = "redox"))'.dependencies]
libc = { version = "0.2.62", default-features = false }
[target.'cfg(unix)'.dependencies]
josephlr marked this conversation as resolved.
Show resolved Hide resolved
libc = { version = "0.2.64", default-features = false }

[target.'cfg(target_os = "wasi")'.dependencies]
wasi = "0.5"
Expand Down
2 changes: 2 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ pub(crate) const BINDGEN_CRYPTO_UNDEF: Error = internal_error!(7);
pub(crate) const BINDGEN_GRV_UNDEF: Error = internal_error!(8);
pub(crate) const STDWEB_NO_RNG: Error = internal_error!(9);
pub(crate) const STDWEB_RNG_FAILED: Error = internal_error!(10);
pub(crate) const RAND_SECURE_FATAL: Error = internal_error!(11);

fn internal_desc(error: Error) -> Option<&'static str> {
match error {
Expand All @@ -152,6 +153,7 @@ fn internal_desc(error: Error) -> Option<&'static str> {
BINDGEN_GRV_UNDEF => Some("wasm-bindgen: crypto.getRandomValues is undefined"),
STDWEB_NO_RNG => Some("stdweb: no randomness source available"),
STDWEB_RNG_FAILED => Some("stdweb: failed to get randomness"),
RAND_SECURE_FATAL => Some("randSecure: fatal error"),
newpavlov marked this conversation as resolved.
Show resolved Hide resolved
_ => None,
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
//! | Haiku | `/dev/random` (identical to `/dev/urandom`)
//! | L4RE, SGX, UEFI | [RDRAND][18]
//! | Hermit | [RDRAND][18] as [`sys_rand`][22] is currently broken.
//! | VxWorks | `randABytes` after checking entropy pool initialization with `randSecure`
//! | Web browsers | [`Crypto.getRandomValues`][14] (see [Support for WebAssembly and ams.js][14])
//! | Node.js | [`crypto.randomBytes`][15] (see [Support for WebAssembly and ams.js][16])
//! | WASI | [`__wasi_random_get`][17]
Expand Down Expand Up @@ -160,6 +161,10 @@ pub use crate::error::Error;
#[allow(dead_code)]
mod util;

#[cfg(target_os = "vxworks")]
#[allow(dead_code)]
mod util_libc;

cfg_if! {
// Unlike the other Unix, Fuchsia and iOS don't use the libc to make any calls.
if #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "emscripten",
Expand Down Expand Up @@ -221,6 +226,8 @@ cfg_if! {
#[path = "solaris_illumos.rs"] mod imp;
} else if #[cfg(target_os = "wasi")] {
#[path = "wasi.rs"] mod imp;
} else if #[cfg(target_os = "vxworks")] {
#[path = "vxworks.rs"] mod imp;
} else if #[cfg(all(windows, getrandom_uwp))] {
#[path = "windows_uwp.rs"] mod imp;
} else if #[cfg(windows)] {
Expand Down
3 changes: 3 additions & 0 deletions src/util_libc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ cfg_if! {
}

pub fn last_os_error() -> Error {
#[cfg(not(target_os = "vxworks"))]
let errno = unsafe { *errno_location() };
#[cfg(target_os = "vxworks")]
let errno = unsafe { libc::errnoGet() };
if errno > 0 {
Error::from(NonZeroU32::new(errno as u32).unwrap())
} else {
Expand Down
35 changes: 35 additions & 0 deletions src/vxworks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation for VxWorks
use crate::error::{Error, RAND_SECURE_FATAL};
use crate::util_libc::last_os_error;
use core::sync::atomic::{AtomicBool, Ordering::Relaxed};

pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
static RNG_INIT: AtomicBool = AtomicBool::new(false);
while !RNG_INIT.load(Relaxed) {
Copy link
Member

Choose a reason for hiding this comment

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

We should use LazyBool here, something like:

fn rng_init() -> bool {
    loop {
        let ret = unsafe { libc::randSecure() }
        if ret != 0 {
            return ret > 0;
        }
        unsafe { libc::usleep(10) };
    }
}
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
    static RNG_INIT: LazyBool = LazyBool::new();
    if !RNG_INIT.unsync_init(rng_init) {
        return Err(RAND_SECURE_FATAL);
    }

    // Prevent overflow of i32
    ...

You could also use a lambda, if you think it would look better.

Copy link
Member Author

Choose a reason for hiding this comment

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

@BaoshanPang @n-salim
Is it possible for the system to recover after randSecure failure or can we assume that once it has failed it will always fail?

Choose a reason for hiding this comment

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

Yes, the system can recover after randSecure failure. This is the randSecure's function desciption:

  • randSecure - determine if state is secure
  • This routine determines if state is secure and returns status.
  • When the system boots, the SW random number lib contains no entropy. Once
  • enough entropy has been collected in order to make the random numbers
  • cryptographically secure, the state is considered to be secure.
  • It will make a system call to a kernel side handler.
  • RETURNS: 1 if the state is secure, 0 if the state is not secure, ERROR if
  • the random number generator module is not initialized.
  • ERRNOS: N/A

Copy link
Member

Choose a reason for hiding this comment

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

"ERROR if the random number generator module is not initialized."

If I'm understanding this right, the RNG module might not be initialized, but it could become initialized later?

If that's the case, the current code looks good to me.

let ret = unsafe { libc::randSecure() };
if ret < 0 {
return Err(RAND_SECURE_FATAL);
} else if ret > 0 {
RNG_INIT.store(true, Relaxed);
break;
}
unsafe { libc::usleep(10) };
}

// Prevent overflow of i32
for chunk in dest.chunks_mut(i32::max_value() as usize) {
let ret = unsafe { libc::randABytes(chunk.as_mut_ptr(), chunk.len() as i32) };
if ret != 0 {
return Err(last_os_error());
}
}
Ok(())
}