Skip to content

Commit 2832253

Browse files
committed
Auto merge of rust-lang#3162 - RalfJung:random, r=RalfJung
share getentropy shim across various unixes
2 parents 382475d + edb4c0a commit 2832253

File tree

8 files changed

+65
-49
lines changed

8 files changed

+65
-49
lines changed

src/tools/miri/src/shims/unix/foreign_items.rs

+32-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ fn is_dyn_sym(name: &str, target_os: &str) -> bool {
2727
// `signal` is set up as a weak symbol in `init_extern_statics` (on Android) so we might as
2828
// well allow it in `dlsym`.
2929
"signal" => true,
30+
// needed at least on macOS to avoid file-based fallback in getrandom
31+
"getentropy" => true,
3032
// Give specific OSes a chance to allow their symbols.
3133
_ =>
3234
match target_os {
@@ -525,6 +527,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
525527
let result = this.getpid()?;
526528
this.write_scalar(Scalar::from_i32(result), dest)?;
527529
}
530+
"getentropy" => {
531+
// This function is non-standard but exists with the same signature and behavior on
532+
// Linux, macOS, and FreeBSD.
533+
if !matches!(&*this.tcx.sess.target.os, "linux" | "macos" | "freebsd") {
534+
throw_unsup_format!(
535+
"`getentropy` is not supported on {}",
536+
this.tcx.sess.target.os
537+
);
538+
}
539+
540+
let [buf, bufsize] =
541+
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
542+
let buf = this.read_pointer(buf)?;
543+
let bufsize = this.read_target_usize(bufsize)?;
544+
545+
// getentropy sets errno to EIO when the buffer size exceeds 256 bytes.
546+
// FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=getentropy&sektion=3&format=html
547+
// Linux: https://man7.org/linux/man-pages/man3/getentropy.3.html
548+
// macOS: https://keith.github.io/xcode-man-pages/getentropy.2.html
549+
if bufsize > 256 {
550+
let err = this.eval_libc("EIO");
551+
this.set_last_error(err)?;
552+
this.write_scalar(Scalar::from_i32(-1), dest)?
553+
} else {
554+
this.gen_random(buf, bufsize)?;
555+
this.write_scalar(Scalar::from_i32(0), dest)?;
556+
}
557+
}
528558

529559
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
530560
// 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> {
594624
this.write_int(super::UID, dest)?;
595625
}
596626

597-
"getpwuid_r" if this.frame_in_std() => {
627+
"getpwuid_r"
628+
if this.frame_in_std() => {
598629
let [uid, pwd, buf, buflen, result] =
599630
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
600631
this.check_no_isolation("`getpwuid_r`")?;

src/tools/miri/src/shims/unix/freebsd/foreign_items.rs

-17
Original file line numberDiff line numberDiff line change
@@ -47,23 +47,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
4747
this.read_scalar(len)?,
4848
)?;
4949
}
50-
"getentropy" => {
51-
let [buf, bufsize] =
52-
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
53-
let buf = this.read_pointer(buf)?;
54-
let bufsize = this.read_target_usize(bufsize)?;
55-
56-
// getentropy sets errno to EIO when the buffer size exceeds 256 bytes.
57-
// https://man.freebsd.org/cgi/man.cgi?query=getentropy&sektion=3&format=html
58-
if bufsize > 256 {
59-
let err = this.eval_libc("EIO");
60-
this.set_last_error(err)?;
61-
this.write_scalar(Scalar::from_i32(-1), dest)?
62-
} else {
63-
this.gen_random(buf, bufsize)?;
64-
this.write_scalar(Scalar::from_i32(0), dest)?;
65-
}
66-
}
6750

6851
// errno
6952
"__error" => {

src/tools/miri/src/shims/unix/macos/foreign_items.rs

+2-14
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use shims::foreign_items::EmulateForeignItemResult;
66
use shims::unix::fs::EvalContextExt as _;
77
use shims::unix::thread::EvalContextExt as _;
88

9-
pub fn is_dyn_sym(name: &str) -> bool {
10-
matches!(name, "getentropy")
9+
pub fn is_dyn_sym(_name: &str) -> bool {
10+
false
1111
}
1212

1313
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> {
113113
this.write_scalar(result, dest)?;
114114
}
115115

116-
// Random generation related shims
117-
"getentropy" => {
118-
let [buf, bufsize] =
119-
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
120-
let buf = this.read_pointer(buf)?;
121-
let bufsize = this.read_target_usize(bufsize)?;
122-
123-
this.gen_random(buf, bufsize)?;
124-
125-
this.write_scalar(Scalar::from_i32(0), dest)?; // KERN_SUCCESS
126-
}
127-
128116
// Access to command-line arguments
129117
"_NSGetArgc" => {
130118
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;

src/tools/miri/test_dependencies/Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ edition = "2021"
1212
libc = "0.2"
1313
num_cpus = "1.10.1"
1414

15-
getrandom_1 = { package = "getrandom", version = "0.1" }
16-
getrandom = { version = "0.2", features = ["js"] }
15+
getrandom_01 = { package = "getrandom", version = "0.1" }
16+
getrandom_02 = { package = "getrandom", version = "0.2", features = ["js"] }
1717
rand = { version = "0.8", features = ["small_rng"] }
1818

1919
[target.'cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))'.dependencies]
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// mac-os `getrandom_01` does some pointer shenanigans
2+
//@compile-flags: -Zmiri-permissive-provenance
3+
4+
/// Test direct calls of getrandom 0.1 and 0.2.
5+
/// Make sure they work even with isolation enabled (i.e., we do not hit a file-based fallback path).
6+
fn main() {
7+
let mut data = vec![0; 16];
8+
getrandom_01::getrandom(&mut data).unwrap();
9+
getrandom_02::getrandom(&mut data).unwrap();
10+
}

src/tools/miri/tests/pass-dep/getrandom_1.rs

-8
This file was deleted.

src/tools/miri/tests/pass-dep/random.rs renamed to src/tools/miri/tests/pass-dep/rand.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
//@compile-flags: -Zmiri-strict-provenance
2-
use rand::{rngs::SmallRng, Rng, SeedableRng};
2+
use rand::prelude::*;
33

4+
// Test using the `rand` crate to generate randomness.
45
fn main() {
5-
// Test `getrandom` directly.
6-
let mut data = vec![0; 16];
7-
getrandom::getrandom(&mut data).unwrap();
6+
// Fully deterministic seeding.
7+
let mut rng = SmallRng::seed_from_u64(42);
8+
let _val = rng.gen::<i32>();
9+
let _val = rng.gen::<isize>();
10+
let _val = rng.gen::<i128>();
811

912
// Try seeding with "real" entropy.
1013
let mut rng = SmallRng::from_entropy();
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
1-
//@only-target-freebsd
1+
//@ignore-target-windows: no libc
2+
3+
// on macOS this is not in the `libc` crate.
4+
#[cfg(target_os = "macos")]
5+
extern "C" {
6+
fn getentropy(bytes: *mut libc::c_void, count: libc::size_t) -> libc::c_int;
7+
}
8+
9+
#[cfg(not(target_os = "macos"))]
10+
use libc::getentropy;
211

312
fn main() {
413
let mut buf1 = [0u8; 256];
514
let mut buf2 = [0u8; 257];
615
unsafe {
7-
assert_eq!(libc::getentropy(buf1.as_mut_ptr() as *mut libc::c_void, buf1.len()), 0);
8-
assert_eq!(libc::getentropy(buf2.as_mut_ptr() as *mut libc::c_void, buf2.len()), -1);
16+
assert_eq!(getentropy(buf1.as_mut_ptr() as *mut libc::c_void, buf1.len()), 0);
17+
assert_eq!(getentropy(buf2.as_mut_ptr() as *mut libc::c_void, buf2.len()), -1);
918
assert_eq!(std::io::Error::last_os_error().raw_os_error().unwrap(), libc::EIO);
1019
}
1120
}

0 commit comments

Comments
 (0)