Created
January 11, 2021 22:39
-
-
Save edwintorok/f3830326a7fc3f09326bf2e8c23826e0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* SPDX-License-Identifier: LGPL-2.1-or-later */ | |
#if defined(__i386__) || defined(__x86_64__) | |
#include <cpuid.h> | |
#endif | |
#include <errno.h> | |
#include <limits.h> | |
#include <stdbool.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
/* from systemd random-util.c: */ | |
int rdrand(unsigned long *ret) { | |
#if defined(__i386__) || defined(__x86_64__) | |
static int have_rdrand = -1; | |
unsigned long v; | |
uint8_t success; | |
if (have_rdrand < 0) { | |
uint32_t eax, ebx, ecx, edx; | |
/* Check if RDRAND is supported by the CPU */ | |
if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) == 0) { | |
have_rdrand = false; | |
return -EOPNOTSUPP; | |
} | |
/* Compat with old gcc where bit_RDRND didn't exist yet */ | |
#ifndef bit_RDRND | |
#define bit_RDRND (1U << 30) | |
#endif | |
have_rdrand = !!(ecx & bit_RDRND); | |
#if 0 | |
if (have_rdrand > 0) { | |
/* Allow disabling use of RDRAND with SYSTEMD_RDRAND=0 | |
If it is unset getenv_bool_secure will return a negative value. */ | |
if (getenv_bool_secure("SYSTEMD_RDRAND") == 0) { | |
have_rdrand = false; | |
return -EOPNOTSUPP; | |
} | |
} | |
#endif | |
} | |
if (have_rdrand == 0) | |
return -EOPNOTSUPP; | |
asm volatile("rdrand %0;" | |
"setc %1" | |
: "=r" (v), | |
"=qm" (success)); | |
#if 0 | |
msan_unpoison(&success, sizeof(success)); | |
#endif | |
if (!success) | |
return -EAGAIN; | |
/* Apparently on some AMD CPUs RDRAND will sometimes (after a suspend/resume cycle?) report success | |
* via the carry flag but nonetheless return the same fixed value -1 in all cases. This appears to be | |
* a bad bug in the CPU or firmware. Let's deal with that and work-around this by explicitly checking | |
* for this special value (and also 0, just to be sure) and filtering it out. This is a work-around | |
* only however and something AMD really should fix properly. The Linux kernel should probably work | |
* around this issue by turning off RDRAND altogether on those CPUs. See: | |
* https://github.com/systemd/systemd/issues/11810 */ | |
if (v == 0 || v == ULONG_MAX) | |
#if 0 | |
return log_debug_errno(SYNTHETIC_ERRNO(EUCLEAN), | |
"RDRAND returned suspicious value %lx, assuming bad hardware RNG, not using value.", v); | |
#else | |
{ | |
fprintf(stderr, "RDRAND returned suspicious value %lx, assuming bad hardware RNG\n", v); | |
return EUCLEAN; | |
} | |
#endif | |
*ret = v; | |
return 0; | |
#else | |
return -EOPNOTSUPP; | |
#endif | |
} | |
int main(int argc, char *argv[]) | |
{ | |
unsigned long val; | |
do { | |
errno = -rdrand(&val); | |
if (errno) { | |
perror("rdrand"); | |
exit(2); | |
} | |
fwrite(&val, sizeof(val), 1, stdout); | |
} while(1); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment