[Date Prev][Date Next] [Chronological] [Thread] [Top]

SASL bind memory bug (ITS#2548)

Full_Name: Anton Ushakov
Version: 2.1.20
OS: Sparc Solaris 8
URL: ftp://ftp.openldap.org/incoming/
Submission from: (NULL) (

Hello, I have a memory bug to report. We are using openldap client side
libraries, binding to openldap server using SASL, GSSAPI Kerberos 5.

Client environment:
SunOS zver.Stanford.EDU 5.8 Generic_108528-17 sun4u sparc SUNW,Ultra-5_10

In long-running client services we like to renew the kerberos ticket on
the fly, as a failback from "Local Error". So the logic is:

rc = ldap_sasl_interactive_bind_s
if (rc == LDAP_LOCAL_ERROR) // means TGT expired or missing
    [krb5 code to get new TGT]
    ldap_unbind                 <------- memory error, memory freed twice
    ldap_sasl_interactive_bind_s // try again

The problem is that during the first ldap_sasl_interactive_bind_s, when
the LDAP_LOCAL_ERROR is generated, ldap_free_connection is called, and as
you can see from the purify trace below, that eventually enters sasl code
and frees ld->ld_error, but it is never set to NULL afterwards. Then
ldap_unbind goes thru and tries to free ld->ld_error AGAIN, since it's
not NULL, and that's a double free(), folks.

I uploaded a small program (referred to as ldap.c below) that was used to
the following Purify output, illustrating the double bind problem. The test
needs libldif.a and ldap include files. The program was uploaded as
ftp.openldap.org/incoming/anton-ushakov-030523.c It can be built like so:

gcc -g -I/usr/local/include -I./ -I/usr/local/openldap-2.1.20/include -c
-o ldap.o ldap.c
purify gcc -g -o ldap ldap.o \
-R/usr/local/lib \
libldif.a \
-lresolv \
-lsasl2 \
-lkrb4 -ldes425 -lkrb5 -lk5crypto -lcom_err \
-lssl \
-lcrypto \
-lnsl -lsocket \
-lldap -llber


Purify output:

      FUM: Freeing unallocated memory
      This is occurring while in:
            free           [rtlib.o]
            ber_memfree    [memory.c:143]
                               memset( mh, 0xff, mh->bm_length +
sizeof(struct ber_mem_hdr) + sizeof(ber_int_t));
                               free( mh );
            =>                 free( p );
            ldap_ld_free   [unbind.c:98]
                       if ( ld->ld_error != NULL ) {
            =>                 LDAP_FREE( ld->ld_error );
                               ld->ld_error = NULL;

            ldap_unbind_ext [unbind.c:46]
                       rc = ldap_int_client_controls( ld, cctrls );
                       if( rc != LDAP_SUCCESS ) return rc;

            =>         return ldap_ld_free( ld, 1, sctrls, cctrls );

            ldap_unbind    [unbind.c:67]
                       Debug( LDAP_DEBUG_TRACE, "ldap_unbind\n", 0, 0, 0

            =>         return( ldap_unbind_ext( ld, NULL, NULL ) );

            main           [ldap.c:350]
               fprintf( stderr, "second ldap_init:\n");

            => ldap_unbind( ld );
               ld = NULL;
      Attempting to free block at 0xaf2a0 already freed.
      This block was allocated from:
            malloc         [rtlib.o]
            _buf_alloc     [libsasl2.so.2.0.13]
            _sasl_conn_init [libsasl2.so.2.0.13]
            sasl_client_new [libsasl2.so.2.0.13]
            ldap_int_sasl_open [cyrus.c:477]
            ldap_int_open_connection [open.c:348]
      There have been 8 frees since this block was freed from:
            free           [rtlib.o]
            _sasl_conn_dispose [libsasl2.so.2.0.13]
            client_dispose [libsasl2.so.2.0.13]
            sasl_dispose   [libsasl2.so.2.0.13]
            ldap_int_sasl_close [cyrus.c:507]
            ldap_free_connection [request.c:472]

Please let me know if you need more info on this. Our current workaround
is to not unbind at all, avoiding the double free but leaking 500 bytes a

thank you for looking at this


Anton Ushakov
Infrastructure Services, ITSS, Stanford University