@@ -40,71 +40,54 @@ mod imp {
40
40
}
41
41
42
42
#[ 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 }
44
44
45
+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
45
46
fn getrandom_fill_bytes ( v : & mut [ u8 ] ) -> bool {
47
+ use sync:: atomic:: { AtomicBool , Ordering } ;
48
+ static GETRANDOM_UNAVAILABLE : AtomicBool = AtomicBool :: new ( false ) ;
49
+ if GETRANDOM_UNAVAILABLE . load ( Ordering :: Relaxed ) {
50
+ return false ;
51
+ }
52
+
46
53
let mut read = 0 ;
47
54
while read < v. len ( ) {
48
55
let result = getrandom ( & mut v[ read..] ) ;
49
56
if result == -1 {
50
57
let err = errno ( ) as libc:: c_int ;
51
58
if err == libc:: EINTR {
52
59
continue ;
60
+ } else if err == libc:: ENOSYS {
61
+ GETRANDOM_UNAVAILABLE . store ( true , Ordering :: Relaxed ) ;
53
62
} else if err == libc:: EAGAIN {
54
- return false
63
+ return false ;
55
64
} else {
56
65
panic ! ( "unexpected getrandom error: {}" , err) ;
57
66
}
58
67
} else {
59
68
read += result as usize ;
60
69
}
61
70
}
62
-
63
- return true
64
- }
65
-
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 )
71
+ true
88
72
}
89
73
90
- #[ cfg( not( any( target_os = "linux" , target_os = "android" ) ) ) ]
91
- fn is_getrandom_available ( ) -> bool { false }
92
-
93
74
pub fn fill_bytes ( v : & mut [ u8 ] ) {
94
75
// getrandom_fill_bytes here can fail if getrandom() returns EAGAIN,
95
76
// 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
77
+ // has not initialized in the kernel yet due to a lack of entropy. The
97
78
// fallback we do here is to avoid blocking applications which could
98
79
// 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
80
+ // work around. The PRNG of /dev/urandom will still be used but over a
81
+ // possibly predictable entropy pool.
82
+ if getrandom_fill_bytes ( v) {
83
+ return ;
103
84
}
104
85
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" ) ;
86
+ // getrandom failed because it is permanently or temporarily (because
87
+ // of missing entropy) unavailable. Open /dev/urandom, read from it,
88
+ // and close it again.
89
+ let mut file = File :: open ( "/dev/urandom" ) . expect ( "failed to open /dev/urandom" ) ;
90
+ file. read_exact ( v) . expect ( "failed to read /dev/urandom" )
108
91
}
109
92
}
110
93
0 commit comments