libgcrypt-1.7 fails self-test for all 'basic' with 'Checksum error' (log attached)

Jussi Kivilinna jussi.kivilinna at iki.fi
Thu Apr 28 17:09:52 CEST 2016


Hello,

On 28.04.2016 12:07, Werner Koch wrote:
> On Thu, 28 Apr 2016 10:31, buraphalinuxserver at gmail.com said:
>> -O3 seems to trigger the problem.  Gmail will often mangle long lines,
>> but this should still be enough for you to see the problems.
> 
> Thanks.  Can you please try with another gcc version?
> 

Looks as this is caused by some compiler error. I reproduced this with
gcc-5.3 on Ubuntu 16.04.

With -O3 optimization level, gcc inlines _gcry_cipher_ocb_get_l, 
double_block_cpy and double_block to _gcry_cipher_ocb_authenticate.

Inlined double_block_cpy/double_block for main ocb_authentication loop
(on line ~306-308) look as:

++ tail of _gcry_cipher_ocb_get_l inlined into
   _gcry_cipher_ocb_authenticate:
++ start double_block_cpy:
>>  double_block_cpy (l_tmp, c->u_mode.ocb.L[OCB_L_TABLE_SIZE - 1]);
     c2f:       4c 39 64 24 08          cmp    %r12,0x8(%rsp)
     c34:       74 18                   je     c4e <_gcry_cipher_ocb_authenticate+0x34e>
     c36:       48 8b b3 c0 01 00 00    mov    0x1c0(%rbx),%rsi
     c3d:       48 8b bb c8 01 00 00    mov    0x1c8(%rbx),%rdi
     c44:       48 89 74 24 10          mov    %rsi,0x10(%rsp)
     c49:       48 89 7c 24 18          mov    %rdi,0x18(%rsp)
     c4e:       48 8b 7c 24 10          mov    0x10(%rsp),%rdi
     c53:       48 8b 74 24 18          mov    0x18(%rsp),%rsi
     c58:       48 0f cf                bswap  %rdi
     c5b:       48 0f ce                bswap  %rsi
     c5e:       4c 8d 0c 3f             lea    (%rdi,%rdi,1),%r9
     c62:       48 89 f2                mov    %rsi,%rdx
     c65:       48 c1 ff 3f             sar    $0x3f,%rdi
     c69:       48 c1 ea 3f             shr    $0x3f,%rdx
     c6d:       81 e7 87 00 00 00       and    $0x87,%edi
     c73:       48 01 f6                add    %rsi,%rsi
     c76:       4c 31 ca                xor    %r9,%rdx
     c79:       48 31 fe                xor    %rdi,%rsi
     c7c:       85 c0                   test   %eax,%eax
     c7e:       48 0f ca                bswap  %rdx
     c81:       48 0f ce                bswap  %rsi
>> here new block generated in double_block_cpy is stored to
   stack (variable l_tmp):
     c84:       48 89 54 24 10          mov    %rdx,0x10(%rsp)
     c89:       48 89 74 24 18          mov    %rsi,0x18(%rsp)
-- end double_block_cpy
++ start double_block loop of _gcry_cipher_ocb_get_l
>>  for (ntz -= OCB_L_TABLE_SIZE; ntz; ntz--)
>>    double_block (l_tmp);
     c8e:       74 32                   je     cc2 <_gcry_cipher_ocb_authenticate+0x3c2>
     c90:       48 89 d7                mov    %rdx,%rdi
     c93:       48 0f ce                bswap  %rsi
     c96:       48 0f cf                bswap  %rdi
     c99:       48 89 f2                mov    %rsi,%rdx
     c9c:       48 01 f6                add    %rsi,%rsi
     c9f:       4c 8d 0c 3f             lea    (%rdi,%rdi,1),%r9
     ca3:       48 c1 ff 3f             sar    $0x3f,%rdi
     ca7:       48 c1 ea 3f             shr    $0x3f,%rdx
     cab:       81 e7 87 00 00 00       and    $0x87,%edi
     cb1:       4c 31 ca                xor    %r9,%rdx
     cb4:       48 31 fe                xor    %rdi,%rsi
     cb7:       83 e8 01                sub    $0x1,%eax
>> in double_block loop, new block generated is _not_ stored
   to stack, which seems to cause OCB to fail.
     cba:       48 0f ca                bswap  %rdx
     cbd:       48 0f ce                bswap  %rsi
     cc0:       75 ce                   jne    c90 <_gcry_cipher_ocb_authenticate+0x390>
-- end double_block loop
>>  return l_tmp;
     cc2:       4c 89 e0                mov    %r12,%rax
     cc5:       e9 2e fe ff ff          jmpq   af8 <_gcry_cipher_ocb_authenticate+0x1f8>
-- returning jump from inlined _gcry_cipher_ocb_get_l,
   %rax has pointer to l_tmp variable. %rdx holds first
   64-bit half of new block and %rsi the second half.

Target of jump is on line 307 of cipher-ocb.c:

      buf_xor_1 (c->u_mode.ocb.aad_offset,
  >>             ocb_get_l (c, l_tmp, c->u_mode.ocb.aad_nblocks),
                 OCB_BLOCK_LEN);

>> Xoring c->u_mode.ocb.aad_offset[0..63-bit] to
   L[0..63-bit]. Ok as %rdx is preloaded with first
   64-bits of L block in each code path jumping at <af8>:
     af8:       48 33 93 e0 01 00 00    xor    0x1e0(%rbx),%rdx
     aff:       49 83 ed 10             sub    $0x10,%r13
>> Overwriting %rsi, loses second half of L block
   computed in double_block loop:
     b03:       4c 89 e6                mov    %r12,%rsi
     b06:       48 8b 3c 24             mov    (%rsp),%rdi
     b0a:       49 83 c6 10             add    $0x10,%r14
     b0e:       48 89 93 e0 01 00 00    mov    %rdx,0x1e0(%rbx)
>> Tries to load second half of L block from stack for
   xoring. All other code-paths have stored second half to
   l_tmp stack variable but this was not done in double_block
   loop:
     b15:       48 8b 40 08             mov    0x8(%rax),%rax
     b19:       48 33 83 e8 01 00 00    xor    0x1e8(%rbx),%rax
     b20:       48 89 83 e8 01 00 00    mov    %rax,0x1e8(%rbx)
     b27:       49 33 46 f8             xor    -0x8(%r14),%rax
     b2b:       49 33 56 f0             xor    -0x10(%r14),%rdx
     b2f:       48 89 44 24 18          mov    %rax,0x18(%rsp)
     b34:       48 8b 43 18             mov    0x18(%rbx),%rax
     b38:       48 89 54 24 10          mov    %rdx,0x10(%rsp)
     b3d:       4c 89 e2                mov    %r12,%rdx
     b40:       ff 50 40                callq  *0x40(%rax)
     b43:       48 8b 44 24 10          mov    0x10(%rsp),%rax
     b48:       48 31 83 f0 01 00 00    xor    %rax,0x1f0(%rbx)
     b4f:       48 8b 44 24 18          mov    0x18(%rsp),%rax
     b54:       48 31 83 f8 01 00 00    xor    %rax,0x1f8(%rbx)

Simple workaround that avoid this is to add __attribute__((noinline))
for _gcry_cipher_ocb_get_l to prevent inlining inside cipher-ocb.c.

-Jussi

>> This shows an aliasing issue that may be related to the problem:
> 
> 
>> sexp.c: In function '_gcry_sexp_vextract_param':
> 
> No this is not related.  The tests fail in cipher-ocb where we do not
> use any s-expression code.
> 
> 
> Salam-Shalom,
> 
>    Werner
> 




More information about the Gcrypt-devel mailing list