Browse Source

Merge pull request #625 from besser82/topic/besser82/json-c-0.13/rdrand_fixes

json-c-0.13.x: Detect broken RDRAND during initialization.
json-c-0.13
Eric Hawicz GitHub 2 years ago
parent
commit
aadde421a5
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 67 additions and 29 deletions
  1. +67
    -29
      random_seed.c

+ 67
- 29
random_seed.c View File

@@ -26,20 +26,11 @@


static void do_cpuid(int regs[], int h) static void do_cpuid(int regs[], int h)
{ {
__asm__ __volatile__(
#if defined __x86_64__
"pushq %%rbx;\n"
#else
"pushl %%ebx;\n"
#endif
"cpuid;\n"
#if defined __x86_64__
"popq %%rbx;\n"
#else
"popl %%ebx;\n"
#endif
: "=a"(regs[0]), [ebx] "=r"(regs[1]), "=c"(regs[2]), "=d"(regs[3])
/* clang-format off */
__asm__ __volatile__("cpuid"
: "=a"(regs[0]), "=b"(regs[1]), "=c"(regs[2]), "=d"(regs[3])
: "a"(h)); : "a"(h));
/* clang-format on */
} }


#elif defined _MSC_VER #elif defined _MSC_VER
@@ -53,12 +44,51 @@ static void do_cpuid(int regs[], int h)


#if HAS_X86_CPUID #if HAS_X86_CPUID


static int has_rdrand()
static int get_rdrand_seed(void);

/* Valid values are -1 (haven't tested), 0 (no), and 1 (yes). */
static int _has_rdrand = -1;

static int has_rdrand(void)
{ {
// CPUID.01H:ECX.RDRAND[bit 30] == 1
int regs[4];
do_cpuid(regs, 1);
return (regs[2] & (1 << 30)) != 0;
if (_has_rdrand != -1)
{
return _has_rdrand;
}

/* CPUID.01H:ECX.RDRAND[bit 30] == 1 */
int regs[4];
do_cpuid(regs, 1);
if (!(regs[2] & (1 << 30)))
{
_has_rdrand = 0;
return 0;
}

/*
* Some CPUs advertise RDRAND in CPUID, but return 0xFFFFFFFF
* unconditionally. To avoid locking up later, test RDRAND here. If over
* 3 trials RDRAND has returned the same value, declare it broken.
* Example CPUs are AMD Ryzen 3000 series
* and much older AMD APUs, such as the E1-1500
* https://github.com/systemd/systemd/issues/11810
* https://linuxreviews.org/RDRAND_stops_returning_random_values_on_older_AMD_CPUs_after_suspend
*/
_has_rdrand = 0;
int prev = get_rdrand_seed();
for (int i = 0; i < 3; i++)
{
int temp = get_rdrand_seed();
if (temp != prev)
{
_has_rdrand = 1;
break;
}

prev = temp;
}

return _has_rdrand;
} }


#endif #endif
@@ -69,17 +99,19 @@ static int has_rdrand()


#define HAVE_RDRAND 1 #define HAVE_RDRAND 1


static int get_rdrand_seed()
static int get_rdrand_seed(void)
{ {
DEBUG_SEED("get_rdrand_seed");
int _eax;
// rdrand eax
__asm__ __volatile__("1: .byte 0x0F\n"
" .byte 0xC7\n"
" .byte 0xF0\n"
" jnc 1b;\n"
: "=a" (_eax));
return _eax;
DEBUG_SEED("get_rdrand_seed");
int _eax;
/* rdrand eax */
/* clang-format off */
__asm__ __volatile__("1: .byte 0x0F\n"
" .byte 0xC7\n"
" .byte 0xF0\n"
" jnc 1b;\n"
: "=a" (_eax));
/* clang-format on */
return _eax;
} }


#endif #endif
@@ -109,7 +141,7 @@ static int get_rdrand_seed()
DEBUG_SEED("get_rdrand_seed"); DEBUG_SEED("get_rdrand_seed");
int _eax; int _eax;
retry: retry:
// rdrand eax
/* rdrand eax */
__asm _emit 0x0F __asm _emit 0xC7 __asm _emit 0xF0 __asm _emit 0x0F __asm _emit 0xC7 __asm _emit 0xF0
__asm jnc retry __asm jnc retry
__asm mov _eax, eax __asm mov _eax, eax
@@ -178,8 +210,14 @@ static int get_dev_random_seed()


#define HAVE_CRYPTGENRANDOM 1 #define HAVE_CRYPTGENRANDOM 1


/* clang-format off */
#include <windows.h> #include <windows.h>

/* Caution: these blank lines must remain so clang-format doesn't reorder
includes to put windows.h after wincrypt.h */

#include <wincrypt.h> #include <wincrypt.h>
/* clang-format on */
#ifndef __GNUC__ #ifndef __GNUC__
#pragma comment(lib, "advapi32.lib") #pragma comment(lib, "advapi32.lib")
#endif #endif


Loading…
Cancel
Save