Do not construct out-of-bound pointers in SHA2 code #15950

pull sipa wants to merge 1 commits into bitcoin:master from sipa:201905_shapointerissue changing 3 files +3 −3
  1. sipa commented at 10:27 PM on May 3, 2019: member

    This looks like an issue in the current SHA256/512 code, where a pointer outside of the area pointed to may be constructed (this is UB in theory, though in practice every supported platform treats pointers as integers).

    I discovered this while investigating #14580. Sadly, it does not fix it.

  2. MarcoFalke added the label Refactoring on May 3, 2019
  3. sipa force-pushed on May 3, 2019
  4. sipa commented at 11:08 PM on May 3, 2019: member

    Rewritten; a much simpler change was possible to accomplish the same.

  5. gmaxwell commented at 1:33 AM on May 4, 2019: contributor

    sha1 and ripemd160 need the same treatment.

  6. practicalswift commented at 8:48 AM on May 4, 2019: contributor

    Very nice find! Thanks for fixing!

    Similar issues:

    https://github.com/bitcoin/bitcoin/blob/f19a3b2ded4b86d859c0a464f550e0743af78ae3/src/uint256.cpp#L44-L52

    https://github.com/bitcoin/bitcoin/blob/f19a3b2ded4b86d859c0a464f550e0743af78ae3/src/crypto/sha1.cpp#L166

    https://github.com/bitcoin/bitcoin/blob/f19a3b2ded4b86d859c0a464f550e0743af78ae3/src/crypto/ripemd160.cpp#L259

    When looking for pointer arithmetic issues in the SHA256 and SHA512 code I stumbled across these two:

    Consider the case where keylen is 64:

    https://github.com/bitcoin/bitcoin/blob/f19a3b2ded4b86d859c0a464f550e0743af78ae3/src/crypto/hmac_sha256.cpp#L9-L14

    Consider the case where keylen is 128:

    https://github.com/bitcoin/bitcoin/blob/f19a3b2ded4b86d859c0a464f550e0743af78ae3/src/crypto/hmac_sha512.cpp#L9-L14

    AFAIK p in memset(p, …, n) must be valid for writing even in the case where n is 0 to avoid UB.

    Anyways -- concept ACK of course:

    Getting rid of also the "not-yet-(ab-)used-by-compiler-authors-for-optimisation" class of UB makes perfect sense:

    • a.) avoiding UB makes our code robust against future time bombs introduced by new compiler optimisations,
    • b.) UB is a nuisance when trying do apply formal methods, and
    • c.) the warm fuzzy feeling that follows from knowing that our consensus critical piece of software will only make use of defined operations :-)

    Avoiding UB is largely about avoiding future problems. This is a frequently missed point when discussing UB.

    We should assume that current and future compiler writers care about benchmarks and that they will (ab-)use all optimisation opportunities given to them in the form of UB - regardless of if such optimisations would be "good" or "bad" for us. As been shown historically it is a risky strategy to assume otherwise: Changes in GCC Code Optimization Can Cause a Crash in BIND, D J Bernstein boringcc announcement, etc.

  7. sipa commented at 9:05 PM on May 4, 2019: member

    @gmaxwell Extended to SHA1 and RIPEMD160.

  8. sipa force-pushed on May 4, 2019
  9. sipa commented at 9:07 PM on May 4, 2019: member

    @practicalswift I don't see the issue with the uint256 code (as far as I can see, all pointers are to objects or one-past the object which is legal). I also can't find a reference for requiring that the memset argument needs to be a writable pointer if length is 0 (it needs to be a valid pointer, but it is; just not a writable one).

    Also no reason to explain me why fixing UB is a good idea; I obviously agree, or I wouldn't have opened this PR.

  10. l2a5b1 commented at 6:54 PM on May 5, 2019: contributor

    Concept ACK

    I don't see the issue with the uint256 code (as far as I can see, all pointers are to objects or one-past the object which is legal) @sipa see #14734

  11. practicalswift commented at 8:44 PM on May 5, 2019: contributor

    I don't see the issue with the uint256 code (as far as I can see, all pointers are to objects or one-past the object which is legal).

    Consider the case SetHex("1000000000000000000000000000000000000000000000000000000000000000"):

    When the reverse processing reaches the leading 1 we have psz == pbegin and the following happens:

    *p1 |= ((unsigned char)HexDigit(*psz--) << 4);
    

    Please note that psz has now been decremented to pbegin - 1 which is outside of the object.

    Let me know if I'm reading this incorrectly.

    I also can't find a reference for requiring that the memset argument needs to be a writable pointer if length is 0 (it needs to be a valid pointer, but it is; just not a writable one).

    Unfortunately the spec is not entirely clear on this (see 7.24.1.2. and 7.1.4.1. in ISO/IEC 9899:201x N1570).

    Arguments for why the pointer should be valid for writing even in the case of n is 0 are given here:

    The discussion is about memcpy but memset should have the same pointer requirements in this case.

    Also no reason to explain me why fixing UB is a good idea; I obviously agree, or I wouldn't have opened this PR.

    I was just giving a proper rationale for my concept ACK. Let me know if I'm too verbose in my concept ACKs and I'll adjust :-)

  12. laanwj commented at 9:47 AM on May 6, 2019: member

    utACK 7a3426096fede34607695ee1523b795784a3a40f

  13. jonasschnelli commented at 9:57 AM on May 6, 2019: contributor

    utACK 7a3426096fede34607695ee1523b795784a3a40f

  14. MarcoFalke commented at 1:32 PM on May 6, 2019: member

    Consider the case SetHex("1000000000000000000000000000000000000000000000000000000000000000"):

    Could add a unit testcase for this if that exact code path is not already covered?

  15. in src/crypto/sha1.cpp:166 in 7a3426096f outdated
     162 | @@ -163,7 +163,7 @@ CSHA1& CSHA1::Write(const unsigned char* data, size_t len)
     163 |          sha1::Transform(s, buf);
     164 |          bufsize = 0;
     165 |      }
     166 | -    while (end >= data + 64) {
     167 | +    while (end -data >= 64) {
    


    promag commented at 5:52 PM on May 6, 2019:

    nit, space


    sipa commented at 10:11 PM on May 6, 2019:

    Fixed.

  16. promag commented at 5:54 PM on May 6, 2019: member

    utACK 7a34260.

  17. Do not construct out-of-bound pointers in SHA512/SHA1/RIPEMD160 code c01c065b9d
  18. sipa force-pushed on May 6, 2019
  19. sipa commented at 10:12 PM on May 6, 2019: member

    Ok, let's discuss the uint256 issue further in #14734.

  20. practicalswift commented at 11:37 AM on May 7, 2019: contributor

    utACK c01c065b9ded3399a6a480f15543827dd5e8eb4d

  21. gmaxwell commented at 8:24 PM on May 8, 2019: contributor

    ACK

  22. laanwj merged this on May 16, 2019
  23. laanwj closed this on May 16, 2019

  24. laanwj referenced this in commit fd61b9fc22 on May 16, 2019
  25. sidhujag referenced this in commit abbe50b4a1 on May 18, 2019
  26. jasonbcox referenced this in commit 39e41a449c on Sep 13, 2019
  27. jonspock referenced this in commit 924313d920 on Dec 22, 2019
  28. proteanx referenced this in commit 08a1b60663 on Dec 23, 2019
  29. PastaPastaPasta referenced this in commit c019c6346a on Jun 27, 2021
  30. PastaPastaPasta referenced this in commit d5e4873c40 on Jun 28, 2021
  31. PastaPastaPasta referenced this in commit 166c770296 on Jun 29, 2021
  32. PastaPastaPasta referenced this in commit 6d3605d245 on Jul 1, 2021
  33. PastaPastaPasta referenced this in commit 8804421c39 on Jul 1, 2021
  34. PastaPastaPasta referenced this in commit fc4c9f49e5 on Jul 8, 2021
  35. PastaPastaPasta referenced this in commit 55c35078a5 on Jul 10, 2021
  36. DrahtBot locked this on Dec 16, 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-17 06:14 UTC

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