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