[HN Gopher] Linux RNG RFC Patch: implement getrandom() in vDSO
       ___________________________________________________________________
        
       Linux RNG RFC Patch: implement getrandom() in vDSO
        
       Author : zx2c4
       Score  : 72 points
       Date   : 2022-07-29 16:32 UTC (6 hours ago)
        
 (HTM) web link (lore.kernel.org)
 (TXT) w3m dump (lore.kernel.org)
        
       | 10000truths wrote:
       | Why not just have the kernel map a page containing random bytes,
       | that it rewrites with newly seeded random bytes when needed? Then
       | userspace CSPRNGs could use that as a basis for their own
       | reseeding.
        
         | quesomaster9000 wrote:
         | How often do you reseed?
         | 
         | How frequently does the kernel populate these pages with new
         | entropy (for every process, pre-emptively?)
         | 
         | Does this avoid pagefaults or other process interrupts? Don't
         | want process interrupting every time it accesses the 'magic
         | page of random'.
         | 
         | Surely these are all pain points that Intel's `RDRAND` is
         | supposed to alleviate.
        
       | mjb wrote:
       | Making providing high-quality randomness without compromises a
       | first-class OS feature seems like a great idea. Especially
       | because it reduces the chances of using a bad/incorrectly
       | seeded/inadequately seeded/cloned from snapshot userspace
       | cryptographic PRNG, and of using a non-cryptographic PRNG for
       | cryptographic stuff.
       | 
       | I'm a kernel expert, so I don't know if VDSO is the right
       | implementation, but the idea seems sound. Make it harder for
       | people to make mistakes that break security!
        
         | mjb wrote:
         | To clarify, I am _not_ a kernel expert.
        
       | marcodiego wrote:
       | For those who need it: vDSO is almost a hack that allows
       | implementation of syscalls without context switch.
        
         | onmobile2022 wrote:
         | Slightly more verbose: it is an ELF library that is mapped into
         | every process containing kernel code that runs (due to app
         | calls) in userspace. Most often it works (like in the case of
         | gettimeofday) by reading values from another shared memory
         | segment mapped between the kernel and user space. Getting time
         | just involves carefully ordered reading from that shared mem
        
       | colmmacc wrote:
       | This change makes me sad, not because it isn't brilliant work -
       | it is - but because this kind of brilliant work is unlikely to
       | move the needle in the real-world. I can't use this RNG because
       | it isn't FIPS validated. I can't sponsor getting it FIPS
       | validated because the cryptography it uses isn't even FIPS
       | compatible. It wouldn't make it past the cursory skim of a
       | reviewer. That says more about FIPS than it does this work, but
       | it still means that it's a non-starter for many libraries and
       | applications that end up having US Federal Government users ...
       | which is to say that basically everything important gets pushed
       | away from benefiting from work like this.
       | 
       | Seperately, I'm also a little sad that there are no distinct RNGs
       | for secret and non-secret output. It is an indispensable layer of
       | defense to have separately seeded RNGs for these use-cases. That
       | way if there is an implementation flaw or bug in the RNG that
       | leads to re-use or predictability, it is vastly harder for that
       | flaw to be abused. s2n, BouncyCastle, OpenSSL, and more user-
       | space libraries use separately seeded RNGs for this reason and I
       | don't think I could justify removing that protection.
        
         | fweimer wrote:
         | I don't see why this couldn't be validated if an approved DRBG
         | is used instead.
        
         | staticassertion wrote:
         | > That says more about FIPS than it does this work
         | 
         | It would be nice to have companies collectively reject FIPS. I
         | realize that that's a pipe dream, but we do it with patents.
         | Lots of companies pool their patents to defend against trolls
         | on the condition that none of those companies sue each other
         | over patent violations.
         | 
         | If a bunch of companies were like "We won't require you to be
         | FIPS, and we won't get FIPS" or something that'd be cool.
         | Unfortunately, that can't happen with FIPS specifically as it's
         | government mandated, but idk, maybe SOC2 or something?
         | 
         | I hate things so much
        
         | yjftsjthsd-h wrote:
         | That's not really a fault of Linux or the 'real world', that's
         | government entities intentionally holding themselves back. I'm
         | not even saying that's a terrible thing - gov't work is a good
         | place to require audited security options! - but that's the
         | tradeoff they've chosen.
        
         | gerdesj wrote:
         | "unlikely to move the needle in the real-world"
         | 
         | FIPS does not impinge on me in any way whatsoever - that's my
         | real world and that's the real world for a darn sight larger
         | number of people than ... Americans.
         | 
         | I note your secret/non secret discussion for RNGs and that
         | seems to be a good idea - many non FIPS standards also have a
         | dichotomy like that or something more complicated. However,
         | separately seeded pools reduces the entropy available
         | (IANACryptographer) that's a trade off of some sort that I'm
         | not qualified to assess.
         | 
         | This work is done by people I respect and I will evaluate it
         | according to the standards I have to adhere to. None of those
         | standards is FIPS. I'm not quite in a cargo cult state but I
         | have to take a certain amount of things on trust when it comes
         | to this stuff!
        
         | tptacek wrote:
         | On the other hand, there's the FIPS-accelerationist
         | perspective, which suggests that as more and more modern
         | cryptography is mainstreamed irrespective of FIPS silly
         | requirements, FIPS will itself gradually become untenable,
         | leaving us all better off.
        
           | oittaa wrote:
           | I'm not a cryptographer so disregard my opinions as you
           | please, but I really like OpenSSH's approach. They just
           | implement whatever the cryptographer community thinks is the
           | best approach at the moment and disregard NIST and other
           | authorities. For example they already have a post quantum key
           | exchange as one of the default algorithms.
        
         | hinkley wrote:
         | For lower-stakes streams of random data, like such as
         | unguessable patterns in video games (or perhaps in Monte Carlo
         | simulations for a Chess or Go engine), CSPRNGs are a common
         | solution here.
         | 
         | You bite off a chunk of data from the RNG and use it as the
         | seed for a sequence based on a cryptographic hash, relying on
         | the non-repeating qualities of these algorithms to give you a
         | convincing random data stream that is not necessarily suitable
         | for generating cryptographic keys.
         | 
         | The problem here, if there is one, is that if you implemented
         | your RNG source as just reading from a file descriptor, the
         | subsequent bite of that proverbial sandwich gets the entire
         | tomato slice and most of the lettuce. If the language you
         | picked already abstracts /dev/random, then it's just a couple
         | lines of code difference for you. If not, well then welcome to
         | the wide world of cryptography APIs, friend.
        
         | cesarb wrote:
         | > I can't use this RNG because it isn't FIPS validated. I can't
         | sponsor getting it FIPS validated because the cryptography it
         | uses isn't even FIPS compatible. It wouldn't make it past the
         | cursory skim of a reviewer. [...] but it still means that it's
         | a non-starter for many libraries and applications that end up
         | having US Federal Government users
         | 
         | But how do these user-space libraries get the entropy for their
         | RNG? If they read it from /dev/random or /dev/urandom or call
         | getrandom(), it's the _exact same algorithm_.
         | 
         | To put it another way: even though this is running in user
         | mode, it's not a user-space library; it's part of the Linux
         | kernel, which happens to be running in user mode. If for some
         | reason you need to make getrandom() use FIPS algorithms, you
         | already have to patch the kernel, and when doing so you'd patch
         | this code to match. Because this code _is_ the getrandom()
         | system call, which like a couple of other  "fast" system calls
         | like gettimeofday(), is implemented partially in user mode and
         | partially in kernel mode.
        
           | thayne wrote:
           | Possibly, it uses `/dev/random` or `/dev/urandom` to seed
           | (and periodically re-seed) a userspace implementation of a
           | FIPS validated PRNG.
        
           | fweimer wrote:
           | I expect that most vendors carry downstream kernel patches
           | with an approved algorithm, so that the kernel can still be
           | used as an entropy source.
        
           | colmmacc wrote:
           | Usually those libraries seed from a FIPS-validated hardware
           | entropy source. AES-NI is a common one, it's validated on
           | some chips, but other hardware vendors have others (we have a
           | hardware RNG in the AWS Nitro System for example). FIPS
           | specifies a handful of DRBG algorithms that can then be used.
           | AES-CTR-DRBG is the most popular. That's definitely no the
           | exact same algorithm as the ChaCha/Blake constructions in
           | Jason's work. It's all rather carefully constructed and then
           | checked as part of the validation process. This is probably
           | the most common reason for userspace RNGs in cryptographic
           | software.
        
             | cipherboy wrote:
             | Every major Linux distro ships FIPS crypto libraries that
             | seed from the Linux kernel; the source is available.
        
       | a-dub wrote:
       | > hyperspeed card shuffling
       | 
       | i think that's mostly scientific computing where you want the
       | ability to control the RNG and even intentionally use
       | deterministic seeds for reproducibility.
       | 
       | i think if the kernel is going to provide secure random numbers
       | (which seems like a good idea), it should be through a (new)
       | specific system call that fails unless a hardware entropy
       | facility is available. performance seems like a secondary goal,
       | where the primary is ensuring that people are using the right
       | thing to generate keys and such.
        
         | secondcoming wrote:
         | I think you need reproducible RNGs for financial modelling
         | audits.
        
       | comex wrote:
       | On many operating systems, including macOS and Windows, the only
       | ABI-stable interface is a userland-to-userland interface.
       | Application code loads a shared library vended by the system and
       | calls functions from that library like open() or CreateFileW(),
       | in userland. These functions are in turn are usually thin
       | wrappers around system calls with equivalent argument lists - but
       | not always, and even when they are, it's only an implementation
       | detail. Trying to call system calls directly without going
       | through the wrappers risks incompatibility with future OS
       | versions, e.g. [1].
       | 
       | On Linux, traditionally, the userland-kernel interface itself is
       | ABI-stable. The userland code can be fully custom and doesn't
       | even need to support dynamic linking. Syscall numbers and
       | arguments are fixed, and application code can perform its own
       | syscall instructions. You can then layer something like glibc on
       | top of that, which provides its own syscall wrapper functions
       | with a corresponding stable (userland-to-userland) ABI, but
       | that's separate.
       | 
       | The vDSO has always been a step away from that. It's userland
       | code, automatically mapped by the kernel, that provides its own
       | system call wrappers. Applications are still allowed to make
       | system calls manually, but they're encouraged to use the vDSO
       | instead. Its original purpose was to allow certain functions such
       | as gettimeofday() to be completed in userland rather than
       | actually performing a syscall [2], but it's been used for a few
       | other things. It's worked pretty well, but it does have the
       | drawback that statically linked binaries no longer control all of
       | the code in their address space. This, for instance, caused a
       | problem with the Go runtime [3], which expected userland code to
       | follow a certain stack discipline.
       | 
       | Anyway, this patch seems to me like a significant further step.
       | Not just putting an RNG into the vDSO, which is more complicated
       | than anything the vDSO currently does, but also essentially
       | saying that you _must_ use the vDSO 's RNG to be secure (to quote
       | the RFC, "userspace rolling its own RNG from a getrandom() seed
       | is fraught"), and explicitly choosing not to provide stable APIs
       | for custom userland RNGs to access the same entropy information.
       | 
       | I don't think that's necessarily a bad thing. It's not _that_
       | complicated, and to me, macOS ' and Windows' approach always
       | seemed more sensible in the first place. But it's a step worth
       | noting.
       | 
       | [1] https://github.com/jart/cosmopolitan/issues/426
       | 
       | [2] https://man7.org/linux/man-pages/man7/vdso.7.html
       | 
       | [3] https://marcan.st/2017/12/debugging-an-evil-go-runtime-bug/
        
         | tptacek wrote:
         | Just for the sake of clarity: the claim is that you must use
         | getrandom, somehow, to be secure, or maybe more specifically
         | "you are almost certainly not secure if you roll your own
         | CSPRNG". Even before the vDSO, I think one would have made the
         | same claim about getrandom.
        
           | comex wrote:
           | > Just for the sake of clarity: the claim is that you must
           | use getrandom, somehow, to be secure, or maybe more
           | specifically "you are almost certainly not secure if you roll
           | your own CSPRNG".
           | 
           | Right; more accurately stated, you must use the vDSO's RNG to
           | securely get random numbers _quickly_.
           | 
           | > Even before the vDSO, I think one would have made the same
           | claim about getrandom.
           | 
           | Because of VM forks. But an alternative would be to expose VM
           | fork events more explicitly to userland, so custom RNGs can
           | take them into account.
           | 
           | And I'm not sure that fixing the RNG, without providing a
           | generic way for userland code to take forks into account, is
           | enough to avoid all vulnerabilities. After all, there will
           | always be a window between generating random numbers and
           | using them. As a dumb example, suppose a DSA implementation
           | first picks a random nonce, then reads the data to be signed
           | from some external source. If the VM forks in between those
           | actions, and the two forks choose different data to be
           | signed, you're in trouble no matter how good the RNG is.
           | 
           | I said it's a dumb example because there's an obvious fix
           | (picking the nonce after the data to be signed). But as a
           | nonexpert, I'd be kind of surprised if there wasn't _some_
           | cryptographic protocol where forking midway through operation
           | is inherently insecure, and the only solution is to abort and
           | retry. Heck, couldn 't that apply to TLS?
           | 
           | Actually, I see that Jason submitted an earlier patch [1]
           | that does provide explicit fork events. I don't know whether
           | this vDSO patch is meant as a replacement or a complement.
           | 
           | [1] https://www.spinics.net/lists/linux-crypto/msg63759.html
        
       | mustache_kimono wrote:
       | Nowhere near an expert, but this seems like a bad idea?
        
         | [deleted]
        
         | zx2c4 wrote:
         | It's kind of wild, yea. I'd rather not do it. But if it's
         | between unsafe userspace implementations and this thing, this
         | thing is better. Maybe people will decide they don't care about
         | hyperspeed card shuffling or whatever else. But if they do,
         | this is an attempt to provide it safely.
        
           | deathanatos wrote:
           | > _hyperspeed card shuffling_
           | 
           | The article mentions this case too. getrandom() on my system
           | seems to return the required amount of random bits to perform
           | a shuffle of a deck in less time than my clock seems to have
           | precision for; ... that's ... too slow?
        
             | AlotOfReading wrote:
             | There are cases where you want tons of random numbers (e.g.
             | monte carlo) and the line between "good enough" and
             | "disastrously bad" is often unclear. Providing
             | cryptographic random numbers is the only possible API
             | that's both safe and generic.
             | 
             | As the post says, it's worth entertaining the idea of
             | having the kernel provide a blessed way for userspace to do
             | that, though I admit I've never personally seen a scenario
             | where RNG was truly the bottleneck. But it'd still be nice
             | to kill all the custom RNGs out there.
        
               | kzrdude wrote:
               | Don't you always want a reproducible random sequence for
               | such simulations? I.e you use getrandom for the initial
               | seed only, record it, and do the rest of your RNG state
               | in userspace code?
        
           | nneonneo wrote:
           | I guess my biggest concern here is the notion that vDSO is
           | going to manage the state in user space, if I understand
           | correctly. That seems like a big footgun.
           | 
           | If I call the getrandom system call, and it succeeds, I am
           | (pretty much) guaranteed that the results are properly random
           | no matter what state my userspace program might be in.
           | 
           | With vDSO, it seems we lose this critical guarantee. If a
           | memory corruption occurs, or my process's memory contents can
           | be disclosed somehow (easier to do against a userspace
           | process than against the kernel!), I don't have truly random
           | numbers anymore. Using a superficially similar API to the
           | system call for this seems like a really bad idea.
        
             | sophacles wrote:
             | The vDSO page is mapped without write though, just r and x.
        
             | saagarjha wrote:
             | If you have memory corruption in your process, what makes
             | you confident your program state will let you do something
             | useful with the randomness you get back from getrandom()?
        
               | nneonneo wrote:
               | I guess my concern is with "silent" memory corruption,
               | e.g. someone putting in a "bzero(state, ...)" by accident
               | and winding up with deterministic randomness. Sure, they
               | could also just as well do a "bzero(randombuf, ...)"
               | before using it but that's much easier to detect (and in
               | my head, somewhat harder to do by accident).
               | 
               | Silly mistakes like the Debian randomness bug come to
               | mind - a program can be totally well-behaved even in the
               | face of a glaring entropy failure, in a way that's hard
               | for developers to detect.
        
               | saagarjha wrote:
               | I guess? I mean, I see "something overflowed on the stack
               | and into my randomness buffer" as being similarly common
               | and about as undetectable. That's not to say we shouldn't
               | invest in making APIs that are harder to misuse even if
               | you hold them incorrectly, but I'm not sure the benefits
               | are very compelling here.
        
             | zx2c4 wrote:
             | > If a memory corruption occurs, or my process's memory
             | contents can be disclosed somehow (easier to do against a
             | userspace process than against the kernel!), I don't have
             | truly random numbers anymore.
             | 
             | Yea, that's definitely a downside of sorts. Jeffrey Walton
             | mentioned that in the glibc discussion a few days ago:
             | https://lore.kernel.org/linux-
             | crypto/CAH8yC8n2FM9uXimT71Ej0m...
             | 
             | A mitigating factor might be that if your process memory
             | leaks, then the secrets generated leak anyway, no matter
             | what generated them, so maybe not as large of a difference.
             | But of course a generator leaking means future secrets
             | potentially leak too. I suppose frequent reseeds could
             | mitigate this, just as they do for potential leaks in the
             | kernel.
             | 
             | But anyway, I agree that compromising application memory is
             | somewhat more possible than compromising kernel memory,
             | though both obviously happen.
        
       | rogers18445 wrote:
       | There is always the option to reseed userspace PRNG with with
       | getrandom() regularly. This makes userspace PRNG safe and more
       | versatile than getrandom().
        
         | LukeShu wrote:
         | The article specifically addresses why this is a bad idea.
        
           | rogers18445 wrote:
           | And it's wrong. If you initialize your own PRNG properly with
           | multiple reseeds you saturate the entropy pool of your PRNG
           | and subsequent reseeds are only relevant for ratcheting and
           | state compromise proofing.
           | 
           | This assumes you aren't starved for entropy on
           | initialization. If you are, it would imply a constrained
           | environment and you are better off using getrandom() then.
        
             | tptacek wrote:
             | There is no such thing as being "starved for entropy", once
             | you've hit whatever threshold you require for considering
             | your RNG to be seeded in the first place.
        
               | rogers18445 wrote:
               | If your PRNG state is is x bits, if you initialize it
               | with less than x bits of entropy you are starved.
               | 
               | Since you cannot know how many bits of entropy
               | getrandom() would give you and when it itself is reseeded
               | with fresh entropy, you usually have your userspace PRNG
               | sample getrandom() for some amount of time, after which
               | it is considered initialized.
        
               | amluto wrote:
               | > you usually have your userspace PRNG sample getrandom()
               | for some amount of time, after which it is considered
               | initialized.
               | 
               | Who is "you"? Calling getrandom() extra times to get
               | extra bits on the hope that the result is magically
               | better is entirely useless.
        
               | rogers18445 wrote:
               | There is no magic. If entropy got injected in between
               | getrandom() calls you get that entropy - it does not
               | matter if the entropy is cryptographically scrambled and
               | 'merged' into the kernel PRNG state.
               | 
               | All you have to do is 'merge'/'absorb' multiple
               | getrandom() results over some time t into your userspace
               | PRNG, with t big enough to allow for multiple reseeding
               | events by the kernel. You are in effect getting samples
               | of the new entries into the kernel entropy pool
               | indirectly by doing this, sampling too frequently is
               | wasteful however as you are just going to be sampling the
               | kernel CSRPNG with the same entropy in its state most of
               | the time.
               | 
               | Doing the above is actually the only way to properly seed
               | your userspace CSPRNG if your userspace CSPRNG has a
               | state larger than the kernel CSPRNG (kernel's is 512 bits
               | I believe) otherwise you will be working with a 512 bits
               | of entropy as an absolute maximum even if your CSPRNG is
               | capable of holding more, at least until reseeding (both
               | the kernel and the userspace PRNG).
        
             | jepler wrote:
             | It was the discussion of the situation with cloned virtual
             | machines that convinced me, not this.
        
         | fweimer wrote:
         | This is what the patch does. It does not handle the case of VM
         | resume yet. Fork safety is achieved through a generic mechanism
         | that any userspace generator could use. The advantage the vDSO
         | has is that it can assume that MADV_WIPEONFORK is implemented,
         | but that's about it.
         | 
         | The vDSO-based approach is certainly interesting because the
         | kernel can know exactly where randomness caches are located and
         | zap them as needed (on fork, periodically, after VM resume).
         | But if entire pages of memory are dedicated to buffers anyway,
         | MADV_WIPEONFORK is sufficient for now.
        
       | fefe23 wrote:
       | This looks like an excellent idea. I will implement support for
       | it in my libc immediately when it's available in a release
       | kernel.
       | 
       | Currently userspace has incentive to roll their own RNG stuff.
       | This removes that, which is good for everyone. The less incentive
       | you give people to write code that has already been written by
       | other, more experienced people, the better.
       | 
       | I would go even further and export the kernel ciphers via vDSO.
       | Then user space could rely on those ciphers being optimized for
       | the host CPU and side channel free instead of everybody bringing
       | their own crypto primitives. I don't think there is a good reason
       | why gnupg and openssl would bring different crypto primitives.
        
         | thadt wrote:
         | Isn't there already userspace access to the kernel's crypto
         | machinery?
         | 
         | https://www.kernel.org/doc/html/latest/crypto/userspace-if.h...
        
       ___________________________________________________________________
       (page generated 2022-07-29 23:00 UTC)