summaryrefslogtreecommitdiff
path: root/src/basic/random-util.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2019-05-10 15:16:16 -0400
committerLennart Poettering <lennart@poettering.net>2019-05-10 15:31:46 -0400
commit1c53d4a070edbec8ad2d384ba0014d0eb6bae077 (patch)
treeef0a99767652ec23c315a9426ef4deda3686bf89 /src/basic/random-util.c
parentcb367b17853d215ebcf2816118c1f53d003e5088 (diff)
downloadsystemd-1c53d4a070edbec8ad2d384ba0014d0eb6bae077.tar.gz
random-util: eat up bad RDRAND values seen on AMD CPUs
An ugly, ugly work-around for #11810. And no, we shouldn't have to do this. This is something for AMD, the firmware or the kernel to fix/work-around, not us. But nonetheless, this should do it for now. Fixes: #11810
Diffstat (limited to 'src/basic/random-util.c')
-rw-r--r--src/basic/random-util.c15
1 files changed, 14 insertions, 1 deletions
diff --git a/src/basic/random-util.c b/src/basic/random-util.c
index b8bbf2d418..0561f0cb22 100644
--- a/src/basic/random-util.c
+++ b/src/basic/random-util.c
@@ -35,6 +35,7 @@ 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) {
@@ -59,12 +60,24 @@ int rdrand(unsigned long *ret) {
asm volatile("rdrand %0;"
"setc %1"
- : "=r" (*ret),
+ : "=r" (v),
"=qm" (success));
msan_unpoison(&success, sizeof(success));
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)
+ return log_debug_errno(SYNTHETIC_ERRNO(EUCLEAN),
+ "RDRAND returned suspicious value %lx, assuming bad hardware RNG, not using value.", v);
+
+ *ret = v;
return 0;
#else
return -EOPNOTSUPP;