Page MenuHome GnuPG

Buffer Overrun in GPGME encrypt-sign.c:168?
Closed, ResolvedPublic

Details

Version
1.6.0

Event Timeline

dylanetaft set Version to 1.6.0.
dylanetaft added a subscriber: dylanetaft.

It wasn't apparent to me until I looked at tests/gpg/t-encrypt.c that
gpgme_op_encrypt_sign expects an array of keys for the second parameter. It worked
when my code was straight C with a pointer to just a single key. In C++ I started
getting segfaults so I switched to an array.

gpgme_key_t keys[1] = {NULL};
gpgErr = gpgme_get_key(gpgCtx,to.c_str(),&keys[0],0);
It still segfaulted, further review, I THINK the array of keys needs to have one
blank key at the end else it may result in a buffer overrun in GPGME? Shouldn't
sizeof be used to determine the length of the array or something similar? Otherwise
the array would have to be at least 2 elements with the last element not a key so
the GPGME doesn't seg.

Process 12727 stopped

  • thread #1: tid = 0x864b5, 0x00000001000107ea

libgpgme.11.dylib`gpgme_op_encrypt_sign(ctx=0x0000000100200850,
recp=0x00007fff5fbffa50, flags=GPGME_ENCRYPT_NO_ENCRYPT_TO,
plain=0x0000000100201000, cipher=0x0000000100200dc0) + 474 at encrypt-sign.c:168,
queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)

frame #0: 0x00000001000107ea

libgpgme.11.dylib`gpgme_op_encrypt_sign(ctx=0x0000000100200850,
recp=0x00007fff5fbffa50, flags=GPGME_ENCRYPT_NO_ENCRYPT_TO,
plain=0x0000000100201000, cipher=0x0000000100200dc0) + 474 at encrypt-sign.c:168

165 	
166 	      while (recp[i])
167 		{

-> 168 TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],

169 			      (recp[i]->subkeys && recp[i]->subkeys->fpr) ?
170 			      recp[i]->subkeys->fpr : "invalid");
171 		  i++;

(lldb) bt

  • thread #1: tid = 0x864b5, 0x00000001000107ea

libgpgme.11.dylib`gpgme_op_encrypt_sign(ctx=0x0000000100200850,
recp=0x00007fff5fbffa50, flags=GPGME_ENCRYPT_NO_ENCRYPT_TO,
plain=0x0000000100201000, cipher=0x0000000100200dc0) + 474 at encrypt-sign.c:168,
queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)

  • frame #0: 0x00000001000107ea

libgpgme.11.dylib`gpgme_op_encrypt_sign(ctx=0x0000000100200850,
recp=0x00007fff5fbffa50, flags=GPGME_ENCRYPT_NO_ENCRYPT_TO,
plain=0x0000000100201000, cipher=0x0000000100200dc0) + 474 at encrypt-sign.c:168

frame #1: 0x0000000100000b76

pgtalk`GPGWrapper::encryptAndSign(this=0x00007fff5fbffb30, message="This is a
test\n", to="044E9E1D78D510E4C798D3B803254F162CFF2601") + 166 at GPGWrapper.cpp:32

frame #2: 0x00000001000019c6 pgtalk`main(argc=1, argv=0x00007fff5fbffc38) + 486

at pgtalk.cpp:13

frame #3: 0x00007fff910ad5ad libdyld.dylib`start + 1
frame #4: 0x00007fff910ad5ad libdyld.dylib`start + 1

(lldb) quit

The manual states:

     RECP must be a ‘NULL’-terminated array of keys.  The user must keep
     references for all keys during the whole duration of the call (but
     see ‘gpgme_op_encrypt_start’ for the requirements with the
     asynchronous variant).

What you call a blank key is a NULL stored in the array. A common way to
allocate such an array is by using

  gpgme_key_t *keys = calloc(nkeys+1, sizeof *keys);

and then fill the array with the keys: If you don't put keys into the array
(i.e.NULL as first item) the fucntion retruns GPG_ERR_INV_VALUE.

Regarding your problem with gpgme_get_key: You need to pass a variabale of type
gpgme_key_t to that function. The fucntion allocates a new key objects and
_stores_ it at that variable:

  gpgme_key_t akey;
  err = gpgme_get_key (ctx, fingerprint, &akey, 0);
  .. processing goes here ...
  gpgme_key_unref (akey);

Note that on error NULL is stored at AKEY and thus gpgme_key_unref can be called
in any case.

Thank you! All set.

On Friday, April 15, 2016, Werner Koch via BTS <gnupg@bugs.g10code.com>
wrote:

Werner Koch <wk@gnupg.org <javascript:;>> added the comment:

The manual states:

RECP must be a ‘NULL’-terminated array of keys.  The user must keep
references for all keys during the whole duration of the call (but
see ‘gpgme_op_encrypt_start’ for the requirements with the
asynchronous variant).

What you call a blank key is a NULL stored in the array. A common way to
allocate such an array is by using

gpgme_key_t *keys = calloc(nkeys+1, sizeof *keys);

and then fill the array with the keys: If you don't put keys into the
array
(i.e.NULL as first item) the fucntion retruns GPG_ERR_INV_VALUE.

Regarding your problem with gpgme_get_key: You need to pass a variabale
of type
gpgme_key_t to that function. The fucntion allocates a new key objects and
_stores_ it at that variable:

gpgme_key_t akey;
err = gpgme_get_key (ctx, fingerprint, &akey, 0);
.. processing goes here ...
gpgme_key_unref (akey);

Note that on error NULL is stored at AKEY and thus gpgme_key_unref can be
called
in any case.


category: -> gpgme
topic: +nobug


GnuPG's BTS <gnupg@bugs.g10code.com <javascript:;>>
<T2304>


werner claimed this task.