Page MenuHome GnuPG

tests/openpgp/ecc.scm fails when building GPG with address sanitizer
Open, Needs TriagePublic

Description

When compiling GPG with -fsanitize=address I see that tests/openpgp/ecc.scm fails with the following:

Importing ECC secret keys 
Checking ECC encryption 
Checking ECDH decryption 
    > msg_encrypted_256 msg_encrypted_384 msg_encrypted_521 <  
Checking ECC encryption and decryption 
    > plain-1 ...len: 133
pubkey_len: 133
=================================================================
==224378==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7b506eb01d81 at pc 0x7f5071ce4822 bp 0x7ffd98f7c8e0 sp 0x7ffd98f7c0a0
WRITE of size 133 at 0x7b506eb01d81 thread T0
    #0 0x7f5071ce4821 in memcpy (/lib64/libasan.so.8+0xe4821) (BuildId: 6a82bb83b1f19d3f3a2118085acf79daa3b52371)
    #1 0x7f507192ce5a in _gcry_ecc_curve_keypair /home/collin/.local/src/libgcrypt/cipher/ecc-ecdh.c:178
    #2 0x7f5071835f5c in _gcry_ecc_raw_keypair /home/collin/.local/src/libgcrypt/cipher/kem-ecc.c:128
    #3 0x7f5071835fcf in _gcry_ecc_raw_encap /home/collin/.local/src/libgcrypt/cipher/kem-ecc.c:146
    #4 0x7f507182d990 in _gcry_kem_encap /home/collin/.local/src/libgcrypt/cipher/kem.c:191
    #5 0x7f507180408a in gcry_kem_encap /home/collin/.local/src/libgcrypt/src/visibility.c:1507
    #6 0x000000580632 in do_encrypt_ecdh (/home/collin/.local/src/gnupg/g10/gpg+0x580632) (BuildId: 1ebb60ac0818488ba30f020093791b58323ac271)
    #7 0x0000005bff72 in write_pubkey_enc (/home/collin/.local/src/gnupg/g10/gpg+0x5bff72) (BuildId: 1ebb60ac0818488ba30f020093791b58323ac271)
    #8 0x0000005c0407 in write_pubkey_enc_from_list (/home/collin/.local/src/gnupg/g10/gpg+0x5c0407) (BuildId: 1ebb60ac0818488ba30f020093791b58323ac271)
    #9 0x0000005c0e88 in encrypt_crypt (/home/collin/.local/src/gnupg/g10/gpg+0x5c0e88) (BuildId: 1ebb60ac0818488ba30f020093791b58323ac271)
    #10 0x00000041a3cb in main (/home/collin/.local/src/gnupg/g10/gpg+0x41a3cb) (BuildId: 1ebb60ac0818488ba30f020093791b58323ac271)
    #11 0x7f5070e115f4 in __libc_start_call_main (/lib64/libc.so.6+0x35f4) (BuildId: 2b3c02fe7e4d3811767175b6f323692a10a4e116)
    #12 0x7f5070e116a7 in __libc_start_main@@GLIBC_2.34 (/lib64/libc.so.6+0x36a7) (BuildId: 2b3c02fe7e4d3811767175b6f323692a10a4e116)
    #13 0x00000041ffb4 in _start (/home/collin/.local/src/gnupg/g10/gpg+0x41ffb4) (BuildId: 1ebb60ac0818488ba30f020093791b58323ac271)

Address 0x7b506eb01d81 is located in stack of thread T0 at offset 385 in frame
    #0 0x00000057ffbf in do_encrypt_ecdh (/home/collin/.local/src/gnupg/g10/gpg+0x57ffbf) (BuildId: 1ebb60ac0818488ba30f020093791b58323ac271)

  This frame has 8 object(s):
    [48, 52) 'nbits' (line 754)
    [64, 72) 'hd' (line 755)
    [96, 104) 'kdf_params_spec' (line 774)
    [128, 136) 'kdf_params' (line 778)
    [160, 168) 'kdf_params_len' (line 779)
    [192, 224) 'fp' (line 775)
    [256, 385) 'ecc_ct' (line 766)
    [464, 593) 'ecc_ecdh' (line 767) <== Memory access at offset 385 partially underflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow /home/collin/.local/src/libgcrypt/cipher/ecc-ecdh.c:178 in _gcry_ecc_curve_keypair
Shadow bytes around the buggy address:
  0x7b506eb01b00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b506eb01b80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b506eb01c00: f1 f1 f1 f1 f1 f1 04 f2 00 f2 f2 f2 00 f2 f2 f2
  0x7b506eb01c80: 00 f2 f2 f2 00 f2 f2 f2 00 00 00 00 f2 f2 f2 f2
  0x7b506eb01d00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x7b506eb01d80:[01]f2 f2 f2 f2 f2 f2 f2 f2 f2 00 00 00 00 00 00
  0x7b506eb01e00: 00 00 00 00 00 00 00 00 00 00 01 f3 f3 f3 f3 f3
  0x7b506eb01e80: f3 f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b506eb01f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b506eb01f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b506eb02000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==224378==ABORTING
: (() ((throw (:stderr result)) (call-popen cmd input)))
0: #<CLOSURE>
1: tests.scm:425: (apply throw error)
FAIL: <standard>tests/openpgp/ecc.scm

I tried looking into this yesterday but I am not too familiar with the gcrypt functions. It seems this failure was introduced by this recent commit:

commit d1c3bfda2a8c032165ad41dc750f31d92369cd37
Author:     NIIBE Yutaka <gniibe@fsij.org>
AuthorDate: Mon May 19 14:51:17 2025 +0900
Commit:     NIIBE Yutaka <gniibe@fsij.org>
CommitDate: Mon May 19 14:57:19 2025 +0900

    gpg: Use the KEM API for ECC encryption.
    
    * g10/ecdh.c (gnupg_ecc_6637_kdf): New.
    (pk_ecdh_encrypt_with_shared_point, gen_k): Remove.
    (pk_ecdh_generate_ephemeral_key): Remove.
    * g10/pkglue.c (get_data_from_sexp): Remove.
    (do_encrypt_ecdh): Use gcry_kem_encap of the KEM API,
    gnupg_ecc_6637_kdf, and AESWRAP.
    * g10/pkglue.h (gnupg_ecc_6637_kdf): New.
    (pk_ecdh_encrypt_with_shared_point): Remove.
    (pk_ecdh_generate_ephemeral_key, pk_ecdh_encrypt): Remove.
    
    --
    
    GnuPG-bug-id: 7649
    Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>

@gniibe Can you take a look? I have a feeling you will be able to solve this much faster than me. Thanks!