@@ -29,8 +29,8 @@ pub fn hashmap_random_keys() -> (u64, u64) {
2929mod imp {
3030 use fs:: File ;
3131 use io:: Read ;
32+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
3233 use libc;
33- use sys:: os:: errno;
3434
3535 #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
3636 fn getrandom ( buf : & mut [ u8 ] ) -> libc:: c_long {
@@ -40,71 +40,57 @@ mod imp {
4040 }
4141
4242 #[ cfg( not( any( target_os = "linux" , target_os = "android" ) ) ) ]
43- fn getrandom ( _buf : & mut [ u8 ] ) -> libc :: c_long { - 1 }
43+ fn getrandom_fill_bytes ( _buf : & mut [ u8 ] ) -> bool { false }
4444
45+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
4546 fn getrandom_fill_bytes ( v : & mut [ u8 ] ) -> bool {
47+ use sync:: atomic:: { AtomicBool , Ordering } ;
48+ use sys:: os:: errno;
49+
50+ static GETRANDOM_UNAVAILABLE : AtomicBool = AtomicBool :: new ( false ) ;
51+ if GETRANDOM_UNAVAILABLE . load ( Ordering :: Relaxed ) {
52+ return false ;
53+ }
54+
4655 let mut read = 0 ;
4756 while read < v. len ( ) {
4857 let result = getrandom ( & mut v[ read..] ) ;
4958 if result == -1 {
5059 let err = errno ( ) as libc:: c_int ;
5160 if err == libc:: EINTR {
5261 continue ;
62+ } else if err == libc:: ENOSYS {
63+ GETRANDOM_UNAVAILABLE . store ( true , Ordering :: Relaxed ) ;
64+ return false ;
5365 } else if err == libc:: EAGAIN {
54- return false
66+ return false ;
5567 } else {
5668 panic ! ( "unexpected getrandom error: {}" , err) ;
5769 }
5870 } else {
5971 read += result as usize ;
6072 }
6173 }
62-
63- return true
74+ true
6475 }
6576
66- #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
67- fn is_getrandom_available ( ) -> bool {
68- use io;
69- use sync:: atomic:: { AtomicBool , Ordering } ;
70- use sync:: Once ;
71-
72- static CHECKER : Once = Once :: new ( ) ;
73- static AVAILABLE : AtomicBool = AtomicBool :: new ( false ) ;
74-
75- CHECKER . call_once ( || {
76- let mut buf: [ u8 ; 0 ] = [ ] ;
77- let result = getrandom ( & mut buf) ;
78- let available = if result == -1 {
79- let err = io:: Error :: last_os_error ( ) . raw_os_error ( ) ;
80- err != Some ( libc:: ENOSYS )
81- } else {
82- true
83- } ;
84- AVAILABLE . store ( available, Ordering :: Relaxed ) ;
85- } ) ;
86-
87- AVAILABLE . load ( Ordering :: Relaxed )
88- }
89-
90- #[ cfg( not( any( target_os = "linux" , target_os = "android" ) ) ) ]
91- fn is_getrandom_available ( ) -> bool { false }
92-
9377 pub fn fill_bytes ( v : & mut [ u8 ] ) {
9478 // getrandom_fill_bytes here can fail if getrandom() returns EAGAIN,
9579 // meaning it would have blocked because the non-blocking pool (urandom)
96- // has not initialized in the kernel yet due to a lack of entropy the
80+ // has not initialized in the kernel yet due to a lack of entropy. The
9781 // fallback we do here is to avoid blocking applications which could
9882 // depend on this call without ever knowing they do and don't have a
99- // work around. The PRNG of /dev/urandom will still be used but not
100- // over a completely full entropy pool
101- if is_getrandom_available ( ) && getrandom_fill_bytes ( v) {
102- return
83+ // work around. The PRNG of /dev/urandom will still be used but over a
84+ // possibly predictable entropy pool.
85+ if getrandom_fill_bytes ( v) {
86+ return ;
10387 }
10488
105- let mut file = File :: open ( "/dev/urandom" )
106- . expect ( "failed to open /dev/urandom" ) ;
107- file. read_exact ( v) . expect ( "failed to read /dev/urandom" ) ;
89+ // getrandom failed because it is permanently or temporarily (because
90+ // of missing entropy) unavailable. Open /dev/urandom, read from it,
91+ // and close it again.
92+ let mut file = File :: open ( "/dev/urandom" ) . expect ( "failed to open /dev/urandom" ) ;
93+ file. read_exact ( v) . expect ( "failed to read /dev/urandom" )
10894 }
10995}
11096
0 commit comments