@@ -154,40 +154,65 @@ mod imp {
154154 }
155155}
156156
157- #[ cfg( target_os = "macos " ) ]
157+ #[ cfg( target_vendor = "apple " ) ]
158158mod imp {
159- use crate :: fs:: File ;
160- use crate :: io:: Read ;
161- use crate :: sys:: os:: errno;
162- use crate :: sys:: weak:: weak;
159+ use crate :: io;
163160 use libc:: { c_int, c_void, size_t} ;
164161
165- fn getentropy_fill_bytes ( v : & mut [ u8 ] ) -> bool {
166- weak ! ( fn getentropy( * mut c_void, size_t) -> c_int) ;
167-
168- getentropy
169- . get ( )
170- . map ( |f| {
171- // getentropy(2) permits a maximum buffer size of 256 bytes
172- for s in v. chunks_mut ( 256 ) {
173- let ret = unsafe { f ( s. as_mut_ptr ( ) as * mut c_void , s. len ( ) ) } ;
174- if ret == -1 {
175- panic ! ( "unexpected getentropy error: {}" , errno( ) ) ;
176- }
177- }
178- true
179- } )
180- . unwrap_or ( false )
162+ #[ inline( always) ]
163+ fn random_failure ( ) -> ! {
164+ panic ! ( "unexpected random generation error: {}" , io:: Error :: last_os_error( ) ) ;
181165 }
182166
183- pub fn fill_bytes ( v : & mut [ u8 ] ) {
184- if getentropy_fill_bytes ( v) {
185- return ;
167+ #[ cfg( target_os = "macos" ) ]
168+ fn getentropy_fill_bytes ( v : & mut [ u8 ] ) {
169+ extern "C" {
170+ fn getentropy ( bytes : * mut c_void , count : size_t ) -> c_int ;
186171 }
187172
188- // for older macos which doesn't support getentropy
189- let mut file = File :: open ( "/dev/urandom" ) . expect ( "failed to open /dev/urandom" ) ;
190- file. read_exact ( v) . expect ( "failed to read /dev/urandom" )
173+ // getentropy(2) permits a maximum buffer size of 256 bytes
174+ for s in v. chunks_mut ( 256 ) {
175+ let ret = unsafe { getentropy ( s. as_mut_ptr ( ) . cast ( ) , s. len ( ) ) } ;
176+ if ret == -1 {
177+ random_failure ( )
178+ }
179+ }
180+ }
181+
182+ #[ cfg( not( target_os = "macos" ) ) ]
183+ fn ccrandom_fill_bytes ( v : & mut [ u8 ] ) {
184+ extern "C" {
185+ fn CCRandomGenerateBytes ( bytes : * mut c_void , count : size_t ) -> c_int ;
186+ }
187+
188+ let ret = unsafe { CCRandomGenerateBytes ( v. as_mut_ptr ( ) . cast ( ) , v. len ( ) ) } ;
189+ if ret == -1 {
190+ random_failure ( )
191+ }
192+ }
193+
194+ pub fn fill_bytes ( v : & mut [ u8 ] ) {
195+ // All supported versions of macOS (10.12+) support getentropy.
196+ //
197+ // `getentropy` is measurably faster then the other alternatives, so its preferred
198+ // when usable.
199+ #[ cfg( target_os = "macos" ) ]
200+ getentropy_fill_bytes ( v) ;
201+
202+ // On Apple platforms, `CCRandomGenerateBytes` and `SecRandomCopyBytes` simply
203+ // call into `CCRandomCopyBytes` with `kCCRandomDefault`. `CCRandomCopyBytes`
204+ // manages a CSPRNG which is seeded from the kernel's CSPRNG and which runs on
205+ // its own thread accessed via GCD. This seems needlessly heavyweight for our purposes
206+ // so we only use it on non-Mac OSes where the better entrypoints are blocked.
207+ //
208+ // `CCRandomGenerateBytes` is used instead of `SecRandomCopyBytes` because the former is accessible
209+ // via `libSystem` (libc) while the other needs to link to `Security.framework`.
210+ //
211+ // Note that while `getentropy` has a available attribute in the macOS headers, the lack
212+ // of a header in the iOS (and others) SDK means that its can cause app store rejections.
213+ // Just use `CCRandomGenerateBytes` instead.
214+ #[ cfg( not( target_os = "macos" ) ) ]
215+ ccrandom_fill_bytes ( v) ;
191216 }
192217}
193218
@@ -206,36 +231,6 @@ mod imp {
206231 }
207232}
208233
209- // On iOS and MacOS `SecRandomCopyBytes` calls `CCRandomCopyBytes` with
210- // `kCCRandomDefault`. `CCRandomCopyBytes` manages a CSPRNG which is seeded
211- // from `/dev/random` and which runs on its own thread accessed via GCD.
212- // This seems needlessly heavyweight for the purposes of generating two u64s
213- // once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is
214- // only used on iOS where direct access to `/dev/urandom` is blocked by the
215- // sandbox.
216- #[ cfg( any( target_os = "ios" , target_os = "tvos" , target_os = "watchos" ) ) ]
217- mod imp {
218- use crate :: io;
219- use crate :: ptr;
220- use libc:: { c_int, size_t} ;
221-
222- enum SecRandom { }
223-
224- #[ allow( non_upper_case_globals) ]
225- const kSecRandomDefault: * const SecRandom = ptr:: null ( ) ;
226-
227- extern "C" {
228- fn SecRandomCopyBytes ( rnd : * const SecRandom , count : size_t , bytes : * mut u8 ) -> c_int ;
229- }
230-
231- pub fn fill_bytes ( v : & mut [ u8 ] ) {
232- let ret = unsafe { SecRandomCopyBytes ( kSecRandomDefault, v. len ( ) , v. as_mut_ptr ( ) ) } ;
233- if ret == -1 {
234- panic ! ( "couldn't generate random bytes: {}" , io:: Error :: last_os_error( ) ) ;
235- }
236- }
237- }
238-
239234#[ cfg( target_os = "netbsd" ) ]
240235mod imp {
241236 use crate :: ptr;
0 commit comments