Avoid UB (member call on nullptr) when failing to read randomness in the startup process #15111

pull practicalswift wants to merge 1 commits into bitcoin:master from practicalswift:random-ub changing 1 files +13 −8
  1. practicalswift commented at 9:10 PM on January 5, 2019: contributor

    Avoid UB (member call on nullptr) when failing to read randomness in the startup process.

    RandFailure is called by GetDevURandom, GetOSRand and GetRandBytes when failing to read randomness for some reason.

    This is RandFailure:

    [[noreturn]] static void RandFailure()
    {
        LogPrintf("Failed to read randomness, aborting\n");
        std::abort();
    }
    

    This is LogPrintf:

    template <typename... Args>
    static inline void LogPrintf(const char* fmt, const Args&... args)
    {
        if (g_logger->Enabled()) {
            …
        }
    }
    

    Compilers are allowed to optimise away calls to RandFailure that are guaranteed to take place when g_logger == nullptr. Please note that such optimisation would remove the crucial std::abort call in RandFailure.

    Failing to read randomness before this patch (under UBSan):

    $ src/bitcoind
    logging.h:135:19: runtime error: member call on null pointer of type 'BCLog::Logger'
    <undefined behaviour>
    

    Failing to read randomness after this patch (under UBSan):

    $ src/bitcoind
    Failed to read randomness, aborting
    $
    
  2. Avoid UB (member call on nullptr) when failing to generate randomness in the startup process 72c81f828b
  3. MarcoFalke commented at 10:17 PM on January 5, 2019: member

    I fail to see how g_logger could be a nullptr. It is well-defined for the whole duration of main.

    About the randomness failure: We should probably not consume bytes before we did a RandomInit()?

    Could you clarify how this is happening and maybe include steps to reproduce?

  4. practicalswift renamed this:
    Avoid UB (member call on nullptr) when failing to read randomness in the startup process
    Avoid UB (member call on nullptr) when failing to read randomness in the startup process when logging is not yet initialised
    on Jan 5, 2019
  5. sipa commented at 10:38 PM on January 5, 2019: member

    @MarcoFalke After #14955 the initialization of the RNG happens on first use, even before calling RandomInit().

  6. practicalswift renamed this:
    Avoid UB (member call on nullptr) when failing to read randomness in the startup process when logging is not yet initialised
    Avoid UB (member call on nullptr) when failing to read randomness in the startup process
    on Jan 5, 2019
  7. practicalswift commented at 10:44 PM on January 5, 2019: contributor

    @MarcoFalke Consider the case when the PRNG has not been seeded with enough randomness to ensure an unpredictable byte sequence. RAND_bytes() will then return 0.

    Give me a few minutes I'll get back with the exact steps to reproduce.

  8. practicalswift commented at 11:02 PM on January 5, 2019: contributor

    @MarcoFalke

    Steps to reproduce:

    $ git clone https://github.com/bitcoin/bitcoin
    $ cd bitcoin
    $ ./autogen.sh
    $ CC=clang CXX=clang++ ./configure --with-sanitizers=undefined
    $ git apply
    diff --git a/src/random.cpp b/src/random.cpp
    index f8ffda136..a3f84798d 100644
    --- a/src/random.cpp
    +++ b/src/random.cpp
    @@ -274,7 +274,7 @@ void GetOSRand(unsigned char *ent32)
    
     void GetRandBytes(unsigned char* buf, int num)
     {
    -    if (RAND_bytes(buf, num) != 1) {
    +    if (true) {
             RandFailure();
         }
     }
    $ make
    $ UBSAN_OPTIONS="halt_on_error=1:print_stacktrace=1" src/bitcoind
    logging.h:135:19: runtime error: member call on null pointer of type 'BCLog::Logger'
        [#0](/bitcoin-bitcoin/0/) 0x564eac67cff2 in void LogPrintf<>(char const*) /.../bitcoin/src/./logging.h:135:19
        [#1](/bitcoin-bitcoin/1/) 0x564eac67c054 in RandFailure() /.../bitcoin/src/random.cpp:53:5
        [#2](/bitcoin-bitcoin/2/) 0x564eac67c07d in GetRandBytes(unsigned char*, int) /.../bitcoin/src/random.cpp:278:9
        [#3](/bitcoin-bitcoin/3/) 0x564eabc15be7 in (anonymous namespace)::CSignatureCache::CSignatureCache() /.../bitcoin/src/script/sigcache.cpp:35:9
        [#4](/bitcoin-bitcoin/4/) 0x564eabc15be7 in __cxx_global_var_init.8 /.../bitcoin/src/script/sigcache.cpp:68
        [#5](/bitcoin-bitcoin/5/) 0x564eabc15be7 in _GLOBAL__sub_I_sigcache.cpp /.../bitcoin/src/script/sigcache.cpp
        [#6](/bitcoin-bitcoin/6/) 0x564eac8125cc in __libc_csu_init (/.../bitcoin/src/bitcoind+0x22185cc)
        [#7](/bitcoin-bitcoin/7/) 0x7f522eaa8b27 in __libc_start_main /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:266
        [#8](/bitcoin-bitcoin/8/) 0x564eabc201d9 in _start (/.../bitcoin/src/bitcoind+0x16261d9)
    

    Please note: before main.

    That answers the raised questions?

  9. practicalswift commented at 12:23 AM on January 6, 2019: contributor

    @MarcoFalke @sipa These are places I've identified (so far) where randomness is requested before main:

    1. CSignatureCache ctor (src/script/sigcache.cpp): Calls GetRandBytes(nonce.begin(), 32)

    2. SaltedTxidHasher ctor (src/txmempool.cpp): Calls GetRand(std::numeric_limits<uint64_t>::{min,max}()) which calls GetRandBytes(…)

    3. static uint256 scriptExecutionCacheNonce(GetRandHash()); (src/validation.cpp): Calls GetRandHash() which calls GetRandBytes((…)

  10. MarcoFalke commented at 12:28 PM on January 6, 2019: member

    It seems odd that we need those globals (e.g. the mempool) before main even starts. They should probably be initialized later.

  11. practicalswift commented at 3:36 PM on January 6, 2019: contributor

    @MarcoFalke That would be nice. And LogPrintf(…) should be robust and handle also callers who happen to call it before main, right?

  12. sipa commented at 3:41 PM on January 6, 2019: member

    There are generally two ways of dealing with initialization order of globals. One is to make all globals unique_ptrs or otherwise non-instantiated at startup and explicitly create all. Another approach is using std::call_once or static locals like #14955 does.

    Since C++11 the second can be done with pretty low overhead and without too big hoops, so that's my preference over explicit initialization as it's less fragile.

  13. practicalswift commented at 3:49 PM on January 6, 2019: contributor

    @sipa Do you agree that LogPrintf(…) should be robust and handle also callers who happen to call it before main?

  14. gmaxwell commented at 11:18 PM on January 6, 2019: contributor

    What is even the point of g_logger in the first place? It seems to serve no purpose except creating UB when logging is called by global constructors. I propose instead PR#12954 be reverted: It served no obvious purpose and instead introduced a potentially serious misbehaviour.

  15. practicalswift commented at 9:36 PM on January 17, 2019: contributor

    @MarcoFalke Could this one get a release milestone? :-)

  16. DrahtBot commented at 8:29 PM on January 29, 2019: member

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #15266 (memory: Construct globals on first use by MarcoFalke)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

  17. practicalswift commented at 8:13 PM on February 1, 2019: contributor

    Closing in favour of @MarcoFalke's better fix in #15266. Thanks!

  18. practicalswift closed this on Feb 1, 2019

  19. MarcoFalke referenced this in commit 452acee4da on Feb 4, 2019
  20. practicalswift deleted the branch on Apr 10, 2021
  21. vijaydasmp referenced this in commit 0d276489a9 on Sep 12, 2021
  22. vijaydasmp referenced this in commit 922972dd32 on Sep 12, 2021
  23. vijaydasmp referenced this in commit c9c082553c on Sep 13, 2021
  24. vijaydasmp referenced this in commit b9f2bef379 on Sep 13, 2021
  25. vijaydasmp referenced this in commit 5b5537b8f4 on Sep 14, 2021
  26. vijaydasmp referenced this in commit bcbf3388d1 on Sep 14, 2021
  27. vijaydasmp referenced this in commit 15f14806a8 on Sep 16, 2021
  28. gades referenced this in commit 722b548343 on Apr 30, 2022
  29. DrahtBot locked this on Aug 18, 2022

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 18:15 UTC

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