util: Specific GetOSRandom for Linux/FreeBSD/OpenBSD #9821

pull laanwj wants to merge 4 commits into bitcoin:master from laanwj:2017_02_osrandom changing 6 files +174 −11
  1. laanwj commented at 8:07 PM on February 21, 2017: member

    These are available in sandboxes without access to files or to devices. Also they are considered safer and more straightforward to use than /dev/urandom as reading from a file has quite a few edge cases:

    • Linux: getrandom(buf, buflen, 0). getrandom(2) was introduced in version 3.17 of the Linux kernel.
    • OpenBSD: getentropy(buf, buflen). The getentropy(2) function appeared in OpenBSD 5.6.
    • FreeBSD and NetBSD: sysctl(KERN_ARND). Not sure when this was added but it has existed for quite a while.

    Alternatives:

    • Linux has sysctl CTL_KERN / KERN_RANDOM / RANDOM_UUID which gives 16 bytes of randomness. This may be available on older kernels, however sysctl is deprecated on Linux and even removed in some distros so we shouldn't use it.

    Add tests for GetOSRand():

    • Test that no error happens (otherwise RandFailure() which aborts)
    • Test that all 32 bytes are overwritten (initialize with zeros, try multiple times)

    Discussion:

    • When to use these? Currently they are always used when available. Another option would be to use them only when /dev/urandom is not available. But this would mean these code paths receive less testing, and I'm not sure there is any reason to prefer /dev/urandom.

    Closes: #9676. I've tested this on all three OS-es.

  2. util: Specific GetOSRandom for Linux/FreeBSD/OpenBSD
    These are available in sandboxes without access to files or
    devices. Also [they are safer and more straightforward](https://en.wikipedia.org/wiki/Entropy-supplying_system_calls)
    to use than `/dev/urandom` as reading from a file has quite a few edge
    cases:
    
    - Linux: `getrandom(buf, buflen, 0)`. [getrandom(2)](http://man7.org/linux/man-pages/man2/getrandom.2.html)
      was introduced in version 3.17 of the Linux kernel.
    - OpenBSD: `getentropy(buf, buflen)`. The [getentropy(2)](http://man.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man2/getentropy.2)
      function appeared in OpenBSD 5.6.
    - FreeBSD and NetBSD: `sysctl(KERN_ARND)`. Not sure when this was added
      but it has existed for quite a while.
    
    Alternatives:
    
    - Linux has sysctl `CTL_KERN` / `KERN_RANDOM` / `RANDOM_UUID`
      which gives 16 bytes of randomness. This may be available
      on older kernels, however [sysctl is deprecated on Linux](https://lwn.net/Articles/605392/)
      and even removed in some distros so we shouldn't use it.
    
    Add tests for `GetOSRand()`:
    
    - Test that no error happens (otherwise `RandFailure()` which aborts)
    - Test that all 32 bytes are overwritten (initialize with zeros, try multiple times)
    
    Discussion:
    
    - When to use these? Currently they are always used when available.
      Another option would be to use them only when `/dev/urandom` is not
      available. But this would mean these code paths receive less testing,
      and I'm not sure there is any reason to prefer `/dev/urandom`.
    
    Closes: #9676
    224e6eb089
  3. laanwj added the label Utils and libraries on Feb 21, 2017
  4. gmaxwell commented at 8:11 PM on February 21, 2017: contributor

    Concept ACK. I think this should use a runtime test case at init, not just a boost testcase-- code may be built on a system where it works but run elsewhere and this is too important to mess up. :)

  5. laanwj commented at 8:12 PM on February 21, 2017: member

    I'm OK with adding this to the sanity checks, but in all fairness we don't check that for /dev/urandom either, we used to not even have a boost testcase for this code path. Also a failure while reading randomness will already always trigger a fatal abort.

  6. sipa commented at 8:20 PM on February 21, 2017: member

    I think getrandom if available should be preferred over using /dev/urandom. While a local root access can both replace /dev/urandom with something else or intercept getrandom calls, I expect the latter to require more invasive/detectable changes.

  7. sipa commented at 8:56 PM on February 21, 2017: member

    ~Two questions:~

    • ~What if you're using a 2.25 or later glibc (which has the getrandom function), but your Linux kernel is pre-3.17 (which does not have the syscall)? I have a hard time fnding information about this in the glibc documentation. Either it simulates it by reading /dev/urandom instead, or it fails. If the actual behavior is to fail, we should probably fall back to reading /dev/urandom at runtime rather than at compile time.~
    • ~Given that our release binaries should probably not be required to work only on post-2.25 glibc, with this patch we can't compile release binaries against a post-2.25 glibc...~

    Nevermind, it seems you're using the syscall directly.

  8. gmaxwell commented at 9:01 PM on February 21, 2017: contributor

    but in all fairness we don't check that for /dev/urandom either,

    Yes but we don't have an issue there where there are older kernels that don't have the functionality... (Also, I would be of the view that we should have a runtime test currently too-- but I didn't want to bloat up the original PR that added this.)

  9. theuni commented at 10:40 PM on February 21, 2017: member

    Concept ACK. utACK on the build changes in particular.

  10. in src/random.cpp:None in 224e6eb089 outdated
     123 | +    /* Linux. From the getrandom(2) man page:
     124 | +     * "If the urandom source has been initialized, reads of up to 256 bytes
     125 | +     * will always return as many bytes as requested and will not be
     126 | +     * interrupted by signals."
     127 | +     */
     128 | +    if (syscall(SYS_getrandom, ent32, NUM_OS_RANDOM_BYTES, 0) != NUM_OS_RANDOM_BYTES) {
    


    theuni commented at 10:46 PM on February 21, 2017:

    Does this not need the GRND_BLOCK flag? I think we want this blocking rather than returning /dev/random data, no?


    laanwj commented at 6:27 AM on February 22, 2017:

    According to the man page there is no GRND_BLOCK flag, just a GRND_NONBLOCK flag, which is only significant when passing GRND_RANDOM (which selects /dev/random) too. In that mode, it means EAGAIN can be returned if there is not enough entropy.

    In /dev/urandom mode it will never block. When requesting <= 256 bytes it will not even be interruptable by a signal.


    theuni commented at 6:50 AM on February 22, 2017:

    Thanks for clarifying. When I searched for the kernel implementation, I landed on https://lwn.net/Articles/605828/, which I guess was an early draft of getrandom with the flag reversed. Carry on :)

  11. laanwj commented at 6:22 AM on February 22, 2017: member

    Nevermind, it seems you're using the syscall directly.

    Well it still makes sense. On Linux, syscalls that are not implemented will predictably return an error w/ errno ENOSYS. We want to support older kernels (3.16 isn't that old - 2014) so need to handle this and fall back to /dev/urandom. Currently it will crash with a "randomness error" on those platforms [but only if compiled with kernel headers that did have the syscall]. Edit: added

  12. squashme: comment that NUM_OS_RANDOM_BYTES should not be changed lightly aa09ccbb74
  13. sanity: Move OS random to sanity check function
    Move the OS random test to a sanity check function that is called every
    time bitcoind is initialized.
    
    Keep `src/test/random_tests.cpp` for the case that later random tests
    are added, and keep a rudimentary test that just calls the sanity check.
    7cad849299
  14. random: Add fallback if getrandom syscall not available
    If the code was compiled with newer (>=3.17) kernel headers but executed
    on a system without the system call, every use of random would crash the
    program. Add a fallback for that case.
    7e6dcd9995
  15. sipa commented at 11:45 PM on February 23, 2017: member

    ~@laanwj It seems that Debian Jessie (stable) ships with Linux kernel 3.16, right before 3.17 which introduced getrandom(). That means that a binary compiled on a system with a >=3.17 kernel won't run on Jessie anymore, at all. I think we should prefer trying to call getrandom(), but if it fails, fall back to reading /dev/urandom.~

    It seems I'm consistently commenting on old states of this PR.

  16. sipa commented at 3:42 AM on February 24, 2017: member

    utACK 7e6dcd9995b99e894b8017f09016c405b066ca36

    It seems none of the new methods are available on OSX (or at least in the build environment in Travis), but a new method can be added later.

  17. laanwj commented at 7:36 AM on February 24, 2017: member

    It seems none of the new methods are available on OSX (or at least in the build environment in Travis), but a new method can be added later.

    It may well be that OSX has no way to read kernel randomness besides /dev/urandom. We checked and their own frameworks use that, and nothing else. But yes someone with more knowledge about OSX could take a look at that later.

  18. jameshilliard commented at 7:18 PM on February 25, 2017: contributor

    Libressl has getentropy emulation for a number of different OS's that may be useful as a reference.

  19. laanwj commented at 11:41 AM on March 1, 2017: member

    Libressl has getentropy emulation for a number of different OS's that may be useful as a reference.

    Thanks. That source confirms that there is no other way besides using /dev/urandom in OSX.

  20. laanwj merged this on Mar 1, 2017
  21. laanwj closed this on Mar 1, 2017

  22. laanwj referenced this in commit d19d45a1e6 on Mar 1, 2017
  23. laanwj commented at 6:00 PM on April 1, 2017: member

    Thanks. That source confirms that there is no other way besides using /dev/urandom in OSX.

    While digging around I found that OSX 10.12+ does have getentropy, however it seems to be defined in sys/random.h instead of unistd.h as in OpenBSD:

    __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0)
    int getentropy(void* buffer, size_t size);
    

    Example:

    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/random.h>
    
    int main()
    {
        unsigned char buf[32];
        if (getentropy(buf, sizeof(buf)) < 0) {
            return 1;
        }
        write(STDOUT_FILENO, buf, sizeof(buf));
        return 0;
    }
    

    I'm not sure how to make autoconf detect something that may be in different headers.

  24. laanwj referenced this in commit 318392ca7c on Aug 7, 2017
  25. mempko referenced this in commit d1c8cac9f7 on Sep 28, 2017
  26. PastaPastaPasta referenced this in commit 6c4394ab03 on Dec 28, 2018
  27. PastaPastaPasta referenced this in commit 89fa0f134d on Dec 29, 2018
  28. PastaPastaPasta referenced this in commit 8002429b30 on Dec 29, 2018
  29. PastaPastaPasta referenced this in commit 52dcace111 on Dec 29, 2018
  30. PastaPastaPasta referenced this in commit 37798ac9b6 on Dec 29, 2018
  31. PastaPastaPasta referenced this in commit 95826d5fca on Dec 31, 2018
  32. PastaPastaPasta referenced this in commit 215c5df4f9 on Dec 31, 2018
  33. PastaPastaPasta referenced this in commit b3e38ad1de on Jan 2, 2019
  34. PastaPastaPasta referenced this in commit 98da3902e4 on Jan 2, 2019
  35. PastaPastaPasta referenced this in commit efd708bf1f on Jan 3, 2019
  36. PastaPastaPasta referenced this in commit 9966c4227c on Jan 3, 2019
  37. PastaPastaPasta referenced this in commit 31717f54d5 on Jan 5, 2019
  38. PastaPastaPasta referenced this in commit 079c802188 on Jan 5, 2019
  39. PastaPastaPasta referenced this in commit d47dfbe87d on Jan 7, 2019
  40. PastaPastaPasta referenced this in commit 6054817d1d on Jan 7, 2019
  41. PastaPastaPasta referenced this in commit 1f2a893200 on Jan 7, 2019
  42. PastaPastaPasta referenced this in commit 1f0f0b608f on Jan 7, 2019
  43. PastaPastaPasta referenced this in commit 21e00e9050 on Jan 23, 2019
  44. PastaPastaPasta referenced this in commit 2df84c6f16 on Jan 23, 2019
  45. PastaPastaPasta referenced this in commit 3ac30e5438 on Jan 25, 2019
  46. PastaPastaPasta referenced this in commit df744a78b8 on Jan 25, 2019
  47. PastaPastaPasta referenced this in commit 52aef4cfec on Aug 2, 2019
  48. PastaPastaPasta referenced this in commit 2a295be586 on Aug 6, 2019
  49. charlesrocket referenced this in commit 0b12bcd035 on Nov 29, 2019
  50. barrystyle referenced this in commit be6fb4e218 on Jan 22, 2020
  51. MarcoFalke locked this on Sep 8, 2021

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-04-13 15:15 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me