Pitchforks for RDSEED
As background, it is worth looking at two related instructions provided on x86 systems:
- RDSEED is a true random-number generator; it reads entropy collected from the environment and stores a random bit pattern into a CPU register. It is provided primarily for the seeding of pseudo-random number generators or other applications where the highest-quality randomness is needed.
- RDRAND obtains a random pattern from a deterministic random-number generator built into the hardware and stores it into a register. The generator used by RDRAND is periodically reseeded from the source used by RDSEED.
RDRAND is recommended for most uses; it is faster and can significantly stretch the amount of entropy that is available to the system. Within the kernel, RDSEED is used to seed the kernel's random-number generator, but for little else. An important point to note is that neither of these instructions is privileged; they are equally available to user-space code. Also important is the fact that either instruction can fail if there is not sufficient entropy available. (See this page for lots of details on how these instructions work).
On the x86 architecture, the kernel has a pair of functions, rdseed_long() and rdrand_long(), that make use of the above instructions. Kirill Shutemov recently observed that, while rdrand_long() will retry ten times if RDRAND fails, rdseed_long() gives up immediately. He posted a patch adding a retry loop to rdseed_long(), and another to issue a warning if even ten tries were not enough to get a successful result. That is where the discussion began.
Can they fail (and do we care)?
Initially, there was some uncertainty over whether those instructions can fail at all. RDSEED is able to produce entropy at a high rate, and RDRAND multiplies that entropy considerably, so exhausting them seems unlikely. Jason Donenfeld, who maintains the kernel's random-number generator, worried that, if the CPU's random-number generator could be driven to failure, that denial-of-service problems could result. Dave Hansen, though, thought that such worries were misplaced; he spoke authoritatively:
Despite the SDM allowing it, we (software) need RDRAND/RDSEED failures to be exceedingly rare by design. If they're not, we're going to get our trusty torches and pitchforks and go after the folks who built the broken hardware.Repeat after me:
Regular RDRAND/RDSEED failures only occur on broken hardware
It seems, though, that there may just be a use for those pitchforks. Donenfeld wrote a little program to stress the hardware by repeatedly executing RDRAND and RDSEED instructions; he observed that RDSEED failed nearly 30% of the time — with a single-threaded test. The hardware random-number generator, though, is shared between all CPUs in a socket, so a multi-threaded test can be expected to show worse results. Indeed, Daniel P. Berrangé reported that, with a multi-threaded test, RDSEED only succeeded 3% of the time. Nobody was able to demonstrate RDRAND failures but, as Berrangé pointed out later in the discussion, that situation could change with a larger number of threads. Elena Reshetova also acknowledged that it may be possible to force RDRAND to fail.
The clear outcome is that, with a determined effort, RDSEED can be made to fail and the reliability of RDRAND is not guaranteed. The logical next question is: how much of a concern is this? For most use cases, there is little to worry about. The kernel's random-number generator will continue to produce unpredictable output if the hardware random-number generator fails occasionally, even in the absence of other entropy sources. As Ted Ts'o pointed out, the kernel makes use of any other entropy sources it can find (such as the variation in interrupt timings) and is intended to be robust even if RDRAND were to turn out to be entirely compromised. Since most applications get their random data from the kernel, even an unreliable RDRAND should not be a concern.
There is, however, one noteworthy exception: the use case known as confidential computing (sometimes referred to as "CoCo"), which is intended to guarantee the security and confidentiality of virtual machines even if they are running on a compromised or hostile host computer. Techniques like secure enclaves and encrypted memory have been developed to protect virtual machines from a prying host; these technologies may, someday, work as intended, but they are absolutely dependent on the availability of trustworthy random data. If a "confidential" virtual machine can be launched with a known random seed, the game may be over before it starts.
Availability of entropy at boot time has long been a problem for Linux systems, so a number of mechanisms have been developed to seed the random-number generator as quickly as possible. These can include using random data injected by the bootloader and collecting entropy from the environment. A confidential-computing system, though, cannot trust inputs like that. The bootloader is under the host's control, but so is environmental entropy. As Reshetova explained, the host is able to control events like the expiration of timers and the delivery of interrupts. The only source of entropy that is not, at least theoretically, under the host's control is the hardware random-number generator. If that, too, is compromised, the entire confidential-computing dream falls apart.
What to do
That dream has been somewhat controversial in kernel circles from the
beginning, and this revelation has not helped; at one point Donenfeld asked
directly: "Is this CoCo VM stuff even real? Is protecting guests from
hosts actually possible in the end?
" Most of the ensuing discussion,
though, was focused on what the appropriate response should be.
Outside of the confidential-computing use case, the consensus seems to be that little needs to be done. Adding a warning if RDSEED or RDRAND fail (as Shutemov proposed at the beginning of the discussion) is being considered, but even that is not clearly the right thing to do. Many systems run with panic_on_warn enabled; on such systems, a warning will cause a system crash. That would turn a random-number-generator failure into a denial-of-service problem. Even in this case, though, a failure during early boot seems worth a warning; if that happens, either the random-number-generator is simply broken, or there is clearly some sort of attack underway.
When the system is running in a confidential-computing mode, though, the situation is a bit more complicated. Among other things, that is not a mode that the kernel as a whole recognizes; Ts'o suggested adding a global flag for this purpose, since other parts of the kernel are eventually likely to need it as well. But, even with that in place, there are a number of alternatives to consider; Donenfeld spelled them out in detail. They come down to whether the kernel should warn (or panic) on failure, whether that should happen at any time or only during early boot, and whether this response should change in "confidential-computing mode".
The emerging consensus would seem to be that the first step is simply retrying a failing operation, as is already done for RDRAND. Even if a single RDRAND can be made to fail, doing so ten times in a row is a more difficult prospect. That said, one should remember that, as Reshetova pointed out, the host controls a guest's scheduling and could, in theory, interfere with a retry loop as well. If retries are forced to happen when the random-number generator is exhausted, they will never succeed.
At a minimum, a warning should be issued if these instructions fail during early boot, since that is a clear sign that something is going wrong. For the confidential-computing case, a randomness failure means that the system is unable to provide the guarantees upon which the whole edifice is built, so the system should simply refuse to run. That could be achieved with a panic, or by simply looping on RDRAND indefinitely, locking up the virtual machine if the instruction never succeeds.
Beyond that, there is not a whole lot that needs to be done.
There is one part of the discussion that is not visible, though: this concern seems to have created a scramble within the CPU vendors to characterize the extent of the problem and figure out what, if anything, needs to be done about it. Lest one think this is an Intel-specific issue, Berrangé reported the ability to force high failure rates on some AMD processors as well. The outcome of those discussions may be some combination of documentation, microcode updates, and design changes in future processors.
Meanwhile, the prospect of random-number-generator exhaustion need not be a
big worry for most users; it seems unlikely that it can be used to threaten
real-world systems. For the confidential-computing crowd, it is just
another one of what is sure to be an unending list of potential threats
that need to be mitigated. Fixes will be put into place, and we can all
put our pitchforks away and go back to watching the argument over whether
confidential computing is achievable in the first place.
Index entries for this article | |
---|---|
Kernel | Architectures/x86 |
Kernel | Confidential computing |
Kernel | Random numbers |
Security | Linux kernel/Random number generation |
Posted Feb 8, 2024 18:27 UTC (Thu)
by dullfire (guest, #111432)
[Link] (6 responses)
Sorry but this is a bad statement. The if the system is running with panic_on_warn then the system has explicitly been told to panic (effectively go offline) on a warning event. Which means that it can't be a "denial-of-service" when it is behaving exactly the way the admins[0] requested. Additionally, panic_on_warn turns any ability to generate warnings into a DoS by that definition.
Would you call an admin ssh-ing in running a "sudo reboot" a "denial of service". If so, that makes the term so broad as to be useless.
Further more: If this is occurring after a retry loop of 10 (which, if I did my math right, has less than a 0.001% chance of happening if a 'normal' RDSEED has a failure rate of 30%), then most likely the best case is someone is simply probing you system (or your host) for weaknesses. In the worst case, there's an actual attack in progress. Immediately an panic might be the correct response.
[0] Alternately a non-"admin" managed to control your kernel command line (or equivalent), but if that is the case, you have other, very different, and much worse problems.
Posted Feb 8, 2024 18:29 UTC (Thu)
by corbet (editor, #1)
[Link]
Posted Feb 9, 2024 0:08 UTC (Fri)
by Jannes (subscriber, #80396)
[Link] (1 responses)
A misbehaving app should just crash itself, not bring down the entire kernel and thereby DOSsing all other apps.
Posted Feb 24, 2024 15:14 UTC (Sat)
by DanilaBerezin (guest, #168271)
[Link]
Posted Feb 9, 2024 10:42 UTC (Fri)
by taladar (subscriber, #68407)
[Link] (1 responses)
Posted Feb 9, 2024 13:58 UTC (Fri)
by dullfire (guest, #111432)
[Link]
I think you MIGHT be able to maintain that probably format, if there's a change (possibly delays) you can make to make the next RDSEED mostly unrelated to the first. Also note that isn't not necessary to try accounting for things like another thread attempting to drain entropy (since that would be an attack, in which case a warning, or panic if panic_on_warn, is a perfectly sane response)
IF that's possible[0], then you just need to pick a loop count that makes the likelyhood of successive failures unreasonably small.
Although, honestly I think the sanest course of action would simply to dedicated hardware (that requires privilege to access to use) in the non-cloud case. In my humble opinion the whole notion of confidential cloud compute is intractable, so I have no proposed solutions for it .
[0] I think it should be, but have no proof.
Posted Feb 10, 2024 15:26 UTC (Sat)
by mathstuf (subscriber, #69389)
[Link]
That sounds like you're assuming events are independent. I feel like there's some level of dependence when one is right after another (i.e., failures will cluster).
Posted Feb 8, 2024 19:24 UTC (Thu)
by vstinner (subscriber, #42675)
[Link]
"Result on my i7-11850H: RDRAND: 100.00%, RDSEED: 29.26%"
So RDRAND has a success rate of 100% (and 0% failure), and RDSEED has a success rate of 29.26% which means around 70% of failure, no?
Posted Feb 8, 2024 19:24 UTC (Thu)
by corsac (subscriber, #49696)
[Link] (1 responses)
Posted Feb 9, 2024 10:12 UTC (Fri)
by adobriyan (subscriber, #30858)
[Link]
Posted Feb 9, 2024 9:44 UTC (Fri)
by james (subscriber, #1325)
[Link]
Posted Feb 9, 2024 11:37 UTC (Fri)
by spacefrogg (subscriber, #119608)
[Link] (12 responses)
Any expectation that the OS can just assume (or even assert) that it is an error that a TRNG fails at some point, is severely misguided.
I can even deliver a mathematical argument if you desire. Any functionality test of a TRNG must restrict itself to use a limited amount of TRNG output to draw its conclusion. Otherwise it would never finish. Any TRNG must eventually produce a sequence, by chance(!), that contradicts the functionality test. Otherwise it would not be completely random, because it would specifically avoid the test patterns. Conclusion: Every TRNG that does not fail from time to time is already failing.
Yes you can shift the probabilities etc. pp., but you cannot avoid the fundamental mechanics. By delivering billions of CPUs each running for thousands of hours, you will find those instances.
Posted Feb 9, 2024 12:18 UTC (Fri)
by zx2c4 (subscriber, #82519)
[Link] (4 responses)
Posted Feb 9, 2024 12:42 UTC (Fri)
by spacefrogg (subscriber, #119608)
[Link] (3 responses)
Cross-domain fairness seems to be hard to achieve when I think about it, especially because entropy is such a scarce resource. Access to the entropy source should be exclusive to the kernel(s). Applications should have to make due with derived PRNG values. But I am just thinking out loud...
Posted Feb 9, 2024 12:59 UTC (Fri)
by spacefrogg (subscriber, #119608)
[Link] (2 responses)
Posted Feb 9, 2024 13:28 UTC (Fri)
by zx2c4 (subscriber, #82519)
[Link] (1 responses)
Posted Feb 9, 2024 14:31 UTC (Fri)
by spacefrogg (subscriber, #119608)
[Link]
Daniel J. Bernstein has an excellent write-up about how you could potentially mis-use an entropy source to force your encryption scheme to leak your private key alongside your ciphertext while making it look perfectly fine. I just fail to find it right now. (It was concentrating on why encryption schemes should not mindlessly access entropy)
The argument is quite simple: You do know how the encryption scheme distributes bits. If you control the entropy bits and the encryption scheme, you can hide the private key in the entropy bits and make the ciphertext partially predictable, enough to recover the private key and thus the original message.
Posted Feb 9, 2024 12:30 UTC (Fri)
by smurf (subscriber, #17840)
[Link] (2 responses)
Posted Feb 9, 2024 12:47 UTC (Fri)
by spacefrogg (subscriber, #119608)
[Link]
If you really must and invest a lot of money, the best you can currently achieve is the quality level (very high), speed (kbit/s), chip size (10mm^2) and usage intervals (<100 per day) of smartcards.
Posted Feb 9, 2024 12:52 UTC (Fri)
by Wol (subscriber, #4433)
[Link]
Cheers,
Posted Feb 9, 2024 13:43 UTC (Fri)
by epa (subscriber, #39769)
[Link] (1 responses)
Posted Feb 9, 2024 14:31 UTC (Fri)
by corbet (editor, #1)
[Link]
Posted Feb 9, 2024 14:01 UTC (Fri)
by DemiMarie (subscriber, #164188)
[Link]
The problem is that there is usually very little software can do to handle that failure.
Many random number generation APIs are infallible: they promise to always succeed. Always. The simplest way for software to handle this is to busy-spin until success. If the RNG is working, this succeeds with probability 1, and the likelihood of more retry loops being needed decreases exponentially with time. I’d much rather have RDAND use a CSPRNG like Fortuna that never runs out of entropy once seeded, block the boot until the RNG is seeded, and reseed with entropy from the TRNG whenever possible. Fortuna is designed to be secure even if the new entropy is malicious, so one can feed raw output from the TRNG without any further conditioning. Entropy estimation is then only needed to determine when, and if, RDRAND needs to block. There would be no error returns for software to check: if the TRNG is not working for long enough, you get a machine check exception.
Posted Feb 9, 2024 14:22 UTC (Fri)
by khim (subscriber, #9252)
[Link]
Nope. Or, rather: technically yes, practically no. You are forgetting one fundamental truth: there's non-zero probability (around 10⁻¹² or something like that) that anything at all would fail in a computer. Even simple Why should it fail significantly more often than once per 10¹² calls, though? That is the question and I don't see why that would be the case. We ignore probabilities smaller than these (simply because we don't really, have much choice) and if we do that than making non-fallible (in a practical sense) TRNG should be possible.
Posted Feb 9, 2024 16:54 UTC (Fri)
by zx2c4 (subscriber, #82519)
[Link]
Posted Feb 13, 2024 4:49 UTC (Tue)
by jcm (subscriber, #18262)
[Link]
Pitchforks for RDSEED
Yes, the system is behaving as configured in that setting. Still, developers need to be (and are) aware that issuing warnings can have that effect in a fairly wide swath of deployed systems and consider warnings carefully.
panic_on_warn
Pitchforks for RDSEED
Pitchforks for RDSEED
Pitchforks for RDSEED
Pitchforks for RDSEED
Pitchforks for RDSEED
Pitchforks for RDSEED
Pitchforks for RDSEED
Pitchforks for RDSEED
Pitchforks for RDSEED
...the host controls a guest's scheduling and could, in theory, interfere with a retry loop as well. If retries are forced to happen when the random-number generator is exhausted, they will never succeed.
Or the host could just never let the guest run? Same effect?
Pitchforks for RDSEED
Pitchforks for RDSEED
Pitchforks for RDSEED
Pitchforks for RDSEED
These are unprivileged CPU instructions. This isn't a kernel scheduler issue.
Pitchforks for RDSEED
Pitchforks for RDSEED
Pitchforks for RDSEED
Pitchforks for RDSEED
Pitchforks for RDSEED
Wol
Pitchforks for RDSEED
The RD* instructions do not fail silently; the CPU sets the carry flag to indicate whether they succeed or not.
Instruction failure
Pitchforks for RDSEED
> I have worked in the field of hardware true random number generation and I can tell you with confidence: However you build a system that contains a TRNG, you will always find a significant amount of instances in which the TRNG will fail at some point.
Pitchforks for RDSEED
jz test_passed
may jump to a wrong place once-in-a-while.Pitchforks for RDSEED
Pitchforks for RDSEED