ldap/servers/slapd/back-ldbm/idl_new.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
New commits:
commit 0cc661f3c9a1850a29cb89181f94edabc9f47cb5
Author: Rich Megginson <rmeggins(a)redhat.com>
Date: Fri Apr 20 20:15:21 2012 -0600
Ticket #347 - IPA dirsvr seg-fault during system longevity test
https://fedorahosted.org/389/ticket/347
Resolves: Ticket 347
Bug Description: IPA dirsvr seg-fault during system longevity test
Reviewed by: nhosoi, mreynolds (Thanks!)
Branch: master
Fix Description: Somehow the DB_MULTIPLE_NEXT pointer is being set to
an invalid value (-5). This causes the next iteration to return memory
that points to before the stack buffer, causing a seg fault. Valid
values for the pointer are > -1. The value -1 is used as the list terminator
value. The code that constructs the buffer is in the libdb function
__bam_bulk in bt_cursor.c. The fix is to check for a value < -1,
assume the page or value has been deleted out from under us, and do
a dbc->get to get the next buffer full, if any. The code also needs to
check for duplicate IDs being returned. In the failure case described
above, it is possible that the last ID returned in the multiple buffer is
the first ID in the next buffer. In that case, we want to skip the ID that
was already added to the IDL.
Platforms tested: RHEL6 x86_64
Flag Day: no
Doc impact: no
(cherry picked from commit 5d45dd8de06aaee3e0a52c85fa5b3e18febd7a27)
diff --git a/ldap/servers/slapd/back-ldbm/idl_new.c
b/ldap/servers/slapd/back-ldbm/idl_new.c
index d62511c..9cd3daf 100644
--- a/ldap/servers/slapd/back-ldbm/idl_new.c
+++ b/ldap/servers/slapd/back-ldbm/idl_new.c
@@ -242,6 +242,7 @@ IDList * idl_new_fetch(
/* Iterate over the duplicates, amassing them into an IDL */
#ifdef DB_USE_BULK_FETCH
for (;;) {
+ ID lastid = 0;
DB_MULTIPLE_INIT(ptr, &data);
@@ -250,6 +251,13 @@ IDList * idl_new_fetch(
if (dataret.data == NULL) break;
if (ptr == NULL) break;
+ if (*(int32_t *)ptr < -1) {
+ LDAPDebug1Arg(LDAP_DEBUG_TRACE, "DB_MULTIPLE buffer is corrupt;
"
+ "next offset [%d] is less than zero\n",
+ *(int32_t *)ptr);
+ /* retry the read */
+ break;
+ }
if (dataret.size != sizeof(ID)) {
LDAPDebug(LDAP_DEBUG_ANY, "database index is corrupt; "
"key %s has a data item with the wrong size (%d)\n",
@@ -257,7 +265,14 @@ IDList * idl_new_fetch(
goto error;
}
memcpy(&id, dataret.data, sizeof(ID));
-
+ if (id == lastid) { /* dup */
+ LDAPDebug1Arg(LDAP_DEBUG_TRACE, "Detedted duplicate id "
+ "%d due to DB_MULTIPLE error - skipping\n",
+ id);
+ continue; /* get next one */
+ }
+ /* note the last id read to check for dups */
+ lastid = id;
/* we got another ID, add it to our IDL */
idl_rc = idl_append_extend(&idl, id);
if (idl_rc) {