Skip to Main Content

Berkeley DB Family

Bug report: heap corruption by memp_stat

jstanekApr 16 2015 — edited May 12 2015

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

Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Jun 9 2015
Added on Apr 16 2015
3 comments
1,422 views