Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
17 changes: 17 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#![deny(warnings)]

use std::env;

fn main() {
let target = env::var("TARGET").expect("TARGET was not set");
if target.contains("uwp") {
Comment thread
newpavlov marked this conversation as resolved.
Outdated
// for BCryptGenRandom
println!("cargo:rustc-link-lib=bcrypt");
} else if target.contains("windows") {
// for RtlGenRandom (aka SystemFunction036)
println!("cargo:rustc-link-lib=advapi32");
} else if target.contains("apple-ios") {
// for SecRandomCopyBytes and kSecRandomDefault
println!("cargo:rustc-link-lib=framework=Security");
Comment thread
newpavlov marked this conversation as resolved.
}
}
17 changes: 17 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,14 @@ cfg_if! {
macro_rules! error {
($($x:tt)*) => {};
}
#[allow(unused)]
macro_rules! warn {
($($x:tt)*) => {};
}
#[allow(unused)]
macro_rules! info {
($($x:tt)*) => {};
}
}
}

Expand Down Expand Up @@ -216,6 +224,15 @@ cfg_if! {
#[path = "solaris_illumos.rs"] mod imp;
} else if #[cfg(target_os = "wasi")] {
#[path = "wasi.rs"] mod imp;
} else if #[cfg(any(
// target_vendor was stabilized only in Rust 1.33
target = "i686-uwp-windows-gnu",
target = "x86_64-uwp-windows-gnu",
target = "aarch64-uwp-windows-msvc",
target = "x86_64-uwp-windows-msvc",
target = "i686-uwp-windows-msvc",
Copy link
Copy Markdown
Member Author

@newpavlov newpavlov Aug 2, 2019

Choose a reason for hiding this comment

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

Looks like this will not work, see rust-lang/rust#63217. :/ So our options are:

  • Do not support UWP
  • Bump MSRV to Rust 1.33
  • Add uwp or rust_1_33 feature.
  • Remove support for Windows XP and Vista.

Copy link
Copy Markdown
Member

@josephlr josephlr Aug 3, 2019

Choose a reason for hiding this comment

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

I think we should bump the MSRV to 1.33 (and release 0.1.8), Rust 1.38 is coming out in a few days (Aug 12 I think), so bumping to 1.33 then seems reasonable.

Users still on 1.32 can still use 0.1.7 without any problems.

Copy link
Copy Markdown
Member Author

@newpavlov newpavlov Aug 3, 2019

Choose a reason for hiding this comment

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

Personally until something like rust-lang/rfcs#2495 lands I prefer a conservative position stating that MSRV bump should be considered a breaking change.

I think we also could move UWP check to the Windows branch, so MSRV bump will affect only Windows users, but I would prefer to drop support for Windows XP and Vista instead, but I guess it would require writing an RFC if we want getrandom to be used as part of std.

@dhardy
What dou you think?

Copy link
Copy Markdown
Member

@josephlr josephlr Aug 5, 2019

Choose a reason for hiding this comment

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

After looking at #75 and rust-lang/rfcs#2495, I think you're right. Incrementing the minimum supported version should be considered a breaking change. However, we can support UWP without bumping the MSRV, adding a feature, or dropping support for XP/Vista. We can just check in the build script.

libc does this to maintain a comically low MSRV (Rust 1.13). They just check for the version in build.rs and then set cfgs appropriately.

So we would do the following:

// build.rs
    ...
    if target.contains("uwp") {
        println!("cargo:rustc-cfg=getrandom_uwp");
        // for BCryptGenRandom
        println!("cargo:rustc-link-lib=bcrypt");
    ...
// src/lib.rs
    ...
    } else if #[cfg(all(windows, getrandom_uwp))] {
        #[path = "windows_uwp.rs"] mod imp;
    } else if #[cfg(windows)] {
        #[path = "windows.rs"] mod imp;
    }
    ...

This prevents exposing any of the details in getrandom's public interface.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good workaround!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Using a build.rs file seems appropriate in this case.

))] {
#[path = "windows_uwp.rs"] mod imp;
} else if #[cfg(windows)] {
#[path = "windows.rs"] mod imp;
} else if #[cfg(all(target_arch = "x86_64", any(
Expand Down
55 changes: 55 additions & 0 deletions src/windows_uwp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// 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 Windows UWP targets. After deprecation of Windows XP
//! and Vista, this can superseed the `RtlGenRandom`-based implementation.
use crate::Error;
use core::{ffi::c_void, num::NonZeroU32, ptr, u32};
Comment thread
newpavlov marked this conversation as resolved.
Outdated

const BCRYPT_USE_SYSTEM_PREFERRED_RNG: u32 = 0x00000002;

extern "system" {
fn BCryptGenRandom(
hAlgorithm: *mut c_void,
pBuffer: *mut u8,
cbBuffer: u32,
dwFlags: u32,
) -> u32;
}

pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
// Prevent overflow of u32
for chunk in dest.chunks_mut(u32::max_value() as usize) {
let ret = unsafe {
BCryptGenRandom(
ptr::null_mut(),
chunk.as_mut_ptr(),
chunk.len() as u32,
BCRYPT_USE_SYSTEM_PREFERRED_RNG,
)
};
// NTSTATUS codes use two highest bits for severity codes
match ret >> 30 {
0b01 => info!("BCryptGenRandom: information code 0x{:08X}", ret),
0b10 => warn!("BCryptGenRandom: warning code 0x{:08X}", ret),
0b11 => {
error!("BCryptGenRandom: failed with 0x{:08X}", ret);
// We zeroize the highest bit, so the error code will reside
// inside the range designated for OS codes.
let code = ret & (u32::MAX >> 1);
Comment thread
newpavlov marked this conversation as resolved.
Outdated
// SAFETY: the second highest bit is always equal to one,
// so it's impossible to get zero. Unfortunately compiler
// is not smart enough to figure out it yet.
let code = unsafe { NonZeroU32::new_unchecked(code) };
return Err(Error::from(code));
}
_ => (),
}
}
Ok(())
}