Blame SOURCES/0068-Ticket-48298-ns-slapd-crash-during-ipa-replica-manag.patch

a2f18f
From 5b2efd34c07c65e24f4129430064f7299803dbf8 Mon Sep 17 00:00:00 2001
a2f18f
From: Noriko Hosoi <nhosoi@redhat.com>
a2f18f
Date: Fri, 2 Oct 2015 11:38:01 -0700
a2f18f
Subject: [PATCH 68/68] Ticket #48298 - ns-slapd crash during
a2f18f
 ipa-replica-manage del
a2f18f
a2f18f
Bug Description: The cause of the problem is rather not a race condition but
a2f18f
accessing an already freed agreement in a plug-in:
a2f18f
> The crashed thread is deleting an agreement object, which calls mep_pre_op.
a2f18f
> It eventually calls op_shared_search with the deleted agreement object with
a2f18f
> base scope and filter "(|(objectclass=*)(objectclass=ldapsubentry))"
a2f18f
> Since it is a DSE entry it goes to dse_search, in which it calls agmt_get_
a2f18f
> replarea and crashes in slapi_sdn_copy by NULL dereference in from SDN...
a2f18f
a2f18f
Fix Description: This patch adds the check to agmt_get_replarea, in which if
a2f18f
the agreement is not in the agreement list, it returnes NULL repl area.  When
a2f18f
the NULL repl area is returned the callers back off with an error.
a2f18f
a2f18f
https://fedorahosted.org/389/ticket/48298
a2f18f
a2f18f
Reviewed by rmeggins@redhat.com (Thanks, Rich!)
a2f18f
a2f18f
(cherry picked from commit 3cbdfa613ed8668337213fe9c3c15cf54ce798aa)
a2f18f
(cherry picked from commit f09eb8c0f8ee315b2a20d6460c975a546207411e)
a2f18f
---
a2f18f
 ldap/servers/plugins/replication/repl5.h           |  1 +
a2f18f
 ldap/servers/plugins/replication/repl5_agmt.c      | 17 +++++++++--
a2f18f
 ldap/servers/plugins/replication/repl5_agmtlist.c  | 34 ++++++++++++++++++----
a2f18f
 .../plugins/replication/repl5_inc_protocol.c       | 10 ++++++-
a2f18f
 .../plugins/replication/repl5_replica_config.c     |  6 +++-
a2f18f
 .../plugins/replication/repl5_tot_protocol.c       | 12 ++++++--
a2f18f
 .../plugins/replication/repl_session_plugin.c      | 22 +++++++++++---
a2f18f
 .../plugins/replication/windows_protocol_util.c    | 12 ++++++++
a2f18f
 8 files changed, 98 insertions(+), 16 deletions(-)
a2f18f
a2f18f
diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h
a2f18f
index 17282bb..df92ca0 100644
a2f18f
--- a/ldap/servers/plugins/replication/repl5.h
a2f18f
+++ b/ldap/servers/plugins/replication/repl5.h
a2f18f
@@ -390,6 +390,7 @@ void agmtlist_shutdown();
a2f18f
 void agmtlist_notify_all(Slapi_PBlock *pb);
a2f18f
 Object* agmtlist_get_first_agreement_for_replica (Replica *r);
a2f18f
 Object* agmtlist_get_next_agreement_for_replica (Replica *r, Object *prev);
a2f18f
+int agmtlist_agmt_exists(const Repl_Agmt *ra);
a2f18f
 
a2f18f
 /* In repl5_backoff.c */
a2f18f
 typedef struct backoff_timer Backoff_Timer;
a2f18f
diff --git a/ldap/servers/plugins/replication/repl5_agmt.c b/ldap/servers/plugins/replication/repl5_agmt.c
a2f18f
index f84eacb..76d26a1 100644
a2f18f
--- a/ldap/servers/plugins/replication/repl5_agmt.c
a2f18f
+++ b/ldap/servers/plugins/replication/repl5_agmt.c
a2f18f
@@ -696,6 +696,12 @@ agmt_start(Repl_Agmt *ra)
a2f18f
      * index.
a2f18f
      */
a2f18f
     repl_sdn = agmt_get_replarea(ra);
a2f18f
+    if (!repl_sdn) {
a2f18f
+        slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
a2f18f
+                        "agmt_start: failed to get repl area.  Please check agreement.\n");
a2f18f
+        prot_free(&prot;;
a2f18f
+        return -1;
a2f18f
+    }
a2f18f
 
a2f18f
     pb = slapi_pblock_new();
a2f18f
     attrs[0] = (char*)type_agmtMaxCSN;
a2f18f
@@ -770,7 +776,7 @@ agmt_start(Repl_Agmt *ra)
a2f18f
                                 slapi_rdn_get_value_by_ref(slapi_rdn_get_rdn(ra->rdn)),
a2f18f
                                 ra->hostname, ra->port);
a2f18f
                     if(strstr(maxcsns[i], buf) || strstr(maxcsns[i], unavail_buf)){
a2f18f
-                    	/* Set the maxcsn */
a2f18f
+                        /* Set the maxcsn */
a2f18f
                         slapi_ch_free_string(&ra->maxcsn);
a2f18f
                         ra->maxcsn = slapi_ch_strdup(maxcsns[i]);
a2f18f
                         ra->consumerRID = agmt_maxcsn_get_rid(maxcsns[i]);
a2f18f
@@ -976,8 +982,11 @@ agmt_get_bindmethod(const Repl_Agmt *ra)
a2f18f
 Slapi_DN *
a2f18f
 agmt_get_replarea(const Repl_Agmt *ra)
a2f18f
 {
a2f18f
-	Slapi_DN *return_value;
a2f18f
+	Slapi_DN *return_value = NULL;
a2f18f
 	PR_ASSERT(NULL != ra);
a2f18f
+	if (!agmtlist_agmt_exists(ra)) {
a2f18f
+		return return_value;
a2f18f
+	}
a2f18f
 	PR_Lock(ra->lock);
a2f18f
 	return_value = slapi_sdn_new();
a2f18f
 	slapi_sdn_copy(ra->replarea, return_value);
a2f18f
@@ -2690,6 +2699,9 @@ get_agmt_status(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter,
a2f18f
 		Object *repl_obj = NULL;
a2f18f
 
a2f18f
 		replarea_sdn = agmt_get_replarea(ra);
a2f18f
+		if (!replarea_sdn) {
a2f18f
+			goto bail;
a2f18f
+		}
a2f18f
 		repl_obj = replica_get_replica_from_dn(replarea_sdn);
a2f18f
 		slapi_sdn_free(&replarea_sdn);
a2f18f
 		if (repl_obj) {
a2f18f
@@ -2748,6 +2760,7 @@ get_agmt_status(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter,
a2f18f
 			slapi_entry_add_string(e, "nsds5replicaLastInitStatus", ra->last_init_status);
a2f18f
 		}
a2f18f
 	}
a2f18f
+bail:
a2f18f
 	return SLAPI_DSE_CALLBACK_OK;
a2f18f
 }
a2f18f
 
a2f18f
diff --git a/ldap/servers/plugins/replication/repl5_agmtlist.c b/ldap/servers/plugins/replication/repl5_agmtlist.c
a2f18f
index 34650b4..f50862f 100644
a2f18f
--- a/ldap/servers/plugins/replication/repl5_agmtlist.c
a2f18f
+++ b/ldap/servers/plugins/replication/repl5_agmtlist.c
a2f18f
@@ -109,6 +109,24 @@ agmtlist_release_agmt(Repl_Agmt *ra)
a2f18f
 	}
a2f18f
 }
a2f18f
 
a2f18f
+int
a2f18f
+agmtlist_agmt_exists(const Repl_Agmt *ra)
a2f18f
+{
a2f18f
+	Object *ro;
a2f18f
+	int exists = 0;
a2f18f
+
a2f18f
+	PR_ASSERT(NULL != agmt_set);
a2f18f
+	if (!ra) {
a2f18f
+		return exists;
a2f18f
+	}
a2f18f
+	ro = objset_find(agmt_set, agmt_ptr_cmp, (const void *)ra);
a2f18f
+	if (ro) {
a2f18f
+		exists = 1;
a2f18f
+		object_release(ro);
a2f18f
+	}
a2f18f
+	return exists;
a2f18f
+}
a2f18f
+
a2f18f
 
a2f18f
 /*
a2f18f
  * Note: when we add the new object, we have a reference to it. We hold
a2f18f
@@ -135,6 +153,9 @@ add_new_agreement(Slapi_Entry *e)
a2f18f
 
a2f18f
     /* get the replica for this agreement */
a2f18f
     replarea_sdn = agmt_get_replarea(ra);
a2f18f
+    if (!replarea_sdn) {
a2f18f
+        return 1;
a2f18f
+    }
a2f18f
     repl_obj = replica_get_replica_from_dn(replarea_sdn);
a2f18f
     slapi_sdn_free(&replarea_sdn);
a2f18f
     if (repl_obj) {
a2f18f
@@ -841,13 +862,16 @@ Object* agmtlist_get_next_agreement_for_replica (Replica *r, Object *prev)
a2f18f
     else
a2f18f
         obj = objset_first_obj(agmt_set);
a2f18f
         
a2f18f
-    while (obj)
a2f18f
-    {
a2f18f
+    for ( ; obj; obj = objset_next_obj(agmt_set, obj)) {
a2f18f
         agmt = (Repl_Agmt*)object_get_data (obj);
a2f18f
-        PR_ASSERT (agmt);
a2f18f
+        if (!agmt) {
a2f18f
+            continue;
a2f18f
+        }
a2f18f
 
a2f18f
         agmt_root = agmt_get_replarea(agmt);
a2f18f
-        PR_ASSERT (agmt_root);
a2f18f
+        if (!agmt_root) {
a2f18f
+            continue;
a2f18f
+        }
a2f18f
 
a2f18f
         if (slapi_sdn_compare (replica_root, agmt_root) == 0)
a2f18f
         {
a2f18f
@@ -856,7 +880,7 @@ Object* agmtlist_get_next_agreement_for_replica (Replica *r, Object *prev)
a2f18f
         }
a2f18f
 
a2f18f
         slapi_sdn_free (&agmt_root);
a2f18f
-        obj = objset_next_obj(agmt_set, obj);
a2f18f
+
a2f18f
     }
a2f18f
 
a2f18f
     return NULL;
a2f18f
diff --git a/ldap/servers/plugins/replication/repl5_inc_protocol.c b/ldap/servers/plugins/replication/repl5_inc_protocol.c
a2f18f
index 7680340..244bbb2 100644
a2f18f
--- a/ldap/servers/plugins/replication/repl5_inc_protocol.c
a2f18f
+++ b/ldap/servers/plugins/replication/repl5_inc_protocol.c
a2f18f
@@ -1906,6 +1906,7 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu
a2f18f
 		{
a2f18f
 			Replica *replica;
a2f18f
 			ReplicaId rid = -1; /* Used to create the replica keep alive subentry */
a2f18f
+			Slapi_DN *replarea_sdn = NULL;
a2f18f
 			replica = (Replica*) object_get_data(prp->replica_object);
a2f18f
 			if (replica)
a2f18f
 			{
a2f18f
@@ -1914,7 +1915,14 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu
a2f18f
 			slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
a2f18f
 					"%s: skipped updates was definitely too high (%d) update the subentry now\n",
a2f18f
 					agmt_get_long_name(prp->agmt), skipped_updates);
a2f18f
-			replica_subentry_update(agmt_get_replarea(prp->agmt), rid);
a2f18f
+			replarea_sdn = agmt_get_replarea(prp->agmt);
a2f18f
+			if (!replarea_sdn) {
a2f18f
+				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
a2f18f
+				                "send_updates: Unknown replication area due to agreement not found.");
a2f18f
+				return_value = UPDATE_FATAL_ERROR;
a2f18f
+			} else {
a2f18f
+				replica_subentry_update(replarea_sdn, rid);
a2f18f
+			}
a2f18f
 		}
a2f18f
 		/* Terminate the results reading thread */
a2f18f
 		if (!prp->repl50consumer) 
a2f18f
diff --git a/ldap/servers/plugins/replication/repl5_replica_config.c b/ldap/servers/plugins/replication/repl5_replica_config.c
a2f18f
index 8d3c481..e85ae3e 100644
a2f18f
--- a/ldap/servers/plugins/replication/repl5_replica_config.c
a2f18f
+++ b/ldap/servers/plugins/replication/repl5_replica_config.c
a2f18f
@@ -2368,13 +2368,17 @@ replica_send_cleanruv_task(Repl_Agmt *agmt, cleanruv_data *clean_data)
a2f18f
         conn_delete_internal_ext(conn);
a2f18f
         return;
a2f18f
     }
a2f18f
-    val.bv_len = PR_snprintf(data, sizeof(data), "CLEANRUV%d", clean_data->rid);
a2f18f
     sdn = agmt_get_replarea(agmt);
a2f18f
+    if (!sdn) {
a2f18f
+        conn_delete_internal_ext(conn);
a2f18f
+        return;
a2f18f
+    }
a2f18f
     mod.mod_op  = LDAP_MOD_ADD|LDAP_MOD_BVALUES;
a2f18f
     mod.mod_type = "nsds5task";
a2f18f
     mod.mod_bvalues = vals;
a2f18f
     vals [0] = &val;
a2f18f
     vals [1] = NULL;
a2f18f
+    val.bv_len = PR_snprintf(data, sizeof(data), "CLEANRUV%d", clean_data->rid);
a2f18f
     val.bv_val = data;
a2f18f
     mods[0] = &mod;
a2f18f
     mods[1] = NULL;
a2f18f
diff --git a/ldap/servers/plugins/replication/repl5_tot_protocol.c b/ldap/servers/plugins/replication/repl5_tot_protocol.c
a2f18f
index 7da893a..16b51b5 100644
a2f18f
--- a/ldap/servers/plugins/replication/repl5_tot_protocol.c
a2f18f
+++ b/ldap/servers/plugins/replication/repl5_tot_protocol.c
a2f18f
@@ -329,6 +329,13 @@ repl5_tot_run(Private_Repl_Protocol *prp)
a2f18f
 		goto done;
a2f18f
 	}
a2f18f
 
a2f18f
+	area_sdn = agmt_get_replarea(prp->agmt);
a2f18f
+	if (!area_sdn) {
a2f18f
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Warning: unable to "
a2f18f
+		                "get repl area.  Please check agreement.\n");
a2f18f
+		goto done;
a2f18f
+	}
a2f18f
+
a2f18f
 	conn_set_timeout(prp->conn, agmt_get_timeout(prp->agmt));
a2f18f
 
a2f18f
     /* acquire remote replica */
a2f18f
@@ -387,11 +394,10 @@ repl5_tot_run(Private_Repl_Protocol *prp)
a2f18f
     slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Beginning total update of replica "
a2f18f
 		"\"%s\".\n", agmt_get_long_name(prp->agmt));
a2f18f
 
a2f18f
-    pb = slapi_pblock_new ();
a2f18f
+    /* RMREPL - need to send schema here */
a2f18f
 
a2f18f
-	/* RMREPL - need to send schema here */
a2f18f
+    pb = slapi_pblock_new ();
a2f18f
 
a2f18f
-	area_sdn = agmt_get_replarea(prp->agmt);
a2f18f
     /* we need to provide managedsait control so that referral entries can
a2f18f
        be replicated */
a2f18f
     ctrls = (LDAPControl **)slapi_ch_calloc (3, sizeof (LDAPControl *));
a2f18f
diff --git a/ldap/servers/plugins/replication/repl_session_plugin.c b/ldap/servers/plugins/replication/repl_session_plugin.c
a2f18f
index 1c04089..2fa993d 100644
a2f18f
--- a/ldap/servers/plugins/replication/repl_session_plugin.c
a2f18f
+++ b/ldap/servers/plugins/replication/repl_session_plugin.c
a2f18f
@@ -48,6 +48,10 @@ repl_session_plugin_call_agmt_init_cb(Repl_Agmt *ra)
a2f18f
     }
a2f18f
     if (initfunc) {
a2f18f
         replarea = agmt_get_replarea(ra);
a2f18f
+        if (!replarea) {
a2f18f
+            LDAPDebug0Args(LDAP_DEBUG_ANY, "repl_session_plugin_call_agmt_init_cb -- Aborted -- No replication area\n");
a2f18f
+            return;
a2f18f
+        }
a2f18f
         cookie = (*initfunc)(replarea);
a2f18f
         slapi_sdn_free(&replarea);
a2f18f
     }
a2f18f
@@ -73,8 +77,11 @@ repl_session_plugin_call_pre_acquire_cb(const Repl_Agmt *ra, int is_total,
a2f18f
 
a2f18f
     if (thefunc) {
a2f18f
         replarea = agmt_get_replarea(ra);
a2f18f
-        rc = (*thefunc)(agmt_get_priv(ra), replarea, is_total,
a2f18f
-                data_guid, data);
a2f18f
+        if (!replarea) {
a2f18f
+            LDAPDebug0Args(LDAP_DEBUG_ANY, "repl_session_plugin_call_pre_acquire_cb -- Aborted -- No replication area\n");
a2f18f
+            return 1;
a2f18f
+        }
a2f18f
+        rc = (*thefunc)(agmt_get_priv(ra), replarea, is_total, data_guid, data);
a2f18f
         slapi_sdn_free(&replarea);
a2f18f
     }
a2f18f
 
a2f18f
@@ -95,8 +102,11 @@ repl_session_plugin_call_post_acquire_cb(const Repl_Agmt *ra, int is_total,
a2f18f
 
a2f18f
     if (thefunc) {
a2f18f
         replarea = agmt_get_replarea(ra);
a2f18f
-        rc = (*thefunc)(agmt_get_priv(ra), replarea,
a2f18f
-		is_total, data_guid, data);
a2f18f
+        if (!replarea) {
a2f18f
+            LDAPDebug0Args(LDAP_DEBUG_ANY, "repl_session_plugin_call_post_acquire_cb -- Aborted -- No replication area\n");
a2f18f
+            return 1;
a2f18f
+        }
a2f18f
+        rc = (*thefunc)(agmt_get_priv(ra), replarea, is_total, data_guid, data);
a2f18f
         slapi_sdn_free(&replarea);
a2f18f
     }
a2f18f
 
a2f18f
@@ -151,6 +161,10 @@ repl_session_plugin_call_destroy_agmt_cb(const Repl_Agmt *ra)
a2f18f
 
a2f18f
     if (thefunc) {
a2f18f
         replarea = agmt_get_replarea(ra);
a2f18f
+        if (!replarea) {
a2f18f
+            LDAPDebug0Args(LDAP_DEBUG_ANY, "repl_session_plugin_call_destroy_agmt_cb -- Aborted -- No replication area\n");
a2f18f
+            return;
a2f18f
+        }
a2f18f
         (*thefunc)(agmt_get_priv(ra), replarea);
a2f18f
         slapi_sdn_free(&replarea);
a2f18f
     }
a2f18f
diff --git a/ldap/servers/plugins/replication/windows_protocol_util.c b/ldap/servers/plugins/replication/windows_protocol_util.c
a2f18f
index 5c12af7..084b520 100644
a2f18f
--- a/ldap/servers/plugins/replication/windows_protocol_util.c
a2f18f
+++ b/ldap/servers/plugins/replication/windows_protocol_util.c
a2f18f
@@ -5319,6 +5319,13 @@ windows_update_local_entry(Private_Repl_Protocol *prp,Slapi_Entry *remote_entry,
a2f18f
 		 * in the groups caused by moving member entries.
a2f18f
 		 * We need to update the local groups manually... */
a2f18f
 		local_subtree = agmt_get_replarea(prp->agmt); 
a2f18f
+		if (!local_subtree) {
a2f18f
+			slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name,
a2f18f
+			                "failed to get local subtree from agreement\n");
a2f18f
+			local_entry = orig_local_entry;
a2f18f
+			orig_local_entry = NULL;
a2f18f
+			goto bail;
a2f18f
+		}
a2f18f
 		local_subtree_sdn = local_subtree;
a2f18f
 		orig_local_sdn = slapi_entry_get_sdn_const(orig_local_entry);
a2f18f
 		escaped_filter_val = slapi_escape_filter_value((char *)slapi_sdn_get_ndn(orig_local_sdn),
a2f18f
@@ -5651,6 +5658,11 @@ windows_search_local_entry_by_uniqueid(Private_Repl_Protocol *prp,
a2f18f
 	*ret_entry = NULL;
a2f18f
 	if (is_global) { /* Search from the suffix (rename case) */
a2f18f
 		local_subtree = agmt_get_replarea(prp->agmt); 
a2f18f
+		if (!local_subtree) {
a2f18f
+			slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name,
a2f18f
+			                "failed to get local subtree from agreement\n");
a2f18f
+			return LDAP_PARAM_ERROR;
a2f18f
+		}
a2f18f
 		local_subtree_sdn = local_subtree;
a2f18f
 	} else {
a2f18f
 		local_subtree_sdn = windows_private_get_directory_treetop(prp->agmt);
a2f18f
-- 
a2f18f
1.9.3
a2f18f