[efi] Retry calls to GetRNG() as needed

The UEFI specification allows GetRNG() to return EFI_NOT_READY, which
is not a particularly helpful error status since there is nothing that
can sensibly be done except to retry immediately.

Retry failed calls to GetRNG() up to a maximum number of attempts.

Debugged-by: Stoo Davies <sdavies@nvidia.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2025-12-11 14:04:10 +00:00
parent fb1188936c
commit 86c40a8b1e

View File

@@ -54,6 +54,15 @@ EFI_REQUEST_PROTOCOL ( EFI_RNG_PROTOCOL, &efirng );
*/ */
#define EFIRNG_LEN 32 #define EFIRNG_LEN 32
/** Maximum number of times to attempting requesting data from RNG
*
* The UEFI spec allows GetRNG() to return EFI_NOT_READY, which is not
* a particularly helpful error status since there is nothing that can
* sensibly be done except to retry immediately. We retry failed
* calls to GetRNG() (for any reason) up to this number of times.
*/
#define EFIRNG_MAX_RETRY 16
/** /**
* Enable entropy gathering * Enable entropy gathering
* *
@@ -85,31 +94,37 @@ static int efirng_enable ( void ) {
*/ */
static int efirng_get_noise ( noise_sample_t *noise ) { static int efirng_get_noise ( noise_sample_t *noise ) {
uint8_t buf[EFIRNG_LEN]; uint8_t buf[EFIRNG_LEN];
unsigned int i;
EFI_STATUS efirc; EFI_STATUS efirc;
int rc; int rc;
/* Sanity check */ /* Sanity check */
assert ( efirng != NULL ); assert ( efirng != NULL );
/* Get random bytes, retrying if needed */
for ( i = 0 ; i < EFIRNG_MAX_RETRY ; i++ ) {
/* Get the minimum allowed number of random bytes */ /* Get the minimum allowed number of random bytes */
if ( ( efirc = efirng->GetRNG ( efirng, NULL, sizeof ( buf ), if ( ( efirc = efirng->GetRNG ( efirng, NULL, sizeof ( buf ),
buf ) ) != 0 ) { buf ) ) != 0 ) {
rc = -EEFI ( efirc ); rc = -EEFI ( efirc );
continue;
}
/* Reduce random bytes to a single noise sample. This
* seems like overkill, but we have no way of knowing
* how much entropy is actually present in the bytes
* returned by the RNG protocol.
*/
*noise = crc32_le ( 0, buf, sizeof ( buf ) );
return 0;
}
DBGC ( &efirng, "ENTROPY could not read from RNG: %s\n", DBGC ( &efirng, "ENTROPY could not read from RNG: %s\n",
strerror ( rc ) ); strerror ( rc ) );
return rc; return rc;
} }
/* Reduce random bytes to a single noise sample. This seems
* like overkill, but we have no way of knowing how much
* entropy is actually present in the bytes returned by the
* RNG protocol.
*/
*noise = crc32_le ( 0, buf, sizeof ( buf ) );
return 0;
}
/** EFI random number generator protocol entropy source */ /** EFI random number generator protocol entropy source */
struct entropy_source efirng_entropy __entropy_source ( ENTROPY_NORMAL ) = { struct entropy_source efirng_entropy __entropy_source ( ENTROPY_NORMAL ) = {
.name = "efirng", .name = "efirng",