Fix uninit values passed into cmov #754

pull elichai wants to merge 2 commits into bitcoin-core:master from elichai:2020-05-uninit-cmov changing 12 files +38 −18
  1. elichai commented at 12:15 pm on May 20, 2020: contributor

    This should fix #753. Used @peterdettman’s solution here for the ECMULT_CONST_TABLE_GET_GE #753 (comment) and in ecdsa_sign I initialize s and r to a zero scalar.

    The second commit adds a valgrind check to the cmovs that could’ve caught this (in ecdsa_sign, not in ecmult_const because there’s a scalar clear there under VERIFY_SETUP)

  2. in src/ecmult_const_impl.h:28 in b215741c8c outdated
    24@@ -25,7 +25,11 @@
    25     VERIFY_CHECK((n) <=  ((1 << ((w)-1)) - 1)); \
    26     VERIFY_SETUP(secp256k1_fe_clear(&(r)->x)); \
    27     VERIFY_SETUP(secp256k1_fe_clear(&(r)->y)); \
    28-    for (m = 0; m < ECMULT_TABLE_SIZE(w); m++) { \
    29+    /* Unconditionally ser r->x = (pre)[m].x. r->y = (pre)[m].y. because it's either the correct one \
    


    real-or-random commented at 8:01 pm on May 20, 2020:
    0    /* Unconditionally set r->x = (pre)[m].x. r->y = (pre)[m].y, because it's either the correct one \
    
  3. in src/field.h:128 in b215741c8c outdated
    124@@ -125,10 +125,10 @@ static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe
    125 /** Convert a field element back from the storage type. */
    126 static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a);
    127 
    128-/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
    129+/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time.  both *r and *a must be initialized.*/
    


    real-or-random commented at 8:03 pm on May 20, 2020:
    0/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
    

    same in the other files

  4. in src/field.h:131 in b215741c8c outdated
    124@@ -125,10 +125,10 @@ static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe
    125 /** Convert a field element back from the storage type. */
    126 static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a);
    127 
    128-/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
    129+/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time.  both *r and *a must be initialized.*/
    130 static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag);
    131 
    132-/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
    133+/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time.  both *r and *a must be initialized.*/
    


    real-or-random commented at 8:04 pm on May 20, 2020:
    0/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
    
  5. in src/field_10x26_impl.h:13 in b215741c8c outdated
     9@@ -10,6 +10,10 @@
    10 #include "util.h"
    11 #include "field.h"
    12 
    13+#if defined(VALGRIND)
    


    real-or-random commented at 9:11 am on May 22, 2020:
    I think for now it’s cleaner to check also VERIFY here. (Same in the other files)
  6. real-or-random commented at 9:19 am on May 22, 2020: contributor

    ACK expect nits.

    I think the valgrind checks need some more Concept ACKs because this is “new tooling” in some sense. I think they’re really a good idea here because it’s somewhat unexpected that cmov functions will read their target.

  7. Fixed UB(arithmetics on uninit values) in cmovs a39c2b09de
  8. elichai force-pushed on May 22, 2020
  9. real-or-random commented at 11:38 am on May 22, 2020: contributor

    I think the valgrind checks need some more Concept ACKs because this is “new tooling” in some sense. I think they’re really a good idea here because it’s somewhat unexpected that cmov functions will read their target.

    Ah yes, it seems that gcc 10 will just warn us here.I get warnings only for the ecdsa_sign function and no for ecmult_const, with ecdh enabled. But since valgrind does not help for ecmult_const, it’s maybe simpler not to include the valgrind checks. I don’t have strong opinions here. Either way is okay with me.

  10. sipa commented at 5:13 pm on May 22, 2020: contributor

    I think this is a grey area in the specification, see https://queue.acm.org/detail.cfm?id=3041020 (in C89 it’s probably even less clear), because uintXX_t cannot have trap representations. The only question is whether just using an unspecified value on itself is UB, which seems up for debate.

    Concept ACK on the changes for an abundance of caution.

    I’m not convinced about the additional Valgrind check, because this seems to be outside of the scope of what Valgrind is even supposed to check (even without the additional check, it passing means there is no non-constant time behaviour; whether it’s not triggering any other kind of UB beyond that seems more a job for sanitizers, who understand the source code).

  11. elichai commented at 8:32 pm on May 22, 2020: contributor

    Ah yes, it seems that gcc 10 will just warn us here.I get warnings only for the ecdsa_sign function and no for ecmult_const, with ecdh enabled.

    Do you get those warnings consistently? and on what parts of the code? I only got once on the low_impl implementation

    I think this is a grey area in the specification, see https://queue.acm.org/detail.cfm?id=3041020 (in C89 it’s probably even less clear), because uintXX_t cannot have trap representations. The only question is whether just using an unspecified value on itself is UB, which seems up for debate.

    I must say I wrote down a long post arguing that I do think it’s UB and I think compilers (especially llvm/clang) are really harsh on uninitialized values but then I came across this thread: (after long discussions in the #llvm irc channel) https://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20180528/556592.html So you’re right, this isn’t clear at all.

    I’m not convinced about the additional Valgrind check

    I’m not either, it was just the only test I could come up with to catch this in the future, but I can drop that commit if there’s no consensus about it.

  12. real-or-random commented at 12:51 pm on May 23, 2020: contributor

    I’m not convinced about the additional Valgrind check, because this seems to be outside of the scope of what Valgrind is even supposed to check (even without the additional check, it passing means there is no non-constant time behaviour; whether it’s not triggering any other kind of UB beyond that seems more a job for sanitizers, who understand the source code).

    I don’t think it’s outside the scope of what valgrind is supposed to check. Valgrind tracks uninitialized memory (on a binary level, not on a C abstract machine level). It does not complain about the existence of uninitialized value, it complains if the externally visible behaviour of your binary depends on uninitialized values (e.g., if a branch depends on it, which valgrind always counts as observable.) This is not the case here as we discussed in #753.

    But because valgrind tracks uninitialized memory, you can ask valgrind explicitly to check if a given piece of memory is defined, and that’s what we’re doing here.

    So that the check here passed is not related to the code being constant time (because it’s not about a branch).

    I’m not either, it was just the only test I could come up with to catch this in the future, but I can drop that commit if there’s no consensus about it.

    Yes, shall we get the first commit merged if the second is debatable?

  13. jonasnick commented at 8:00 pm on May 23, 2020: contributor

    ACK a39c2b09de304b8f24716b59219ae37c2538c242 (the first commit)

    I’d be fine with the second commit too. It would have prevented what’s clearly maybe (sic) an issue.

    With gcc 10.1.0 I’m only getting warnings (reliably) in scalar_low_impl (called from ecdsa_sign) and therefore no warnings if compiled without exhaustive tests.

  14. elichai commented at 8:11 am on May 24, 2020: contributor
    FYI, this new valgrind check won’t even run under the valgrind ctime test because it’s guarded under VERIFY which isn’t set for the ctime test. but as @real-or-random this has nothing to do with constant/variable time but with alerting to future contributors in the future that it might be UB to pass uninit r here.
  15. sipa commented at 7:31 pm on May 26, 2020: contributor

    FYI, this new valgrind check won’t even run under the valgrind ctime test because it’s guarded under VERIFY which isn’t set for the ctime test.

    It seems rather pointless then?

  16. elichai commented at 7:39 pm on May 26, 2020: contributor

    It seems rather pointless then?

    The point is that valgrind ./tests and/or valgrind ./exhuastive_tests will catch this.

  17. sipa commented at 7:52 pm on May 26, 2020: contributor

    Ok, Concept ACK.

    I think it’s a bit ugly to have #ifdef VALGRIND all over the place, though.

    Perhaps the VG_UNDEF/VG_CHECK macros from tests.c can be moved to util.h, so these checks can be just #ifdef VERIFY. Alternatively, there could be a VG_CHECK_VERIFY that is only defined when VERIFY is set even.

  18. elichai force-pushed on May 26, 2020
  19. Add valgrind uninit check to cmovs output f79a7adcf5
  20. elichai force-pushed on May 26, 2020
  21. elichai commented at 8:31 pm on May 26, 2020: contributor
    @sipa Is this better?
  22. sipa commented at 10:01 pm on May 26, 2020: contributor
    utACK f79a7adcf555ccc78b591850ea15c64fbfbca152
  23. real-or-random cross-referenced this on May 27, 2020 from issue Recovery signing: add to constant time test, and eliminate non ct operators by elichai
  24. jonasnick approved
  25. jonasnick commented at 4:57 pm on May 28, 2020: contributor
    ACK f79a7adcf555ccc78b591850ea15c64fbfbca152
  26. real-or-random approved
  27. real-or-random commented at 4:02 pm on June 2, 2020: contributor
    ACK f79a7adcf555ccc78b591850ea15c64fbfbca152
  28. real-or-random merged this on Jun 2, 2020
  29. real-or-random closed this on Jun 2, 2020

  30. elichai deleted the branch on Jun 2, 2020
  31. elichai cross-referenced this on Jun 8, 2020 from issue Add schnorrsig module which implements BIP-340 compliant signatures by jonasnick
  32. sipa cross-referenced this on Jun 9, 2020 from issue Update libsecp256k1 subtree by sipa
  33. fanquake referenced this in commit 8c97780db8 on Jun 13, 2020
  34. sidhujag referenced this in commit 8a3a072968 on Jun 13, 2020
  35. ComputerCraftr referenced this in commit b98f1c6e6c on Jun 16, 2020
  36. jasonbcox referenced this in commit 42bcef6862 on Sep 27, 2020
  37. deadalnix referenced this in commit 5176cb8d70 on Sep 28, 2020
  38. UdjinM6 referenced this in commit 9d36ba6570 on Aug 10, 2021
  39. 5tefan referenced this in commit 8ded2caa74 on Aug 12, 2021
  40. gades referenced this in commit d855cc511d on May 8, 2022

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin-core/secp256k1. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-11-21 15:15 UTC

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