Suppress a harmless variable-time optimization by clang in memczero #728

pull real-or-random wants to merge 2 commits into bitcoin-core:master from real-or-random:202003-memczero-clang changing 2 files +26 −5
  1. real-or-random commented at 3:16 pm on March 25, 2020: contributor

    This has been not been caught by the new constant-time tests because valgrind currently gives us a zero exit code even if finds errors, see #723 (review) .

    Note that the timing leak here was the bit whether a secret key was out of range. This leak is harmless and not exploitable. It is just our overcautious practice to prefer constant-time code even here.

    Here’s the “failure” on the current master: https://travis-ci.org/github/bitcoin-core/secp256k1/jobs/666399947#L462

  2. real-or-random force-pushed on Mar 25, 2020
  3. in src/util.h:172 in 5d1aa7fbc5 outdated
    170+    volatile int *flagp = &flag;
    171+    unsigned char mask = -(unsigned char) *flagp;
    172     p = (unsigned char *)s;
    173     while (len) {
    174-        *p ^= *p & mask;
    175+        *p &= ~mask;
    


    real-or-random commented at 3:19 pm on March 25, 2020:
    I also changed the arithmetic here. I find this one here simpler but your taste may be different.

    jonasnick commented at 8:03 pm on March 26, 2020:
    Fine with me. Fwiw the function doesn’t have a test.

    real-or-random commented at 9:55 am on March 27, 2020:
    It was covered within some other test but I added an explicit test now.
  4. real-or-random commented at 3:22 pm on March 25, 2020: contributor

    For completeness, this was the code generated by clang:

     0memczero():
     1src/util.h:169
     2static SECP256K1_INLINE void memczero(void *s, size_t len, int flag) {
     3    unsigned char *p;
     4    unsigned char mask = -(unsigned char)flag;
     5    p = (unsigned char *)s;
     6    while (len) {
     7        *p ^= *p & mask;
     8   20405:    0f 10 5b 10              movups 0x10(%rbx),%xmm3
     9   20409:    0f 10 53 20              movups 0x20(%rbx),%xmm2
    10   2040d:    0f 10 4b 30              movups 0x30(%rbx),%xmm1
    11   20411:    0f 57 c0                 xorps  %xmm0,%xmm0
    12   20414:    74 05                    je     2041b <secp256k1_ec_pubkey_create+0x15b>
    13   20416:    0f 57 e4                 xorps  %xmm4,%xmm4
    14   20419:    eb 03                    jmp    2041e <secp256k1_ec_pubkey_create+0x15e>
    15   2041b:    0f 10 23                 movups (%rbx),%xmm4
    16   2041e:    0f 11 23                 movups %xmm4,(%rbx)
    17   20421:    48 8b 04 24              mov    (%rsp),%rax
    18   20425:    75 42                    jne    20469 <secp256k1_ec_pubkey_create+0x1a9>
    19   20427:    0f 11 5b 10              movups %xmm3,0x10(%rbx)
    20   2042b:    75 45                    jne    20472 <secp256k1_ec_pubkey_create+0x1b2>
    21   2042d:    0f 11 53 20              movups %xmm2,0x20(%rbx)
    22   20431:    74 03                    je     20436 <secp256k1_ec_pubkey_create+0x176>
    23   20433:    0f 57 c9                 xorps  %xmm1,%xmm1
    24   20436:    0f 11 4b 30              movups %xmm1,0x30(%rbx)
    

    This shows that our tests are essentially working. :+1: Except the exit value which will be fixed in #723.

  5. in src/util.h:169 in 5d1aa7fbc5 outdated
    162@@ -163,10 +163,14 @@ SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t;
    163 /* Zero memory if flag == 1. Constant time. */
    164 static SECP256K1_INLINE void memczero(void *s, size_t len, int flag) {
    165     unsigned char *p;
    166-    unsigned char mask = -(unsigned char)flag;
    167+    /* Access flag with a volatile-qualified lvalue.
    168+       This prevents clang from figuring out (after inlining) that flag can
    169+       take only be 0 or 1, which leads to variable time code. */
    170+    volatile int *flagp = &flag;
    


    jonasnick commented at 4:56 pm on March 25, 2020:
    Why add this pointer instead of making the flag argument volatile int?

    real-or-random commented at 5:29 pm on March 25, 2020:

    This works too but I find volatile function parameters very obscure. Some C++ people agree with me: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1152r0.html#parret

    Also the placement of the comment is more natural with this version.


    jonasnick commented at 8:01 pm on March 26, 2020:
    Afaics the argument isn’t super strong (“it leaks function implementation information to the caller”). But what about making flagp a volatile int instead of pointer, and copy flag into it? Otherwise flagp is declared as a pointer to volatile int, but does not in fact point to a volatile int.

    real-or-random commented at 9:32 am on March 27, 2020:

    I changed it to your suggestion. (I didn’t do this previously because I wrongly assumed it needs one more store).

    Otherwise flagp is declared as a pointer to volatile int, but does not in fact point to a volatile int.

    When working on this PR I learned the truth about volatile. While the C standards speaks about “volatile objects”, what the authors meant and luckily what every compiler implemented are “volatile lvalues” [1]. In other words, being volatile is a property of an access to an object, not a property of the object itself. So both variants with and without pointer are equally good in practice but the one without pointer is simpler and indeed closer the letter of the standard.

    [1] Defect report 476. http://www.open-std.org/jtc1/sc22/wg14/www/docs/summary.htm#dr_476

  6. gmaxwell commented at 8:06 am on March 26, 2020: contributor
    I don’t have an opinion on how this is done in general, but the fact that clang would make that non-constant time makes me extremely uneasy about what it will do in the future. It also seems a little inexplicable. A well predicted branch is cheap but still…
  7. real-or-random cross-referenced this on Mar 26, 2020 from issue Alternative cmov implementation by peterdettman
  8. Suppress a harmless variable-time optimization by clang in memczero
    This has been not been caught by the new constant-time tests because
    valgrind currently gives us a zero exit code even if finds errors, see
    https://github.com/bitcoin-core/secp256k1/pull/723#discussion_r388246806 .
    
    This commit also simplifies the arithmetic in memczero.
    
    Note that the timing leak here was the bit whether a secret key was
    out of range. This leak is harmless and not exploitable. It is just
    our overcautious practice to prefer constant-time code even here.
    52a03512c1
  9. real-or-random force-pushed on Mar 27, 2020
  10. real-or-random force-pushed on Mar 27, 2020
  11. Add test for memczero() 01993878bb
  12. real-or-random force-pushed on Mar 27, 2020
  13. jonasnick approved
  14. jonasnick commented at 6:07 pm on March 27, 2020: contributor
    ACK 01993878bb2e7f24f42dac84d6949242143bb7f8
  15. jonasnick merged this on Mar 27, 2020
  16. jonasnick closed this on Mar 27, 2020

  17. elichai cross-referenced this on May 13, 2020 from issue Bump libsecp256k1 by elichai
  18. deadalnix referenced this in commit 81b7dd6bc3 on Jun 4, 2020
  19. deadalnix referenced this in commit fe2a79cd93 on Jun 5, 2020
  20. sipa cross-referenced this on Jun 9, 2020 from issue Update libsecp256k1 subtree by sipa
  21. fanquake referenced this in commit 8c97780db8 on Jun 13, 2020
  22. sidhujag referenced this in commit 8a3a072968 on Jun 13, 2020
  23. ComputerCraftr referenced this in commit b98f1c6e6c on Jun 16, 2020
  24. real-or-random cross-referenced this on Jul 24, 2020 from issue Add valgrind constant-time test to `make check` by real-or-random
  25. real-or-random cross-referenced this on Jul 26, 2020 from issue Improve constant-timeness on PowerPC by real-or-random
  26. UdjinM6 referenced this in commit 9d36ba6570 on Aug 10, 2021
  27. 5tefan referenced this in commit 8ded2caa74 on Aug 12, 2021
  28. 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-10-30 03:15 UTC

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