Message ID | e43e49f9ca4a9696f9c72e16182266593bbc1379.1406177531.git.luto@amacapital.net (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Il 24/07/2014 06:57, Andy Lutomirski ha scritto: > This is a straightforward implementation: for each bit of internal > RNG state, request one bit from KVM_GET_RNG_SEED. This is done even > if RDSEED/RDRAND worked, since KVM_GET_RNG_SEED is likely to provide > cryptographically secure output even if the CPU's RNG is weak or > compromised. > > Signed-off-by: Andy Lutomirski <luto@amacapital.net> > --- > arch/x86/Kconfig | 4 ++++ > arch/x86/include/asm/kvm_guest.h | 9 +++++++++ > arch/x86/kernel/archrandom.c | 25 ++++++++++++++++++++++++- > arch/x86/kernel/kvm.c | 10 ++++++++++ > 4 files changed, 47 insertions(+), 1 deletion(-) > > diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig > index a8f749e..adfa09c 100644 > --- a/arch/x86/Kconfig > +++ b/arch/x86/Kconfig > @@ -593,6 +593,7 @@ config KVM_GUEST > bool "KVM Guest support (including kvmclock)" > depends on PARAVIRT > select PARAVIRT_CLOCK > + select ARCH_RANDOM > default y > ---help--- > This option enables various optimizations for running under the KVM > @@ -1507,6 +1508,9 @@ config ARCH_RANDOM > If supported, this is a high bandwidth, cryptographically > secure hardware random number generator. > > + This also enables paravirt RNGs such as KVM's if the relevant > + PV guest support is enabled. > + > config X86_SMAP > def_bool y > prompt "Supervisor Mode Access Prevention" if EXPERT > diff --git a/arch/x86/include/asm/kvm_guest.h b/arch/x86/include/asm/kvm_guest.h > index a92b176..8c4dbd5 100644 > --- a/arch/x86/include/asm/kvm_guest.h > +++ b/arch/x86/include/asm/kvm_guest.h > @@ -3,4 +3,13 @@ > > int kvm_setup_vsyscall_timeinfo(void); > > +#if defined(CONFIG_KVM_GUEST) && defined(CONFIG_ARCH_RANDOM) > +extern bool kvm_get_rng_seed(u64 *rv); > +#else > +static inline bool kvm_get_rng_seed(u64 *rv) > +{ > + return false; > +} > +#endif > + > #endif /* _ASM_X86_KVM_GUEST_H */ > diff --git a/arch/x86/kernel/archrandom.c b/arch/x86/kernel/archrandom.c > index 47d13b0..8c8d021 100644 > --- a/arch/x86/kernel/archrandom.c > +++ b/arch/x86/kernel/archrandom.c > @@ -15,6 +15,7 @@ > */ > > #include <asm/archrandom.h> > +#include <asm/kvm_guest.h> > > void arch_get_rng_seed(void *ctx, > void (*seed)(void *ctx, u32 data), > @@ -22,7 +23,7 @@ void arch_get_rng_seed(void *ctx, > const char *log_prefix) > { > int i; > - int rdseed_bits = 0, rdrand_bits = 0; > + int rdseed_bits = 0, rdrand_bits = 0, kvm_bits = 0; > char buf[128] = ""; > char *msgptr = buf; > > @@ -42,10 +43,32 @@ void arch_get_rng_seed(void *ctx, > #endif > } > > + /* > + * Use KVM_GET_RNG_SEED regardless of whether the CPU RNG > + * worked, since it incorporates entropy unavailable to the CPU, > + * and we shouldn't trust the hardware RNG more than we need to. > + * We request enough bits for the entire internal RNG state, > + * because there's no good reason not to. > + */ > + for (i = 0; i < bits_per_source; i += 64) { > + u64 rv; > + > + if (kvm_get_rng_seed(&rv)) { > + seed(ctx, (u32)rv); > + seed(ctx, (u32)(rv >> 32)); > + kvm_bits += 8 * sizeof(rv); > + } else { > + break; /* If it fails once, it will keep failing. */ > + } > + } > + > if (rdseed_bits) > msgptr += sprintf(msgptr, ", %d bits from RDSEED", rdseed_bits); > if (rdrand_bits) > msgptr += sprintf(msgptr, ", %d bits from RDRAND", rdrand_bits); > + if (kvm_bits) > + msgptr += sprintf(msgptr, ", %d bits from KVM_GET_RNG_BITS", > + kvm_bits); > if (buf[0]) > pr_info("%s with %s\n", log_prefix, buf + 2); > } > diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c > index 3dd8e2c..bd8783a 100644 > --- a/arch/x86/kernel/kvm.c > +++ b/arch/x86/kernel/kvm.c > @@ -416,6 +416,16 @@ void kvm_disable_steal_time(void) > wrmsr(MSR_KVM_STEAL_TIME, 0, 0); > } > > +bool kvm_get_rng_seed(u64 *v) > +{ > + /* > + * Allow migration from a hypervisor with the GET_RNG_SEED > + * feature to a hypervisor without it. > + */ > + return (kvm_para_has_feature(KVM_FEATURE_GET_RNG_SEED) && > + rdmsrl_safe(MSR_KVM_GET_RNG_SEED, v) == 0); > +} > + > #ifdef CONFIG_SMP > static void __init kvm_smp_prepare_boot_cpu(void) > { > Acked-by: Paolo Bonzini <pbonzini@redhat.com> -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index a8f749e..adfa09c 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -593,6 +593,7 @@ config KVM_GUEST bool "KVM Guest support (including kvmclock)" depends on PARAVIRT select PARAVIRT_CLOCK + select ARCH_RANDOM default y ---help--- This option enables various optimizations for running under the KVM @@ -1507,6 +1508,9 @@ config ARCH_RANDOM If supported, this is a high bandwidth, cryptographically secure hardware random number generator. + This also enables paravirt RNGs such as KVM's if the relevant + PV guest support is enabled. + config X86_SMAP def_bool y prompt "Supervisor Mode Access Prevention" if EXPERT diff --git a/arch/x86/include/asm/kvm_guest.h b/arch/x86/include/asm/kvm_guest.h index a92b176..8c4dbd5 100644 --- a/arch/x86/include/asm/kvm_guest.h +++ b/arch/x86/include/asm/kvm_guest.h @@ -3,4 +3,13 @@ int kvm_setup_vsyscall_timeinfo(void); +#if defined(CONFIG_KVM_GUEST) && defined(CONFIG_ARCH_RANDOM) +extern bool kvm_get_rng_seed(u64 *rv); +#else +static inline bool kvm_get_rng_seed(u64 *rv) +{ + return false; +} +#endif + #endif /* _ASM_X86_KVM_GUEST_H */ diff --git a/arch/x86/kernel/archrandom.c b/arch/x86/kernel/archrandom.c index 47d13b0..8c8d021 100644 --- a/arch/x86/kernel/archrandom.c +++ b/arch/x86/kernel/archrandom.c @@ -15,6 +15,7 @@ */ #include <asm/archrandom.h> +#include <asm/kvm_guest.h> void arch_get_rng_seed(void *ctx, void (*seed)(void *ctx, u32 data), @@ -22,7 +23,7 @@ void arch_get_rng_seed(void *ctx, const char *log_prefix) { int i; - int rdseed_bits = 0, rdrand_bits = 0; + int rdseed_bits = 0, rdrand_bits = 0, kvm_bits = 0; char buf[128] = ""; char *msgptr = buf; @@ -42,10 +43,32 @@ void arch_get_rng_seed(void *ctx, #endif } + /* + * Use KVM_GET_RNG_SEED regardless of whether the CPU RNG + * worked, since it incorporates entropy unavailable to the CPU, + * and we shouldn't trust the hardware RNG more than we need to. + * We request enough bits for the entire internal RNG state, + * because there's no good reason not to. + */ + for (i = 0; i < bits_per_source; i += 64) { + u64 rv; + + if (kvm_get_rng_seed(&rv)) { + seed(ctx, (u32)rv); + seed(ctx, (u32)(rv >> 32)); + kvm_bits += 8 * sizeof(rv); + } else { + break; /* If it fails once, it will keep failing. */ + } + } + if (rdseed_bits) msgptr += sprintf(msgptr, ", %d bits from RDSEED", rdseed_bits); if (rdrand_bits) msgptr += sprintf(msgptr, ", %d bits from RDRAND", rdrand_bits); + if (kvm_bits) + msgptr += sprintf(msgptr, ", %d bits from KVM_GET_RNG_BITS", + kvm_bits); if (buf[0]) pr_info("%s with %s\n", log_prefix, buf + 2); } diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 3dd8e2c..bd8783a 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -416,6 +416,16 @@ void kvm_disable_steal_time(void) wrmsr(MSR_KVM_STEAL_TIME, 0, 0); } +bool kvm_get_rng_seed(u64 *v) +{ + /* + * Allow migration from a hypervisor with the GET_RNG_SEED + * feature to a hypervisor without it. + */ + return (kvm_para_has_feature(KVM_FEATURE_GET_RNG_SEED) && + rdmsrl_safe(MSR_KVM_GET_RNG_SEED, v) == 0); +} + #ifdef CONFIG_SMP static void __init kvm_smp_prepare_boot_cpu(void) {
This is a straightforward implementation: for each bit of internal RNG state, request one bit from KVM_GET_RNG_SEED. This is done even if RDSEED/RDRAND worked, since KVM_GET_RNG_SEED is likely to provide cryptographically secure output even if the CPU's RNG is weak or compromised. Signed-off-by: Andy Lutomirski <luto@amacapital.net> --- arch/x86/Kconfig | 4 ++++ arch/x86/include/asm/kvm_guest.h | 9 +++++++++ arch/x86/kernel/archrandom.c | 25 ++++++++++++++++++++++++- arch/x86/kernel/kvm.c | 10 ++++++++++ 4 files changed, 47 insertions(+), 1 deletion(-)