Browse Source

Ticket #48299 - pagedresults - when timed out, search results could have been already freed.

Description: When a search results object is freed, there is a window
until the information is set to the pagedresults handle.  If the paged-
results handle is released due to a timeout in the window, double free
occurs.

This patch sets NULL just before the search results object is freed
in the backend as well as in dse.

Plus, fixed a minor memory leak in pagedresults_parse_control_value.

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

Reviewed and a bug found by [email protected] (Thank you, Thierry!!)
Noriko Hosoi 10 years ago
parent
commit
f90c3a6e19

+ 1 - 0
ldap/servers/slapd/back-ldbm/ldbm_search.c

@@ -1890,6 +1890,7 @@ delete_search_result_set( Slapi_PBlock *pb, back_search_result_set **sr )
             /* If the op is pagedresults, let the module clean up sr. */
             return;
         }
+        pagedresults_set_search_result_pb(pb, NULL, 0);
         slapi_pblock_set(pb, SLAPI_SEARCH_RESULT_SET, NULL);
     }
     if ( NULL != (*sr)->sr_candidates )

+ 1 - 0
ldap/servers/slapd/dse.c

@@ -2830,6 +2830,7 @@ dse_next_search_entry (Slapi_PBlock *pb)
 	/* we reached the end of the list */
 	if (e == NULL)
 	{
+		pagedresults_set_search_result_pb(pb, NULL, 0);
 		dse_search_set_delete (ss);
 		slapi_pblock_set(pb, SLAPI_SEARCH_RESULT_SET, NULL);
 	}

+ 32 - 1
ldap/servers/slapd/pagedresults.c

@@ -172,7 +172,6 @@ pagedresults_parse_control_value( Slapi_PBlock *pb,
     }
     /* reset sizelimit */
     op->o_pagedresults_sizelimit = -1;
-    slapi_ch_free((void **)&cookie.bv_val);
 
     if ((*index > -1) && (*index < conn->c_pagedresults.prl_maxlen)) {
         if (conn->c_pagedresults.prl_list[*index].pr_flags & CONN_FLAG_PAGEDRESULTS_ABANDONED) {
@@ -189,6 +188,7 @@ pagedresults_parse_control_value( Slapi_PBlock *pb,
         LDAPDebug1Arg(LDAP_DEBUG_ANY, "pagedresults_parse_control_value: invalid cookie: %d\n", *index);
     }
 bail:
+    slapi_ch_free((void **)&cookie.bv_val);
     /* cleaning up the rest of the timedout or abandoned if any */
     prp = conn->c_pagedresults.prl_list;
     for (i = 0; i < conn->c_pagedresults.prl_maxlen; i++, prp++) {
@@ -1010,3 +1010,34 @@ pagedresults_is_abandoned_or_notavailable( Connection *conn, int index )
     PR_Unlock(conn->c_mutex);
     return prp->pr_flags & CONN_FLAG_PAGEDRESULTS_ABANDONED;
 }
+
+int
+pagedresults_set_search_result_pb(Slapi_PBlock *pb, void *sr, int locked)
+{
+    int rc = -1;
+    Connection *conn = NULL;
+    Operation *op = NULL;
+    int index = -1;
+    if (!pb) {
+        return 0;
+    }
+    slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+    if (!op_is_pagedresults(op)) {
+        return 0; /* noop */
+    }
+    slapi_pblock_get(pb, SLAPI_CONNECTION, &conn);
+    slapi_pblock_get(pb, SLAPI_PAGED_RESULTS_INDEX, &index);
+    LDAPDebug2Args(LDAP_DEBUG_TRACE,
+                   "--> pagedresults_set_search_result_pb: idx=%d, sr=%p\n", index, sr);
+    if (conn && (index > -1)) {
+        if (!locked) PR_Lock(conn->c_mutex);
+        if (index < conn->c_pagedresults.prl_maxlen) {
+            conn->c_pagedresults.prl_list[index].pr_search_result_set = sr;
+            rc = 0;
+        }
+        if (!locked) PR_Unlock(conn->c_mutex);
+    }
+    LDAPDebug1Arg(LDAP_DEBUG_TRACE,
+                  "<-- pagedresults_set_search_result_pb: %d\n", rc);
+    return rc;
+}

+ 1 - 0
ldap/servers/slapd/proto-slap.h

@@ -1488,6 +1488,7 @@ void op_set_pagedresults(Operation *op);
 void pagedresults_lock(Connection *conn, int index);
 void pagedresults_unlock(Connection *conn, int index);
 int pagedresults_is_abandoned_or_notavailable(Connection *conn, int index);
+int pagedresults_set_search_result_pb(Slapi_PBlock *pb, void *sr, int locked);
 
 /*
  * sort.c