@@ -137,11 +137,9 @@ mod imp {
137
137
}
138
138
}
139
139
140
- #[ cfg( target_os = "macos" ) ]
140
+ #[ cfg( any ( target_os = "macos" , target_os = "ios" , target_os = "watchos" ) ) ]
141
141
mod imp {
142
- use crate :: fs:: File ;
143
- use crate :: io:: Read ;
144
- use crate :: sys:: os:: errno;
142
+ use crate :: io;
145
143
use crate :: sys:: weak:: weak;
146
144
use libc:: { c_int, c_void, size_t} ;
147
145
@@ -155,22 +153,72 @@ mod imp {
155
153
for s in v. chunks_mut ( 256 ) {
156
154
let ret = unsafe { f ( s. as_mut_ptr ( ) as * mut c_void , s. len ( ) ) } ;
157
155
if ret == -1 {
158
- panic ! ( "unexpected getentropy error: {}" , errno ( ) ) ;
156
+ panic ! ( "unexpected getentropy error: {}" , io :: Error :: last_os_error ( ) ) ;
159
157
}
160
158
}
161
159
true
162
160
} )
163
161
. unwrap_or ( false )
164
162
}
165
163
164
+ #[ cfg( target_os = "macos" ) ]
165
+ fn fallback_fill_bytes ( v : & mut [ u8 ] ) {
166
+ use crate :: fs:: File ;
167
+ use crate :: io:: Read ;
168
+
169
+ let mut file = File :: open ( "/dev/urandom" ) . expect ( "failed to open /dev/urandom" ) ;
170
+ file. read_exact ( v) . expect ( "failed to read /dev/urandom" )
171
+ }
172
+
173
+ // On iOS and MacOS `SecRandomCopyBytes` calls `CCRandomCopyBytes` with
174
+ // `kCCRandomDefault`. `CCRandomCopyBytes` manages a CSPRNG which is seeded
175
+ // from `/dev/random` and which runs on its own thread accessed via GCD.
176
+ //
177
+ // This is very heavyweight compared to the alternatives, but they may not be usable:
178
+ // - `getentropy` was added in iOS 10, but we support a minimum of iOS 7
179
+ // - `/dev/urandom` is not accessible inside the iOS app sandbox.
180
+ //
181
+ // Therefore `SecRandomCopyBytes` is only used on older iOS versions where no
182
+ // better options are present.
183
+ #[ cfg( target_os = "ios" ) ]
184
+ fn fallback_fill_bytes ( v : & mut [ u8 ] ) {
185
+ use crate :: ptr;
186
+
187
+ enum SecRandom { }
188
+
189
+ #[ allow( non_upper_case_globals) ]
190
+ const kSecRandomDefault: * const SecRandom = ptr:: null ( ) ;
191
+
192
+ extern "C" {
193
+ fn SecRandomCopyBytes ( rnd : * const SecRandom , count : size_t , bytes : * mut u8 ) -> c_int ;
194
+ }
195
+
196
+ let ret = unsafe { SecRandomCopyBytes ( kSecRandomDefault, v. len ( ) , v. as_mut_ptr ( ) ) } ;
197
+ if ret == -1 {
198
+ panic ! ( "couldn't generate random bytes: {}" , io:: Error :: last_os_error( ) ) ;
199
+ }
200
+ }
201
+
202
+ // All supported versions of watchOS (>= 5) have support for `getentropy`.
203
+ #[ cfg( target_os = "watchos" ) ]
204
+ #[ cold]
205
+ fn fallback_fill_bytes ( _: & mut [ u8 ] ) {
206
+ unreachable ! ( )
207
+ }
208
+
166
209
pub fn fill_bytes ( v : & mut [ u8 ] ) {
167
210
if getentropy_fill_bytes ( v) {
168
211
return ;
169
212
}
170
213
171
- // for older macos which doesn't support getentropy
172
- let mut file = File :: open ( "/dev/urandom" ) . expect ( "failed to open /dev/urandom" ) ;
173
- file. read_exact ( v) . expect ( "failed to read /dev/urandom" )
214
+ // Older macOS versions (< 10.12) don't support `getentropy`. Fallback to
215
+ // reading from `/dev/urandom` on these systems.
216
+ //
217
+ // Older iOS versions (< 10) don't support it either. Fallback to
218
+ // `SecRandomCopyBytes` on these systems. On watchOS, this is unreachable
219
+ // because the minimum supported version is 5 while `getentropy` became accessible
220
+ // in 3.
221
+ fallback_fill_bytes ( v)
174
222
}
175
223
}
176
224
@@ -189,36 +237,6 @@ mod imp {
189
237
}
190
238
}
191
239
192
- // On iOS and MacOS `SecRandomCopyBytes` calls `CCRandomCopyBytes` with
193
- // `kCCRandomDefault`. `CCRandomCopyBytes` manages a CSPRNG which is seeded
194
- // from `/dev/random` and which runs on its own thread accessed via GCD.
195
- // This seems needlessly heavyweight for the purposes of generating two u64s
196
- // once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is
197
- // only used on iOS where direct access to `/dev/urandom` is blocked by the
198
- // sandbox.
199
- #[ cfg( any( target_os = "ios" , target_os = "watchos" ) ) ]
200
- mod imp {
201
- use crate :: io;
202
- use crate :: ptr;
203
- use libc:: { c_int, size_t} ;
204
-
205
- enum SecRandom { }
206
-
207
- #[ allow( non_upper_case_globals) ]
208
- const kSecRandomDefault: * const SecRandom = ptr:: null ( ) ;
209
-
210
- extern "C" {
211
- fn SecRandomCopyBytes ( rnd : * const SecRandom , count : size_t , bytes : * mut u8 ) -> c_int ;
212
- }
213
-
214
- pub fn fill_bytes ( v : & mut [ u8 ] ) {
215
- let ret = unsafe { SecRandomCopyBytes ( kSecRandomDefault, v. len ( ) , v. as_mut_ptr ( ) ) } ;
216
- if ret == -1 {
217
- panic ! ( "couldn't generate random bytes: {}" , io:: Error :: last_os_error( ) ) ;
218
- }
219
- }
220
- }
221
-
222
240
#[ cfg( any( target_os = "freebsd" , target_os = "netbsd" ) ) ]
223
241
mod imp {
224
242
use crate :: ptr;
0 commit comments