@@ -137,11 +137,9 @@ mod imp {
137137 }
138138}
139139
140- #[ cfg( target_os = "macos" ) ]
140+ #[ cfg( any ( target_os = "macos" , target_os = "ios" , target_os = "watchos" ) ) ]
141141mod imp {
142- use crate :: fs:: File ;
143- use crate :: io:: Read ;
144- use crate :: sys:: os:: errno;
142+ use crate :: io;
145143 use crate :: sys:: weak:: weak;
146144 use libc:: { c_int, c_void, size_t} ;
147145
@@ -155,22 +153,72 @@ mod imp {
155153 for s in v. chunks_mut ( 256 ) {
156154 let ret = unsafe { f ( s. as_mut_ptr ( ) as * mut c_void , s. len ( ) ) } ;
157155 if ret == -1 {
158- panic ! ( "unexpected getentropy error: {}" , errno ( ) ) ;
156+ panic ! ( "unexpected getentropy error: {}" , io :: Error :: last_os_error ( ) ) ;
159157 }
160158 }
161159 true
162160 } )
163161 . unwrap_or ( false )
164162 }
165163
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+
166209 pub fn fill_bytes ( v : & mut [ u8 ] ) {
167210 if getentropy_fill_bytes ( v) {
168211 return ;
169212 }
170213
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)
174222 }
175223}
176224
@@ -189,36 +237,6 @@ mod imp {
189237 }
190238}
191239
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-
222240#[ cfg( any( target_os = "freebsd" , target_os = "netbsd" ) ) ]
223241mod imp {
224242 use crate :: ptr;
0 commit comments