Ver Fonte

Ticket 48132 - modrdn crashes server (invalid read/writes)

Bug Description:  When performing a modrdn stress test using two masters
                  a double free can occur that will lead to a crash.  When
                  the server is under load it might have to retry the modrdn
                  operation.  During this retry the SLAPI_MODRDN_EXISTING_ENTRY
                  entry was previosuly replaced, and it can be freed twice on
                  the second retry..

Fix Description:  Check if entry being retuned form the cache is the same as
                  the entry stored in SLAPI_MODRDN_EXISTING_ENTRY, if it is,
                  set it to NULL so it is not freed again.

https://fedorahosted.org/389/ticket/48132

valgrind: PASSED

Reviewed by: nhosoi(Thanks!)
Mark Reynolds há 10 anos atrás
pai
commit
1d9ae0f4a1
1 ficheiros alterados com 10 adições e 1 exclusões
  1. 10 1
      ldap/servers/slapd/back-ldbm/ldbm_modrdn.c

+ 10 - 1
ldap/servers/slapd/back-ldbm/ldbm_modrdn.c

@@ -279,8 +279,18 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
                 ldap_result_code= LDAP_OPERATIONS_ERROR;
                 goto error_return;
             }
+            slapi_pblock_get( pb, SLAPI_MODRDN_EXISTING_ENTRY, &ent );
             if (cache_is_in_cache(&inst->inst_cache, ec)) {
                 CACHE_REMOVE(&inst->inst_cache, ec);
+                if (ent && (ent == ec->ep_entry)){
+                    /*
+                     * On a retry, it's possible that ec is now stored in the
+                     * pblock as SLAPI_MODRDN_EXISTING_ENTRY.  "ec" will be freed
+                     * by CACHE_RETURN below, so set ent to NULL so don't free
+                     * it again.
+                     */
+                    ent = NULL;
+                }
             }
             CACHE_RETURN(&inst->inst_cache, &ec);
             if (!cache_is_in_cache(&inst->inst_cache, e)) {
@@ -290,7 +300,6 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
                                   slapi_entry_get_dn_const(e->ep_entry));
                 }
             }
-            slapi_pblock_get( pb, SLAPI_MODRDN_EXISTING_ENTRY, &ent );
             if (ent && (ent != original_entry->ep_entry)) {
                 slapi_entry_free(ent);
                 slapi_pblock_set( pb, SLAPI_MODRDN_EXISTING_ENTRY, NULL );