Comment 42 for bug 6867

Revision history for this message
Debian Bug Importer (debzilla) wrote :

Message-ID: <email address hidden>
Date: Tue, 20 Jul 2004 13:34:16 +0200
From: <email address hidden> (Roland Bauerschmidt)
To: Matthias Urlichs <email address hidden>
Cc: Modestas Vainius <email address hidden>, <email address hidden>
Subject: Re: Bug#244827: libgcrypt7: more info

On Mon, Jul 19, 2004 at 05:35:36PM +0200, Matthias Urlichs wrote:
> Looks like a nicely impossible-to-find memory corruption bug. Happiness.
> Did you try to reproduce it under Electric Fence?

I have just reproduced the bug under Electric Fence. The SEGV occurs
slightly earlier:

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 16386 (LWP 15079)]
0x402924fe in _gcry_mpi_copy (a=0x85cfbff6) at mpiutil.c:216
216 if( a && (a->flags & 4) ) {
(gdb) bt
#0 0x402924fe in _gcry_mpi_copy (a=0x85cfbff6) at mpiutil.c:216
#1 0x40292a48 in gcry_mpi_copy (a=0x85cfbff6) at mpiutil.c:343
#2 0x401fe3fc in _gnutls_get_dh_params (dh_primes=0x6c107ff8, ret_p=0xbf7fc248, ret_g=0xbf7fc24c)
    at gnutls_dh_primes.c:45
#3 0x401fe292 in proc_dhe_client_kx (session=0x6c01c630, data=0x85cfbff6 <Address 0x85cfbff6 out of bounds>,
    _data_size=2244984822) at auth_dhe.c:268
#4 0x401ee548 in _gnutls_recv_client_kx_message (session=0x6c01c630) at gnutls_kx.c:329
#5 0x401e94c0 in _gnutls_handshake_server (session=0x6c01c630) at gnutls_handshake.c:2241
#6 0x401e8ad6 in gnutls_handshake (session=0x6c01c630) at gnutls_handshake.c:1892
#7 0x400569a7 in SSL_do_handshake (ssl=0x485d0fdc, end=GNUTLS_SERVER) at gnutls.c:627
#8 0x40056acd in gnutls_SSL_accept (ssl=0x485d0fdc) at gnutls.c:670
#9 0x40054394 in ldap_pvt_tls_accept (sb=0x6bc15fe4, ctx_arg=0x0) at tls.c:928
#10 0x08058ff0 in connection_read (s=32) at /root/tls/openldap2-2.1.30/servers/slapd/connection.c:1134
#11 0x080564ab in slapd_daemon_task (ptr=0x0) at /root/tls/openldap2-2.1.30/servers/slapd/daemon.c:1863
#12 0x40312e51 in pthread_start_thread () from /lib/libpthread.so.0
#13 0x40312ecf in pthread_start_thread_event () from /lib/libpthread.so.0
#14 0x4044969a in clone () from /lib/libc.so.6

That a->d pointed to 0x10 in a previous post doesn't seem to be the
root of failure, but rather a consequence of this:

(gdb) f 0
#0 0x402924fe in _gcry_mpi_copy (a=0x85cfbff6) at mpiutil.c:216
216 if( a && (a->flags & 4) ) {
(gdb) p *a
Cannot access memory at address 0x85cfbff6
(gdb)

The variable 'a' is the same as cred->dh_params in #3:

(gdb) f 3
#3 0x401fe292 in proc_dhe_client_kx (session=0x6c01c630, data=0x85cfbff6 <Address 0x85cfbff6 out of bounds>,
    _data_size=2244984822) at auth_dhe.c:268
268 if ( (ret=_gnutls_get_dh_params( cred->dh_params, &p, &g)) < 0) {
(gdb) p cred->dh_params
Cannot access memory at address 0x85cfbff6
(gdb)

Before, cred gets assigned the following:

auth_dhe.c:
cred = _gnutls_get_cred(session->key, GNUTLS_CRD_CERTIFICATE, NULL);

const void *_gnutls_get_cred( GNUTLS_KEY key, gnutls_credentials_type type, int *err) {
        const void *retval = NULL;
        int _err = -1;
        AUTH_CRED * ccred;

        if (key == NULL) goto out;

        ccred = key->cred;
        while(ccred!=NULL) {
                if (ccred->algorithm==type) {
                        break;
                }
                ccred = ccred->next;
        }
        if (ccred==NULL) goto out;

        _err = 0;
        retval = ccred->credentials;

        out:
        if (err!=NULL) *err=_err;
        return retval;
}

_gnutls_get_cred walks through the linked list of session->key->cred and
returns the first element whose algorithm matches GNUTLS_CRD_CERT.. Here,
session->key->cred consists of only one element (next points to NULL)
that also matches the algorithm, and thus processing should stop there,
and session->key->cred->credentials be returned.

(gdb) p *(session->key->cred)
$42 = {algorithm = GNUTLS_CRD_CERTIFICATE, credentials = 0x47210fb8, next = 0x0}

Consequently, session->key->cred->credentials and cred should be
*identical*. But they aren't (0x47210fb8 != 0x85cfbff6):

(gdb) p session->key->cred->credentials
$53 = (void *) 0x47210fb8
(gdb) p cred
$54 = <value optimized out>
(gdb) p *cred
Cannot access memory at address 0x85cfbff6

I'm assuming that when cred is assigned, they are still identical. But
when does cred get changed? I have no idea.

static int proc_dhe_client_kx(gnutls_session session, opaque * data,
                                  size_t _data_size)
{
int bits;
const gnutls_certificate_credentials cred;
int ret;
GNUTLS_MPI p, g;

        bits = _gnutls_dh_get_prime_bits( session);

        cred = _gnutls_get_cred(session->key, GNUTLS_CRD_CERTIFICATE, NULL);
        if (cred == NULL) {
                gnutls_assert();
                return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
        }

        if ( (ret=_gnutls_get_dh_params( cred->dh_params, &p, &g)) < 0) {
                gnutls_assert();
                return ret;
        }

        ret = _gnutls_proc_dh_common_client_kx( session, data, _data_size, g, p);
        _gnutls_mpi_release(&g);
        _gnutls_mpi_release(&p);

        return ret;

}