7
7
// except according to those terms.
8
8
9
9
//! 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 } ;
12
15
13
16
cfg_if ! {
14
17
if #[ cfg( target_arch = "x86_64" ) ] {
@@ -24,25 +27,16 @@ cfg_if! {
24
27
// Implementation Guide" - Section 5.2.1 and "Intel® 64 and IA-32 Architectures
25
28
// Software Developer’s Manual" - Volume 1 - Section 7.3.17.1.
26
29
const RETRY_LIMIT : usize = 10 ;
27
- const WORD_SIZE : usize = mem:: size_of :: < usize > ( ) ;
28
30
29
31
#[ target_feature( enable = "rdrand" ) ]
30
- unsafe fn rdrand ( ) -> Result < [ u8 ; WORD_SIZE ] , Error > {
32
+ unsafe fn rdrand ( ) -> Option < usize > {
31
33
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 ) ;
43
37
}
44
38
}
45
- Err ( Error :: FAILED_RDRAND )
39
+ None
46
40
}
47
41
48
42
// "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> {
73
67
if !is_rdrand_supported ( ) {
74
68
return Err ( Error :: NO_RDRAND ) ;
75
69
}
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 )
80
71
}
81
72
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 < ( ) > {
84
74
// We use chunks_exact_mut instead of chunks_mut as it allows almost all
85
75
// 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 > ( ) ) ;
87
77
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) ) ;
89
82
}
90
83
91
84
let tail = chunks. into_remainder ( ) ;
92
85
let n = tail. len ( ) ;
93
86
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] ) ) ;
95
89
}
96
- Ok ( ( ) )
90
+ Some ( ( ) )
97
91
}
0 commit comments