Auto merge of #3162 - RalfJung:random, r=RalfJung

share getentropy shim across various unixes
This commit is contained in:
bors 2023-11-13 18:31:26 +00:00
commit 28322532ac
8 changed files with 65 additions and 49 deletions

View file

@ -27,6 +27,8 @@ fn is_dyn_sym(name: &str, target_os: &str) -> bool {
// `signal` is set up as a weak symbol in `init_extern_statics` (on Android) so we might as
// well allow it in `dlsym`.
"signal" => true,
// needed at least on macOS to avoid file-based fallback in getrandom
"getentropy" => true,
// Give specific OSes a chance to allow their symbols.
_ =>
match target_os {
@ -525,6 +527,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let result = this.getpid()?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"getentropy" => {
// This function is non-standard but exists with the same signature and behavior on
// Linux, macOS, and FreeBSD.
if !matches!(&*this.tcx.sess.target.os, "linux" | "macos" | "freebsd") {
throw_unsup_format!(
"`getentropy` is not supported on {}",
this.tcx.sess.target.os
);
}
let [buf, bufsize] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let buf = this.read_pointer(buf)?;
let bufsize = this.read_target_usize(bufsize)?;
// getentropy sets errno to EIO when the buffer size exceeds 256 bytes.
// FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=getentropy&sektion=3&format=html
// Linux: https://man7.org/linux/man-pages/man3/getentropy.3.html
// macOS: https://keith.github.io/xcode-man-pages/getentropy.2.html
if bufsize > 256 {
let err = this.eval_libc("EIO");
this.set_last_error(err)?;
this.write_scalar(Scalar::from_i32(-1), dest)?
} else {
this.gen_random(buf, bufsize)?;
this.write_scalar(Scalar::from_i32(0), dest)?;
}
}
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
// These shims are enabled only when the caller is in the standard library.
@ -594,7 +624,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_int(super::UID, dest)?;
}
"getpwuid_r" if this.frame_in_std() => {
"getpwuid_r"
if this.frame_in_std() => {
let [uid, pwd, buf, buflen, result] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
this.check_no_isolation("`getpwuid_r`")?;

View file

@ -47,23 +47,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.read_scalar(len)?,
)?;
}
"getentropy" => {
let [buf, bufsize] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let buf = this.read_pointer(buf)?;
let bufsize = this.read_target_usize(bufsize)?;
// getentropy sets errno to EIO when the buffer size exceeds 256 bytes.
// https://man.freebsd.org/cgi/man.cgi?query=getentropy&sektion=3&format=html
if bufsize > 256 {
let err = this.eval_libc("EIO");
this.set_last_error(err)?;
this.write_scalar(Scalar::from_i32(-1), dest)?
} else {
this.gen_random(buf, bufsize)?;
this.write_scalar(Scalar::from_i32(0), dest)?;
}
}
// errno
"__error" => {

View file

@ -6,8 +6,8 @@ use shims::foreign_items::EmulateForeignItemResult;
use shims::unix::fs::EvalContextExt as _;
use shims::unix::thread::EvalContextExt as _;
pub fn is_dyn_sym(name: &str) -> bool {
matches!(name, "getentropy")
pub fn is_dyn_sym(_name: &str) -> bool {
false
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
@ -113,18 +113,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_scalar(result, dest)?;
}
// Random generation related shims
"getentropy" => {
let [buf, bufsize] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let buf = this.read_pointer(buf)?;
let bufsize = this.read_target_usize(bufsize)?;
this.gen_random(buf, bufsize)?;
this.write_scalar(Scalar::from_i32(0), dest)?; // KERN_SUCCESS
}
// Access to command-line arguments
"_NSGetArgc" => {
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;

View file

@ -12,8 +12,8 @@ edition = "2021"
libc = "0.2"
num_cpus = "1.10.1"
getrandom_1 = { package = "getrandom", version = "0.1" }
getrandom = { version = "0.2", features = ["js"] }
getrandom_01 = { package = "getrandom", version = "0.1" }
getrandom_02 = { package = "getrandom", version = "0.2", features = ["js"] }
rand = { version = "0.8", features = ["small_rng"] }
[target.'cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))'.dependencies]

View file

@ -0,0 +1,10 @@
// mac-os `getrandom_01` does some pointer shenanigans
//@compile-flags: -Zmiri-permissive-provenance
/// Test direct calls of getrandom 0.1 and 0.2.
/// Make sure they work even with isolation enabled (i.e., we do not hit a file-based fallback path).
fn main() {
let mut data = vec![0; 16];
getrandom_01::getrandom(&mut data).unwrap();
getrandom_02::getrandom(&mut data).unwrap();
}

View file

@ -1,8 +0,0 @@
// mac-os `getrandom_1` does some pointer shenanigans
//@compile-flags: -Zmiri-permissive-provenance
/// Test old version of `getrandom`.
fn main() {
let mut data = vec![0; 16];
getrandom_1::getrandom(&mut data).unwrap();
}

View file

@ -1,10 +1,13 @@
//@compile-flags: -Zmiri-strict-provenance
use rand::{rngs::SmallRng, Rng, SeedableRng};
use rand::prelude::*;
// Test using the `rand` crate to generate randomness.
fn main() {
// Test `getrandom` directly.
let mut data = vec![0; 16];
getrandom::getrandom(&mut data).unwrap();
// Fully deterministic seeding.
let mut rng = SmallRng::seed_from_u64(42);
let _val = rng.gen::<i32>();
let _val = rng.gen::<isize>();
let _val = rng.gen::<i128>();
// Try seeding with "real" entropy.
let mut rng = SmallRng::from_entropy();

View file

@ -1,11 +1,20 @@
//@only-target-freebsd
//@ignore-target-windows: no libc
// on macOS this is not in the `libc` crate.
#[cfg(target_os = "macos")]
extern "C" {
fn getentropy(bytes: *mut libc::c_void, count: libc::size_t) -> libc::c_int;
}
#[cfg(not(target_os = "macos"))]
use libc::getentropy;
fn main() {
let mut buf1 = [0u8; 256];
let mut buf2 = [0u8; 257];
unsafe {
assert_eq!(libc::getentropy(buf1.as_mut_ptr() as *mut libc::c_void, buf1.len()), 0);
assert_eq!(libc::getentropy(buf2.as_mut_ptr() as *mut libc::c_void, buf2.len()), -1);
assert_eq!(getentropy(buf1.as_mut_ptr() as *mut libc::c_void, buf1.len()), 0);
assert_eq!(getentropy(buf2.as_mut_ptr() as *mut libc::c_void, buf2.len()), -1);
assert_eq!(std::io::Error::last_os_error().raw_os_error().unwrap(), libc::EIO);
}
}