qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: privileged entropy sources in QEMU/KVM guests


From: Laszlo Ersek
Subject: Re: privileged entropy sources in QEMU/KVM guests
Date: Thu, 7 Nov 2019 14:27:52 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.9.1

On 11/07/19 12:37, Paolo Bonzini wrote:
> On 07/11/19 11:25, Ard Biesheuvel wrote:
>>> This looks problematic on QEMU. Entropy is a valuable resource, and
>>> whatever resource SMM drivers depend on, should not be possible for e.g.
>>> a 3rd party UEFI driver (or even for the runtime OS) to exhaust.
>>> Therefore, it's not *only* the case that SMM drivers must not consume
>>> EFI_RNG_PROTOCOL (which exists at a less critical privilege level, i.e.
>>> outside of SMM/SMRAM), but also that SMM drivers must not depend on the
>>> same piece of *hardware* that feeds EFI_RNG_PROTOCOL.
>>>
>> The typical model is to seed a DRBG [deterministic pseudorandom
>> sequence generator] using a sufficient amount of high quality entropy.
>> Once you have done that, it is rather hard to exhaust a DRBG - it is a
>> mathematical construction that is designed to last for a long time (<=
>> 2^48 invocations [not bytes] according to the NIST spec), after which
>> it does not degrade although it may have generated so much output that
>> its internal state may be inferred if you have captured enough of it
>> (which is a rather theoretical issue IMHO)
>>
>> The problem is that using the output of a DRBG as a seed is
>> non-trivial - the spec describes ways to do this, but wiring
>> virtio-rng to a DRBG in the host and using its output to seed a DRBG
>> in the guest is slighly problematic.
>>
>> So it seems to me that the correct way to model this is to make the
>> host's true entropy source a shared resource like any other.
>>
> 
> Yes, I would make SMM use a cryptographic pseudo-random number generator 
> and seed it from virtio-rng from DXE,

The VirtioRngDxe driver is a UEFI driver that follows the UEFI driver
model. Meaning (in this context), it is connected to the virtio-rng
device in the BDS phase, by platform BDS code.

The variable SMM driver is necessary for producing the UEFI Variable and
Variable Write architectural protocols. BDS can only be entered when all
the architectural protocols have been installed.

Therefore we have a circular dependency with the above -- assuming we
intend to delay the *startup* of the variable SMM driver until after
EFI_RNG_PROTOCOL is available.

But, perhaps, could the variable SMM driver start up anyway, and consume
EFI_RNG_PROTOCOL just when it really needs the random seed? I doubt it:
other EFI_RNG_PROTOCOL instances could be produced by other (3rd party)
UEFI drivers. Or other (3rd party) modules could "attack" VirtioRngDxe.
A privileged (SMM) driver should not consume such sensitive data from a
non-privileged driver, unless the latter was built into the platform
firmware, and the consumption occurred before the End-of-Dxe event
(which is signaled by platform BDS, early in the BDS phase).

Put differently, the non-privileged driver that's the source of the
sensitive data would have to be a "platform DXE driver". The virtio
drivers are not such drivers however.

I can imagine a roundabout way to hack this around in OVMF's platform
BDS, quite horribly, but I'd like to consider other approaches first.

Thank you!
Laszlo

> way before the OS starts and can 
> "attack" it.
> 
> Once you've gotten a seed, you can create a CSPRNG with a stream cipher 
> such as ChaCha20, which is literally 30 lines of code.
> 
> Paolo
> 
> #define ROTL(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
> #define QR(a, b, c, d) (                      \
>       a += b,  d ^= a,  d = ROTL(d,16),       \
>       c += d,  b ^= c,  b = ROTL(b,12),       \
>       a += b,  d ^= a,  d = ROTL(d, 8),       \
>       c += d,  b ^= c,  b = ROTL(b, 7))
> #define ROUNDS 20
> 
> // initial state:
> // in[0] = 0x65787061
> // in[1] = 0x6e642033
> // in[2] = 0x322d6279
> // in[3] = 0x7465206b
> // in[4]..in[11] = key (seed)
> // in[12]..in[13] = 0
> // in[14]..in[15] = nonce, can probably use RDTSC?
> static uint32_t in[16];
> 
> uint32_t chacha_rng(void)
> {
>       int i;
>       static uint32_t x[16], p;
>       if (p < 16)
>               return in[p++] + x[p++];
> 
>       if (++in[12] == 0)
>               ++in[13];
> 
>       for (i = 0; i < 16; ++i)
>               x[i] = in[i];
> 
>       // 10 loops × 2 rounds/loop = 20 rounds
>       for (i = 0; i < ROUNDS; i += 2) {
>               // Odd round
>               QR(x[0], x[4], x[ 8], x[12]); // column 0
>               QR(x[1], x[5], x[ 9], x[13]); // column 1
>               QR(x[2], x[6], x[10], x[14]); // column 2
>               QR(x[3], x[7], x[11], x[15]); // column 3
>               // Even round
>               QR(x[0], x[5], x[10], x[15]); // diagonal 1 (main diagonal)
>               QR(x[1], x[6], x[11], x[12]); // diagonal 2
>               QR(x[2], x[7], x[ 8], x[13]); // diagonal 3
>               QR(x[3], x[4], x[ 9], x[14]); // diagonal 4
>       }
>       p = 1;
>       return in[0] + x[0];
> }
> 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]