Originally posted as bug for Fedora: https://bugzilla.redhat.com/show_bug.cgi?id=1211871
As a maintainer, I re-post it here in order to get upstream attention to it.
Description of problem:
389 directory can crash when a search for the memory pool file statistics is executed. Investigation shows that __memp_stat can overwrite the allocated memory
Version-Release number of selected component (if applicable):
4.7.25 and later
How reproducible:
hard. the crashes occured occasionally at a customer site, so far it was possible to reproduce the crash only with manually interfering into th etiming in gdb, see below
Steps to Reproduce with libdb as component in 389-ds:
Create and instance with several backends, start the server and run a monitor search, only a couple of files will be open.
attach gdb to slapd and set a breakpoint in __memp_stat()
start the monitor search
when the breakpoint is hit, set another breakpoint in __memp_get_files(), this will be called for each file contained in the mpfstat
when this breakpoint is hit the first time, start a search for a backend and attribute where the index file is not yet open, choose a "long" filename, eg suffix=moremoremore attr is telephonenumber, which will result in "moremoremore/telephonenumber.db4"
continue the thread with the monitor search, the __memp_get_files breakpoint will be hit several times, inparallel the seaarch thjread gets enough time to open the telephonenumber index file and add it to the file list.
After several itearations I got the crash.
Actual results:
Expected results:
Additional info:
In my analysis I think the problem is here in __memp_stat:
/* Per-file statistics. */
if (fspp != NULL) {
*fspp = NULL;
/* Count the MPOOLFILE structures. */
It does not only count the files, but also determines the length of the filenames and calculates the len ot allocate
i = 0;
len = 0;
if ((ret = __memp_walk_files(env,
mp, __memp_count_files, &len, &i, flags)) != 0)
return (ret);
len is the size of memory to allocate
i is the number of files counted
if (i == 0)
return (0);
len += sizeof(DB_MPOOL_FSTAT *); /* Trailing NULL */
/* Allocate space */
if ((ret = __os_umalloc(env, len, fspp)) != 0)
return (ret);
here the space is allocated and used
tfsp = *fspp;
*tfsp = NULL;
/*
* Files may have been opened since we counted, don't walk
* off the end of the allocated space.
*/
this comment indicates that it could happen that files are opened in between and does a countdown of i, stopping if i == 0
this works only if a new file is always appended at the end, if not the required space for file names can increase
if ((ret = __memp_walk_files(env,
mp, __memp_get_files, &tfsp, &i, flags)) != 0)
return (ret);
*++tfsp = NULL;
}
It looks like this was introduced when hash buckets for mpool files were introduced, in my opinion the problem didn't exist in libdb 3.x