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)
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;
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. get_dh_ params (dh_primes= 0x6c107ff8, ret_p=0xbf7fc248, ret_g=0xbf7fc24c) dh_primes. c:45 0x6c01c630, data=0x85cfbff6 <Address 0x85cfbff6 out of bounds>, size=2244984822 ) at auth_dhe.c:268 recv_client_ kx_message (session= 0x6c01c630) at gnutls_kx.c:329 handshake_ server (session= 0x6c01c630) at gnutls_ handshake. c:2241 0x6c01c630) at gnutls_ handshake. c:1892 openldap2- 2.1.30/ servers/ slapd/connectio n.c:1134 openldap2- 2.1.30/ servers/ slapd/daemon. c:1863 start_thread () from /lib/libpthread .so.0 start_thread_ event () from /lib/libpthread .so.0
[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_
at gnutls_
#3 0x401fe292 in proc_dhe_client_kx (session=
_data_
#4 0x401ee548 in _gnutls_
#5 0x401e94c0 in _gnutls_
#6 0x401e8ad6 in gnutls_handshake (session=
#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/
#11 0x080564ab in slapd_daemon_task (ptr=0x0) at /root/tls/
#12 0x40312e51 in pthread_
#13 0x40312ecf in pthread_
#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 0x6c01c630, data=0x85cfbff6 <Address 0x85cfbff6 out of bounds>, size=2244984822 ) at auth_dhe.c:268 get_dh_ params( cred->dh_params, &p, &g)) < 0) {
#3 0x401fe292 in proc_dhe_client_kx (session=
_data_
268 if ( (ret=_gnutls_
(gdb) p cred->dh_params
Cannot access memory at address 0x85cfbff6
(gdb)
Before, cred gets assigned the following:
auth_dhe.c: get_cred( session- >key, GNUTLS_ CRD_CERTIFICATE , NULL);
cred = _gnutls_
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) { >algorithm= =type) {
break;
ccred = ccred->next;
if (ccred-
}
}
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 >key->cred- >credentials be returned.
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-
(gdb) p *(session- >key->cred) CRD_CERTIFICATE , credentials = 0x47210fb8, next = 0x0}
$42 = {algorithm = GNUTLS_
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) certificate_ credentials cred;
{
int bits;
const gnutls_
int ret;
GNUTLS_MPI p, g;
bits = _gnutls_ dh_get_ prime_bits( session);
cred = _gnutls_ get_cred( session- >key, GNUTLS_ CRD_CERTIFICATE , NULL);
gnutls_ assert( );
return GNUTLS_ E_INSUFFICIENT_ CREDENTIALS;
if (cred == NULL) {
}
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;
}