Theoretical (astronomically small) possibility of uninitialized read in GetRdRand()? #17313

issue practicalswift openend this issue on October 30, 2019
  1. practicalswift commented at 9:54 am on October 30, 2019: contributor

    From uint64_t GetRdRand() noexcept :

    https://github.com/bitcoin/bitcoin/blob/0d6b6b7c658b26810c35cb8f467157a1396ab041/src/random.cpp#L145-L150

    In the case of ten RdRand failures in a row: wouldn’t r1 be read uninitialized on L150? (If so, then the same goes for the __i386__ case a couple of lines above.)

    It should be noted that the odds of ten RdRand failures in a row are astronomically small, so I don’t think this is urgent at all. Would be nice to rule out the theoretical possibility though (if such a possibility exists).

    Friendly ping @sipa :)

  2. laanwj added the label Utils/log/libs on Oct 30, 2019
  3. laanwj commented at 10:20 am on October 30, 2019: member

    What would you want to do in this case? Terminate the program? Log a warning?

    (it’s only used as additional entropy source, so maybe even “return 0 and ignore otherwise”)

  4. practicalswift commented at 10:52 am on October 30, 2019: contributor

    @laanwj

    We could change the signature to bool GetRdRand(uint64_t& out) and make it so that callers only do the hasher.Write(… data assumed to be from RdRand …) call if GetRdRand succeeds. In other words: act like we would have done if !g_rdseed_supported in case of GetRdRand failure.

    Alternatively: as long as we keep on using it only as an additional entropy source I guess uint64_t r1 = 0; on L145 would be enough. (Obvious theoretical downside: if someone thinks GetRdRand() can be used as the only entropy source :))

  5. laanwj commented at 11:37 am on October 30, 2019: member

    if someone thinks GetRdRand() can be used as the only entropy source

    There’s plenty of other reasons why that’d be a bad idea. E.g. hardware failures. But sure, it would have to be documented.

  6. practicalswift commented at 12:01 pm on October 30, 2019: contributor

    There’s plenty of other reasons why that’d be a bad idea.

    Yes, obviously so :)

    My point was that bool GetRdRand(uint64_t& out) makes it less likely for someone to make that mistake: it would be immediately obvious from the signature that the operation could fail.

  7. laanwj commented at 12:05 pm on October 30, 2019: member
    Right, agree. We even have Optional<...> for this.
  8. practicalswift commented at 10:07 am on November 1, 2019: contributor
    Friendly ping RdRand connoisseur @gmaxwell - what do you think? :)
  9. practicalswift commented at 7:39 pm on November 10, 2019: contributor

    FWIW, clang++ -Wconditional-uninitialized seems to agree:

    0random.cpp:150:12: warning: variable 'r1' may be uninitialized when used here [-Wconditional-uninitialized]
    
  10. practicalswift commented at 8:49 pm on November 19, 2019: contributor
    @sipa Would you mind leaving a comment - am I missing something here, or is my reading correct? :)
  11. elichai commented at 3:01 pm on December 8, 2019: contributor

    https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide

    It is recommended that applications attempt 10 retries in a tight loop in the unlikely event that the RDRAND instruction does not return a random number. This number is based on a binomial probability argument: given the design margins of the DRNG, the odds of ten failures in a row are astronomically small and would in fact be an indication of a larger CPU issue.

    maybe we should abort then?

    But optional + a good log is also good IMHO

  12. sipa commented at 8:01 pm on March 3, 2020: member
    According to https://www.felixcloutier.com/x86/rdrand, even in case rdrand fails, the resulting register is overwritten (with zeroes), so I don’t think there can be an uninitialized value that comes out.
  13. practicalswift commented at 8:11 pm on March 3, 2020: contributor

    @sipa Thanks for clarifying! Good to hear. Closing this issue.

    I guess it still might make sense to initialize uint64_t r1 to zero just to make it clear for Clang (and human readers) that r1 cannot be used uninitialized here:

    0random.cpp:136:12: warning: variable 'r1' may be uninitialized when used here [-Wconditional-uninitialized]
    1    return r1;
    2           ^~
    3random.cpp:131:16: note: initialize the variable 'r1' to silence this warning
    4    uint64_t r1;
    5               ^
    6                = 0
    
  14. practicalswift closed this on Mar 3, 2020

  15. MarcoFalke locked this on Feb 15, 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: 2024-10-04 22:12 UTC

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