77// except according to those terms.
88
99//! Implementation for SGX using RDRAND instruction
10- use crate :: { util:: slice_as_uninit, Error } ;
11- use core:: mem:: { self , MaybeUninit } ;
10+ use crate :: {
11+ util:: { slice_as_uninit, LazyBool } ,
12+ Error ,
13+ } ;
14+ use core:: mem:: { size_of, MaybeUninit } ;
1215
1316cfg_if ! {
1417 if #[ cfg( target_arch = "x86_64" ) ] {
@@ -24,25 +27,16 @@ cfg_if! {
2427// Implementation Guide" - Section 5.2.1 and "Intel® 64 and IA-32 Architectures
2528// Software Developer’s Manual" - Volume 1 - Section 7.3.17.1.
2629const RETRY_LIMIT : usize = 10 ;
27- const WORD_SIZE : usize = mem:: size_of :: < usize > ( ) ;
2830
2931#[ target_feature( enable = "rdrand" ) ]
30- unsafe fn rdrand ( ) -> Result < [ u8 ; WORD_SIZE ] , Error > {
32+ unsafe fn rdrand ( ) -> Option < usize > {
3133 for _ in 0 ..RETRY_LIMIT {
32- let mut el = mem:: zeroed ( ) ;
33- if rdrand_step ( & mut el) == 1 {
34- // AMD CPUs from families 14h to 16h (pre Ryzen) sometimes fail to
35- // set CF on bogus random data, so we check these values explicitly.
36- // See https://github.com/systemd/systemd/issues/11810#issuecomment-489727505
37- // We perform this check regardless of target to guard against
38- // any implementation that incorrectly fails to set CF.
39- if el != 0 && el != !0 {
40- return Ok ( el. to_ne_bytes ( ) ) ;
41- }
42- // Keep looping in case this was a false positive.
34+ let mut val = 0 ;
35+ if rdrand_step ( & mut val) == 1 {
36+ return Some ( val as usize ) ;
4337 }
4438 }
45- Err ( Error :: FAILED_RDRAND )
39+ None
4640}
4741
4842// "rdrand" target feature requires "+rdrand" flag, see https://github.com/rust-lang/rust/issues/49653.
@@ -73,25 +67,25 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
7367 if !is_rdrand_supported ( ) {
7468 return Err ( Error :: NO_RDRAND ) ;
7569 }
76-
77- // SAFETY: After this point, rdrand is supported, so calling the rdrand
78- // functions is not undefined behavior.
79- unsafe { rdrand_exact ( dest) }
70+ rdrand_exact ( dest) . ok_or ( Error :: FAILED_RDRAND )
8071}
8172
82- #[ target_feature( enable = "rdrand" ) ]
83- unsafe fn rdrand_exact ( dest : & mut [ MaybeUninit < u8 > ] ) -> Result < ( ) , Error > {
73+ fn rdrand_exact ( dest : & mut [ MaybeUninit < u8 > ] ) -> Option < ( ) > {
8474 // We use chunks_exact_mut instead of chunks_mut as it allows almost all
8575 // calls to memcpy to be elided by the compiler.
86- let mut chunks = dest. chunks_exact_mut ( WORD_SIZE ) ;
76+ let mut chunks = dest. chunks_exact_mut ( size_of :: < usize > ( ) ) ;
8777 for chunk in chunks. by_ref ( ) {
88- chunk. copy_from_slice ( slice_as_uninit ( & rdrand ( ) ?) ) ;
78+ // SAFETY: After this point, we know rdrand is supported, so calling
79+ // rdrand is not undefined behavior.
80+ let src = unsafe { rdrand ( ) } ?. to_ne_bytes ( ) ;
81+ chunk. copy_from_slice ( slice_as_uninit ( & src) ) ;
8982 }
9083
9184 let tail = chunks. into_remainder ( ) ;
9285 let n = tail. len ( ) ;
9386 if n > 0 {
94- tail. copy_from_slice ( slice_as_uninit ( & rdrand ( ) ?[ ..n] ) ) ;
87+ let src = unsafe { rdrand ( ) } ?. to_ne_bytes ( ) ;
88+ tail. copy_from_slice ( slice_as_uninit ( & src[ ..n] ) ) ;
9589 }
96- Ok ( ( ) )
90+ Some ( ( ) )
9791}
0 commit comments