[Pkg-openldap-devel] Bug#645810: valgrind

Helmut Grohne helmut at subdivi.de
Sun Mar 4 13:03:16 UTC 2012


I reproduced the problem with valgrind and debug symbols. The output is
likely helpful for anyone interested in tracking down this issue. This
is sid i386, slapd version 2.4.28-1.1, gnutls version 2.12.16-1.

==9140== Memcheck, a memory error detector
==9140== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==9140== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==9140== Command: slapd
==9140==
==9140== Invalid free() / delete / delete[] / realloc()
==9140==    at 0x71FC40C: free (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==9140==    by 0x74D87AD: gnutls_priority_deinit (gnutls_priority.c:804)
==9140==    by 0x7249A4A: tlsg_ctx_free (in /usr/lib/i386-linux-gnu/libldap_r-2.4.so.2.8.1)
==9140==    by 0x72461D2: ldap_pvt_tls_ctx_free (in /usr/lib/i386-linux-gnu/libldap_r-2.4.so.2.8.1)
==9140==    by 0x77D3E15: (below main) (libc-start.c:228)
==9140==  Address 0x7f2dd88 is 0 bytes inside a block of size 492 free'd
==9140==    at 0x71FC40C: free (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==9140==    by 0x74D8549: gnutls_priority_init (gnutls_priority.c:789)
==9140==    by 0x7248CEB: tlsg_ctx_init (in /usr/lib/i386-linux-gnu/libldap_r-2.4.so.2.8.1)
==9140==    by 0x7EBDB07: ???
==9140==
==9140==
==9140== HEAP SUMMARY:
==9140==     in use at exit: 4,114 bytes in 64 blocks
==9140==   total heap usage: 13,850 allocs, 13,787 frees, 777,536 bytes allocated
==9140==
==9140== 31 bytes in 1 blocks are definitely lost in loss record 11 of 21
==9140==    at 0x71FD208: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==9140==    by 0x19829A: ??? (in /usr/sbin/slapd)
==9140==    by 0x74A681E: sasl_server_init (in /usr/lib/i386-linux-gnu/libsasl2.so.2.0.25)
==9140==    by 0x19A211: slap_sasl_init (in /usr/sbin/slapd)
==9140==    by 0x1718BC: slap_init (in /usr/sbin/slapd)
==9140==    by 0x11DE46: main (in /usr/sbin/slapd)
==9140==
==9140== 492 bytes in 1 blocks are definitely lost in loss record 18 of 21
==9140==    at 0x71FB986: calloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==9140==    by 0x74D787B: gnutls_priority_init (gnutls_priority.c:535)
==9140==    by 0x77D3E15: (below main) (libc-start.c:228)
==9140==
==9140== LEAK SUMMARY:
==9140==    definitely lost: 523 bytes in 2 blocks
==9140==    indirectly lost: 0 bytes in 0 blocks
==9140==      possibly lost: 0 bytes in 0 blocks
==9140==    still reachable: 3,591 bytes in 62 blocks
==9140==         suppressed: 0 bytes in 0 blocks
==9140== Reachable blocks (those to which a pointer was found) are not shown.
==9140== To see them, rerun with: --leak-check=full --show-reachable=yes
==9140==
==9140== For counts of detected and suppressed errors, rerun with: -v
==9140== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 103 from 14)

Some line are still missing. As a first step let me first deduce them:

gnutls_priority_deinit is called from tlsg_ctx_free in
libraries/libldap/tls_g.c:275.

gnutls_priority_init is indirectly called from tlsg_ctx_init. The only
possible direct callers are tlsg_parse_ciphers and tlsg_ctx_new. Only
tlsg_parse_ciphers is called from tlsg_ctx_init.

tlsg_ctx_init calls tlsg_parse_ciphers in libraries/libldap/tls_g.c:318
tlsg_parse_ciphers calls gnutls_priority_init in
libraries/libldap/tls_g.c:793

The next step is to deduce what actually happens.
1) (chronological) first free.
   Since gnutls_priority_init frees the priority cache it the return
   value is GNUTLS_E_INVALID_REQUEST != 0.
   (lib/gnutls_priority.c:791)
   Thus tlsg_parse_ciphers also returns non-zero.
   (libraries/libldap/tls_g.c:793)
   Since tlsg_parse_ciphers is called (libraries/libldap/tls_g.c:318)
   lo->ldo_tls_ciphersuite is non-zero. So the error branch is taken.
   Another hint for the error branch is the error message
   "TLS: could not set cipher list TLSv1." output on stdout (with -d..).
   So the tlsg_ctx_init call returns -1.
   (libraries/libldap/tls_g.c:322)

2) (chronological) second free.
   ldap_pvt_tls_ctx_free calls tlsg_ctx_free via a member function table
   in libraries/libldap/tls2.c:79.
   tlsg_ctx_free calls gnutls_priority_deinit in
   libraries/libldap/tls_g.c:275.
   gnutls_priority_deinit then (double) frees the priority cache in 
   lib/gnutls_priority.c:804.

I would say that this is not a gnutls bug, because gnutls_priority_init
returned non-zero and thus gnutls_priority_deinit must not be called.

So how are these ldap tls objects initialized? As we have seen above (in
the second free) a member function table is used. A bit of grepping
reveals the actual initialization in libraries/libldap/tls2.c:232 and
following. Aparently a ldap tls object is initialized by first calling
*_ctx_new and then *_ctx_init. So tlsg_ctx_new is likely called before
tlsg_ctx_init and initializes the priority cache in
libraries/libldap/tls_g.c:243. Note that the return value of
gnutls_priority_init is *not* checked (bug #1). It is unlikely to fail
due to the fixed and known-good priority string, but it still could fail
(e.g. malloc fail). Then tlsg_parse_ciphers re-initializes the priority
cache. This is a memory leak (bug #2, can also be seen in the valgrind
output).  Even though this re-initialization is checked, it is later
double-freed (bug #3).

Maybe someone with more insight into the code can fix the issue?

Helmut





More information about the Pkg-openldap-devel mailing list