Skip to content

Commit 1396400

Browse files
committed
Merge bitcoin/bitcoin#31826: random: Check GetRNDRRS is supported in InitHardwareRand to avoid infinite loop
09b150b In `InitHardwareRand`, do trail test for `RNDRRS` by `VerifyRNDRRS` (Eval EXEC) Pull request description: This PR want to fix #31817 by added a maximum retry limit (`max_retries`) to the `GetRNDRRS` function to prevent it from entering an infinite loop if the hardware random number generator fails to return a valid random number. This change improves stability and ensures that the function terminates after a predefined number of retries. ACKs for top commit: achow101: ACK 09b150b sipa: utACK 09b150b Tree-SHA512: 5626b6b182a55d344a3aba11b782259ecc6bbec513771d50077874c5f70934750e68add8f63aa0bf69c6b7b313112940a85508af5447622c703cc5e92439ab4a
2 parents dc3a714 + 09b150b commit 1396400

File tree

1 file changed

+34
-11
lines changed

1 file changed

+34
-11
lines changed

src/random.cpp

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -192,20 +192,24 @@ uint64_t GetRdSeed() noexcept
192192
#elif defined(__aarch64__) && defined(HWCAP2_RNG)
193193

194194
bool g_rndr_supported = false;
195+
bool g_rndrrs_supported = false;
195196

196197
void InitHardwareRand()
197198
{
198199
if (getauxval(AT_HWCAP2) & HWCAP2_RNG) {
199200
g_rndr_supported = true;
201+
g_rndrrs_supported = VerifyRNDRRS();
200202
}
201203
}
202204

203205
void ReportHardwareRand()
204206
{
205207
// This must be done in a separate function, as InitHardwareRand() may be indirectly called
206208
// from global constructors, before logging is initialized.
207-
if (g_rndr_supported) {
209+
if (g_rndr_supported && g_rndrrs_supported) {
208210
LogPrintf("Using RNDR and RNDRRS as additional entropy sources\n");
211+
} else if (g_rndr_supported) {
212+
LogPrintf("Using RNDR as an additional entropy source\n");
209213
}
210214
}
211215

@@ -227,24 +231,43 @@ uint64_t GetRNDR() noexcept
227231
return r1;
228232
}
229233

230-
/** Read 64 bits of entropy using rndrrs.
231-
*
234+
// Helper function to retrieve random value using RNDRRS
235+
bool GetRNDRRSInternal(uint64_t &r1) noexcept
236+
{
237+
uint8_t ok = 0;
238+
__asm__ volatile("mrs %0, s3_3_c2_c4_1; cset %w1, ne;"
239+
: "=r"(r1), "=r"(ok)::"cc");
240+
return ok != 0;
241+
}
242+
243+
244+
/** Read 64 bits of entropy using RNDRRS.
232245
* Must only be called when RNDRRS is supported.
233246
*/
234247
uint64_t GetRNDRRS() noexcept
235248
{
236-
uint8_t ok = 0;
237249
uint64_t r1;
238-
do {
239-
// https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/RNDRRS--Reseeded-Random-Number
240-
__asm__ volatile("mrs %0, s3_3_c2_c4_1; cset %w1, ne;"
241-
: "=r"(r1), "=r"(ok)::"cc");
242-
if (ok) break;
250+
while (!GetRNDRRSInternal(r1)) {
243251
__asm__ volatile("yield");
244-
} while (true);
252+
}
245253
return r1;
246254
}
247255

256+
/** Verify if RNDRRS is supported and functional.
257+
* Return true if it works within the retry limit.
258+
*/
259+
bool VerifyRNDRRS() noexcept
260+
{
261+
uint64_t test;
262+
for (int retry = 0; retry < 10; ++retry) {
263+
if (GetRNDRRSInternal(test)) {
264+
return true;
265+
}
266+
__asm__ volatile("yield");
267+
}
268+
return false;
269+
}
270+
248271
#else
249272
/* Access to other hardware random number generators could be added here later,
250273
* assuming it is sufficiently fast (in the order of a few hundred CPU cycles).
@@ -295,7 +318,7 @@ void SeedHardwareSlow(CSHA512& hasher) noexcept {
295318
return;
296319
}
297320
#elif defined(__aarch64__) && defined(HWCAP2_RNG)
298-
if (g_rndr_supported) {
321+
if (g_rndrrs_supported) {
299322
for (int i = 0; i < 4; ++i) {
300323
uint64_t out = GetRNDRRS();
301324
hasher.Write((const unsigned char*)&out, sizeof(out));

0 commit comments

Comments
 (0)