Hi,

Some form of this bug still occurs in icedove 38.1.0-1 in unstable.  Icedove
does not crash at startup, but does when I click the "attach" button in a
compose window.

I dug into it with gdb and found something interesting.  Observe this excerpt
from the gdb session (I have edited the backtrace to keep line lenghts
somewhat sensible):

  (gdb) r
  Starting program: /usr/lib/icedove/icedove-bin 
  [Thread debugging using libthread_db enabled]
  Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
  
  (process:13260): GLib-CRITICAL **: g_slice_set_config: assertion 
'sys_page_size == 0' failed
  [A bunch of "new thread" messages]
  
  Program received signal SIGSEGV, Segmentation fault.
  strtok_r () at ../sysdeps/x86_64/strtok.S:186
  186     ../sysdeps/x86_64/strtok.S: No such file or directory.
  (gdb) bt 4
  #0  0x00007ffff6e04c88 in strtok_r () at ../sysdeps/x86_64/strtok.S:186
  #1  0x00007ffff68d14e7 in ldap_str2charray (str=0x7fffc5bd024c 
"ldap://localhost/";, ...)
      at 
/build/icedove-iBYCQn/icedove-38.1.0/ldap/sdks/c-sdk/ldap/libraries/libldap/charray.c:218
  #2  0x00007fffc5bb86c6 in ldap_url_parselist_int (..., url=0x7fffc5bd024c 
"ldap://localhost/";, ...)
      at url.c:1293
  #3  0x00007fffc5bb87e1 in ldap_url_parselist (..., url=0x7fffc5bd024c 
"ldap://localhost/";)
      at url.c:1318
  #4  0x00007fffc5bba25f in ldap_int_initialize_global_options (...) at 
init.c:543
  (gdb) info symbol 0x00007ffff68d14e7
  ldap_str2charray + 135 in section .text of /usr/lib/icedove/libldap60.so
  (gdb) info symbol 0x00007fffc5bb86c6
  ldap_url_parselist_int + 86 in section .text of 
/usr/lib/x86_64-linux-gnu/libldap_r-2.4.so.2

What's this?  ldap_url_parselist_int and ldap_str2charray are in different
libraries?  Downloading the sources reveals that icedove ships its own copy of
libldap, which interferes with symbol resolution from the system libldap.

Let's dig further.  The relevant line for frame #4 is:

  ldap_url_parselist(&gopts->ldo_defludp, "ldap://localhost/";);

The second argument is passed all the way through to the offending
ldap_str2charray function.  The relevant line there reads:

  for ( s = STRTOK( str, brkstr, &lasts ); s != NULL; s = STRTOK( NULL,

With str being the string in question.  For those not familiar with libc,
strtok operates by finding the separator character and then overwriting it
with a nul byte.  But wait, didn't we have a string literal here?  String
literals are usually stored in a read-only section of memory as confirmed by
gdb and /proc/`pidof icedove`/maps:

  0x00007fffc5bcc300 - 0x00007fffc5bd1a69 is .rodata in 
/usr/lib/x86_64-linux-gnu/libldap_r-2.4.so.2

  7fffc5b8e000-7fffc5bdb000 r-xp 00000000 08:05 920396  
/usr/lib/x86_64-linux-gnu/libldap_r-2.4.so.2.10.5

So it's trying to write into a read-only section of memory and the kernel says
"no, you can't do that".  By contrast, the system libldap's ldap_str2charray
does this as the first thing upon entry:

  /* protect the input string from strtok */
  str = LDAP_STRDUP( str_in );

I don't have a permanent solution, but as a temporary one the library load
order can be tweaked with LD_PRELOAD:

  LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libldap_r-2.4.so.2 icedove

This forces the system libldap to be loaded first, so it resolves with its own
symbols.

-- 
Mikko

Reply via email to