Skip to content

Commit 01739dd

Browse files
committed
rdrand: mark rdrand safe
In edition 2024 functions annotated with `target_feature(enable = "..")` are unsafe to call from contexts not so annotated, and otherwise safe. This was used in rust-lang/stdarch@59864cd to mark RDRAND safe, and this change is expected to be in 1.93.0 and is already in nightly. Since uefi targets are only tested on nightly, we only saw this lint on uefi, resulting in a misattribution of the behavior and an incorrect comment. Thus acknowledge that the intrinsics are safe and mark `rdrand` itself safe (when called from an annotated context) and remove all the newly unused unsafe blocks. Link: https://doc.rust-lang.org/reference/attributes/codegen.html#r-attributes.codegen.target_feature.safety-restrictions.
1 parent 658bb1a commit 01739dd

File tree

1 file changed

+25
-17
lines changed

1 file changed

+25
-17
lines changed

src/backends/rdrand.rs

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,19 @@ static RDRAND_GOOD: lazy::LazyBool = lazy::LazyBool::new();
2828
const RETRY_LIMIT: usize = 10;
2929

3030
#[target_feature(enable = "rdrand")]
31-
#[cfg_attr(target_os = "uefi", allow(unused_unsafe))] // HACK: Rust lint gives false positive on uefi
32-
unsafe fn rdrand() -> Option<Word> {
31+
fn rdrand() -> Option<Word> {
3332
for _ in 0..RETRY_LIMIT {
3433
let mut val = 0;
34+
// SAFETY: this function is safe to call from a `[target_feature(enable
35+
// = "rdrand")]` context (it itself is annotated with
36+
// `target_feature(enable = "rdrand")`) but was marked unsafe until
37+
// https://github.com/rust-lang/stdarch/commit/59864cd which was pulled
38+
// in via https://github.com/rust-lang/rust/commit/f2eb88b which is
39+
// expected to be included in 1.93.0. Since our MSRV is 1.85, we need to
40+
// use unsafe here and suppress the lint.
41+
//
42+
// TODO(MSRV 1.93): remove allow(unused_unsafe) and the unsafe block.
43+
#[allow(unused_unsafe)]
3544
if unsafe { rdrand_step(&mut val) } == 1 {
3645
return Some(val);
3746
}
@@ -49,12 +58,12 @@ compile_error!(
4958
// Adapted from Linux's test in arch/x86/kernel/cpu/rdrand.c
5059
// Fails with probability < 2^(-90) on 32-bit systems
5160
#[target_feature(enable = "rdrand")]
52-
unsafe fn self_test() -> bool {
61+
fn self_test() -> bool {
5362
// On AMD, RDRAND returns 0xFF...FF on failure, count it as a collision.
5463
let mut prev = Word::MAX;
5564
let mut fails = 0;
5665
for _ in 0..8 {
57-
match unsafe { rdrand() } {
66+
match rdrand() {
5867
Some(val) if val == prev => fails += 1,
5968
Some(val) => prev = val,
6069
None => return false,
@@ -102,49 +111,48 @@ fn is_rdrand_good() -> bool {
102111
unsafe { self_test() }
103112
}
104113

105-
// TODO: make this function safe when we have feature(target_feature_11)
106114
#[target_feature(enable = "rdrand")]
107-
unsafe fn rdrand_exact(dest: &mut [MaybeUninit<u8>]) -> Option<()> {
115+
fn rdrand_exact(dest: &mut [MaybeUninit<u8>]) -> Option<()> {
108116
// We use chunks_exact_mut instead of chunks_mut as it allows almost all
109117
// calls to memcpy to be elided by the compiler.
110118
let mut chunks = dest.chunks_exact_mut(size_of::<Word>());
111119
for chunk in chunks.by_ref() {
112-
let src = unsafe { rdrand() }?.to_ne_bytes();
120+
let src = rdrand()?.to_ne_bytes();
113121
chunk.copy_from_slice(slice_as_uninit(&src));
114122
}
115123

116124
let tail = chunks.into_remainder();
117125
let n = tail.len();
118126
if n > 0 {
119-
let src = unsafe { rdrand() }?.to_ne_bytes();
127+
let src = rdrand()?.to_ne_bytes();
120128
tail.copy_from_slice(slice_as_uninit(&src[..n]));
121129
}
122130
Some(())
123131
}
124132

125133
#[cfg(target_arch = "x86_64")]
126134
#[target_feature(enable = "rdrand")]
127-
unsafe fn rdrand_u32() -> Option<u32> {
128-
unsafe { rdrand() }.map(crate::util::truncate)
135+
fn rdrand_u32() -> Option<u32> {
136+
rdrand().map(crate::util::truncate)
129137
}
130138

131139
#[cfg(target_arch = "x86_64")]
132140
#[target_feature(enable = "rdrand")]
133-
unsafe fn rdrand_u64() -> Option<u64> {
134-
unsafe { rdrand() }
141+
fn rdrand_u64() -> Option<u64> {
142+
rdrand()
135143
}
136144

137145
#[cfg(target_arch = "x86")]
138146
#[target_feature(enable = "rdrand")]
139-
unsafe fn rdrand_u32() -> Option<u32> {
140-
unsafe { rdrand() }
147+
fn rdrand_u32() -> Option<u32> {
148+
rdrand()
141149
}
142150

143151
#[cfg(target_arch = "x86")]
144152
#[target_feature(enable = "rdrand")]
145-
unsafe fn rdrand_u64() -> Option<u64> {
146-
let a = unsafe { rdrand() }?;
147-
let b = unsafe { rdrand() }?;
153+
fn rdrand_u64() -> Option<u64> {
154+
let a = rdrand()?;
155+
let b = rdrand()?;
148156
Some((u64::from(a) << 32) | u64::from(b))
149157
}
150158

0 commit comments

Comments
 (0)