This is an automated email from the git hooks/post-receive script.
firstyear pushed a commit to branch master
in repository 389-ds-base.
commit b851f16ec8103628c1d2eff053475b1375e6be78
Author: William Brown <firstyear(a)redhat.com>
Date: Fri Aug 18 13:00:46 2017 +1000
Ticket 49356 - mapping tree crash can occur during tot init
Bug Description: Two faults were found in the handling of the mapping
tree of 389 directory server. The first fault was that the tree-free
check was not performed atomically and may cause an incorrect operations
error to be returned. The second was that during a total init the referral
would not lock the be, but the pw_verify code assumed a be was locked.
This caused a segfault.
Fix Description: Fix the freed check to use atomics. Fix the pw_verify
to assert be is NULL (which is correct, there is no backend).
https://pagure.io/389-ds-base/issue/49356
Author: wibrown
Review by: mreynolds (THanks!)
---
.../mapping_tree/referral_during_tot_init.py | 57 +++++++++++
ldap/servers/slapd/fedse.c | 10 ++
ldap/servers/slapd/main.c | 9 +-
ldap/servers/slapd/mapping_tree.c | 106 +++++++++++----------
ldap/servers/slapd/pw_verify.c | 8 +-
5 files changed, 129 insertions(+), 61 deletions(-)
diff --git a/dirsrvtests/tests/suites/mapping_tree/referral_during_tot_init.py
b/dirsrvtests/tests/suites/mapping_tree/referral_during_tot_init.py
new file mode 100644
index 0000000..e5aee7d
--- /dev/null
+++ b/dirsrvtests/tests/suites/mapping_tree/referral_during_tot_init.py
@@ -0,0 +1,57 @@
+# --- BEGIN COPYRIGHT BLOCK ---
+# Copyright (C) 2017 Red Hat, Inc.
+# All rights reserved.
+#
+# License: GPL (version 3 or any later version).
+# See LICENSE for details.
+# --- END COPYRIGHT BLOCK ---
+#
+import ldap
+import pytest
+from lib389.topologies import topology_m2
+from lib389._constants import (DEFAULT_SUFFIX, HOST_MASTER_2, PORT_MASTER_2, TASK_WAIT)
+
+from lib389.idm.user import (TEST_USER_PROPERTIES, UserAccounts)
+
+def test_referral_during_tot(topology_m2):
+
+ master1 = topology_m2.ms["master1"]
+ master2 = topology_m2.ms["master2"]
+
+ # Create a bunch of entries on master1
+ ldif_dir = master1.get_ldif_dir()
+ import_ldif = ldif_dir + '/ref_during_tot_import.ldif'
+ master1.buildLDIF(10000, import_ldif)
+
+ master1.stop()
+ try:
+ master1.ldif2db(bename=None, excludeSuffixes=None, encrypt=False,
suffixes=[DEFAULT_SUFFIX], import_file=import_ldif)
+ except:
+ pass
+ # master1.tasks.importLDIF(suffix=DEFAULT_SUFFIX, input_file=import_ldif,
args={TASK_WAIT: True})
+ master1.start()
+ users = UserAccounts(master1, DEFAULT_SUFFIX, rdn='ou=Accounting')
+
+ u = users.create(properties=TEST_USER_PROPERTIES)
+ u.set('userPassword', 'password')
+
+ binddn = u.dn
+ bindpw = 'password'
+
+ # Now export them to master2
+ master1.agreement.init(DEFAULT_SUFFIX, HOST_MASTER_2, PORT_MASTER_2)
+
+ # While that's happening try to bind as a user to master 2
+ # This should trigger the referral code.
+ for i in range(0, 100):
+ conn = ldap.initialize(master2.toLDAPURL())
+ conn.set_option(ldap.OPT_REFERRALS, False)
+ try:
+ conn.simple_bind_s(binddn, bindpw)
+ conn.unbind_s()
+ except ldap.REFERRAL:
+ pass
+
+ # Done.
+
+
diff --git a/ldap/servers/slapd/fedse.c b/ldap/servers/slapd/fedse.c
index 6442267..f225c40 100644
--- a/ldap/servers/slapd/fedse.c
+++ b/ldap/servers/slapd/fedse.c
@@ -1870,6 +1870,16 @@ setup_internal_backends(char *configdir)
be_addsuffix(be, &monitor);
be_addsuffix(be, &config);
+ /*
+ * Now that the be's are in place, we can
+ * setup the mapping tree.
+ */
+
+ if (mapping_tree_init()) {
+ slapi_log_err(SLAPI_LOG_EMERG, "setup_internal_backends",
"Failed to init mapping tree\n");
+ exit(1);
+ }
+
add_internal_entries();
add_easter_egg_entry();
diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c
index 520e1ab..ddaceff 100644
--- a/ldap/servers/slapd/main.c
+++ b/ldap/servers/slapd/main.c
@@ -824,6 +824,7 @@ main(int argc, char **argv)
}
entry_computed_attr_init();
+ /* This will setup the mapping tree too */
if (0 == setup_internal_backends(slapdFrontendConfig->configdir)) {
slapi_log_err(SLAPI_LOG_EMERG, "main",
"The configuration files in directory %s could not be read
or were not found. Please refer to the error log or output for more
information.\n",
@@ -1077,14 +1078,6 @@ main(int argc, char **argv)
ps_init_psearch_system(); /* must come before plugin_startall() */
- /* Initailize the mapping tree */
-
- if (mapping_tree_init()) {
- slapi_log_err(SLAPI_LOG_EMERG, "main", "Failed to init mapping
tree\n");
- return_value = 1;
- goto cleanup;
- }
-
/* initialize UniqueID generator - must be done once backends are started
and event queue is initialized but before plugins are started */
diff --git a/ldap/servers/slapd/mapping_tree.c b/ldap/servers/slapd/mapping_tree.c
index a708708..651d70e 100644
--- a/ldap/servers/slapd/mapping_tree.c
+++ b/ldap/servers/slapd/mapping_tree.c
@@ -87,12 +87,12 @@ struct mt_node
* release backend lock
*
*/
-static Slapi_RWLock *myLock; /* global lock on the mapping tree structures */
+static Slapi_RWLock *myLock = NULL; /* global lock on the mapping tree structures */
static mapping_tree_node *mapping_tree_root = NULL;
-static int mapping_tree_inited = 0;
-static int mapping_tree_freed = 0;
+static int32_t mapping_tree_inited = 0;
+static int32_t mapping_tree_freed = 0;
static int extension_type = -1; /* type returned from the factory */
/* The different states a mapping tree node can be in. */
@@ -1583,15 +1583,17 @@ add_internal_mapping_tree_node(const char *subtree, Slapi_Backend
*be, mapping_t
Slapi_DN *dn;
mapping_tree_node *node;
backend **be_list = (backend **)slapi_ch_malloc(sizeof(backend *));
+ int *be_states = (int *)slapi_ch_malloc(sizeof(int));
be_list[0] = be;
+ be_states[0] = SLAPI_BE_STATE_ON;
dn = slapi_sdn_new_dn_byval(subtree);
node = mapping_tree_node_new(
dn,
be_list,
NULL, /* backend_name */
- NULL,
+ be_states, /* be state */
1, /* number of backends at this node */
1, /* size of backend list structure */
NULL, /* referral */
@@ -1645,17 +1647,20 @@ mapping_tree_init()
/* we call this function from a single thread, so it should be ok */
- if (mapping_tree_freed) {
+ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
/* shutdown has been detected */
return 0;
}
- if (mapping_tree_inited)
- return 0;
-
/* ONREPL - I have moved this up because otherwise we can endup calling this
* function recursively */
+ if (myLock != NULL) {
+ return 0;
+ }
+ myLock = slapi_new_rwlock();
+ slapi_rwlock_wrlock(myLock);
+ /* Should be fenced by the rwlock. */
mapping_tree_inited = 1;
slapi_register_supported_control(MTN_CONTROL_USE_ONE_BACKEND_OID,
@@ -1663,8 +1668,6 @@ mapping_tree_init()
slapi_register_supported_control(MTN_CONTROL_USE_ONE_BACKEND_EXT_OID,
SLAPI_OPERATION_SEARCH);
- myLock = slapi_new_rwlock();
-
be = slapi_be_select_by_instance_name(DSE_BACKEND);
mapping_tree_root = add_internal_mapping_tree_node("", be, NULL);
@@ -1680,6 +1683,8 @@ mapping_tree_init()
node = add_internal_mapping_tree_node("cn=schema", be, mapping_tree_root);
mapping_tree_node_add_child(mapping_tree_root, node);
+ slapi_rwlock_unlock(myLock);
+
/*
* Now we need to look under cn=mapping tree, cn=config to find the rest
* of the mapping tree entries.
@@ -1687,10 +1692,14 @@ mapping_tree_init()
* calls mapping_tree_node_get_children with the special case for the
* root node.
*/
- if (mapping_tree_node_get_children(mapping_tree_root, 1))
+
+ if (mapping_tree_node_get_children(mapping_tree_root, 1)) {
return -1;
+ }
+ slapi_rwlock_wrlock(myLock);
mtn_create_extension(mapping_tree_root);
+ slapi_rwlock_unlock(myLock);
/* setup the dse callback functions for the ldbm instance config entry */
{
@@ -1762,7 +1771,7 @@ mapping_tree_free()
slapi_unregister_backend_state_change_all();
/* recursively free tree nodes */
mtn_free_node(&mapping_tree_root);
- mapping_tree_freed = 1;
+ __atomic_store_4(&mapping_tree_freed, 1, __ATOMIC_RELAXED);
}
/* This function returns the first node to parse when a search is done
@@ -2013,14 +2022,12 @@ slapi_dn_write_needs_referral(Slapi_DN *target_sdn, Slapi_Entry
**referral)
mapping_tree_node *target_node = NULL;
int ret = 0;
- if (mapping_tree_freed) {
+ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
/* shutdown detected */
goto done;
}
- if (!mapping_tree_inited) {
- mapping_tree_init();
- }
+ PR_ASSERT(mapping_tree_inited == 1);
if (target_sdn) {
mtn_lock();
@@ -2086,7 +2093,7 @@ slapi_mapping_tree_select(Slapi_PBlock *pb, Slapi_Backend **be,
Slapi_Entry **re
int fixup = 0;
- if (mapping_tree_freed) {
+ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
/* shutdown detected */
return LDAP_OPERATIONS_ERROR;
}
@@ -2104,9 +2111,7 @@ slapi_mapping_tree_select(Slapi_PBlock *pb, Slapi_Backend **be,
Slapi_Entry **re
target_sdn = operation_get_target_spec(op);
fixup = operation_is_flag_set(op, OP_FLAG_TOMBSTONE_FIXUP);
- if (!mapping_tree_inited) {
- mapping_tree_init();
- }
+ PR_ASSERT(mapping_tree_inited == 1);
be[0] = NULL;
if (referral) {
@@ -2117,8 +2122,9 @@ slapi_mapping_tree_select(Slapi_PBlock *pb, Slapi_Backend **be,
Slapi_Entry **re
/* Get the mapping tree node that is the best match for the target dn. */
target_node = slapi_get_mapping_tree_node_by_dn(target_sdn);
- if (target_node == NULL)
+ if (target_node == NULL) {
target_node = mapping_tree_root;
+ }
/* The processing of the base scope root DSE search and all other LDAP operations on
""
* will be transferred to the internal DSE backend
@@ -2192,7 +2198,7 @@ slapi_mapping_tree_select_all(Slapi_PBlock *pb, Slapi_Backend
**be_list, Slapi_E
int flag_partial_result = 0;
int op_type;
- if (mapping_tree_freed) {
+ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
return LDAP_OPERATIONS_ERROR;
}
@@ -2212,9 +2218,7 @@ slapi_mapping_tree_select_all(Slapi_PBlock *pb, Slapi_Backend
**be_list, Slapi_E
slapi_pblock_get(pb, SLAPI_OPERATION_TYPE, &op_type);
slapi_pblock_get(pb, SLAPI_SEARCH_SCOPE, &scope);
- if (!mapping_tree_inited) {
- mapping_tree_init();
- }
+ PR_ASSERT(mapping_tree_inited == 1);
mtn_lock();
@@ -2354,7 +2358,7 @@ slapi_mapping_tree_select_and_check(Slapi_PBlock *pb, char *newdn,
Slapi_Backend
int ret;
int need_unlock = 0;
- if (mapping_tree_freed) {
+ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
return LDAP_OPERATIONS_ERROR;
}
@@ -2520,7 +2524,7 @@ mtn_get_be(mapping_tree_node *target_node, Slapi_PBlock *pb,
Slapi_Backend **be,
int flag_stop = 0;
struct slapi_componentid *cid = NULL;
- if (mapping_tree_freed) {
+ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
/* shut down detected */
return LDAP_OPERATIONS_ERROR;
}
@@ -2602,21 +2606,22 @@ mtn_get_be(mapping_tree_node *target_node, Slapi_PBlock *pb,
Slapi_Backend **be,
} else {
/* This MTN has not been linked to its backend
* instance yet. */
- target_node->mtn_be[*index] =
- slapi_be_select_by_instance_name(
- target_node->mtn_backend_names[*index]);
- *be = target_node->mtn_be[*index];
- if (*be == NULL) {
- slapi_log_err(SLAPI_LOG_BACKLDBM, "mtn_get_be",
- "Warning: Mapping tree node entry for %s
"
- "point to an unknown backend :
%s\n",
- slapi_sdn_get_dn(target_node->mtn_subtree),
- target_node->mtn_backend_names[*index]);
- /* Well there's still not backend instance for
- * this MTN, so let's have the default backend
- * deal with this.
- */
- *be = defbackend_get_backend();
+ /* WARNING: internal memory dse backends don't provide NAMES
*/
+ if (target_node->mtn_backend_names != NULL) {
+ target_node->mtn_be[*index] =
slapi_be_select_by_instance_name(target_node->mtn_backend_names[*index]);
+ *be = target_node->mtn_be[*index];
+ if (*be == NULL) {
+ slapi_log_err(SLAPI_LOG_BACKLDBM,
"mtn_get_be",
+ "Warning: Mapping tree node entry for
%s "
+ "point to an unknown backend :
%s\n",
+
slapi_sdn_get_dn(target_node->mtn_subtree),
+
target_node->mtn_backend_names[*index]);
+ /* Well there's still not backend instance for
+ * this MTN, so let's have the default backend
+ * deal with this.
+ */
+ *be = defbackend_get_backend();
+ }
}
}
}
@@ -2628,10 +2633,11 @@ mtn_get_be(mapping_tree_node *target_node, Slapi_PBlock *pb,
Slapi_Backend **be,
result = LDAP_OPERATIONS_ERROR;
*be = defbackend_get_backend();
}
- if (flag_stop)
+ if (flag_stop) {
*index = SLAPI_BE_NO_BACKEND;
- else
+ } else {
(*index)++;
+ }
}
}
} else {
@@ -2706,7 +2712,7 @@ best_matching_child(mapping_tree_node *parent,
mapping_tree_node *highest_match_node = NULL;
mapping_tree_node *current;
- if (mapping_tree_freed) {
+ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
/* shutdown detected */
return NULL;
}
@@ -2733,7 +2739,7 @@ mtn_get_mapping_tree_node_by_entry(mapping_tree_node *node, const
Slapi_DN *dn)
{
mapping_tree_node *found_node = NULL;
- if (mapping_tree_freed) {
+ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
/* shutdown detected */
return NULL;
}
@@ -2776,7 +2782,7 @@ slapi_get_mapping_tree_node_by_dn(const Slapi_DN *dn)
mapping_tree_node *current_best_match = mapping_tree_root;
mapping_tree_node *next_best_match = mapping_tree_root;
- if (mapping_tree_freed) {
+ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
/* shutdown detected */
return NULL;
}
@@ -2810,7 +2816,7 @@ get_mapping_tree_node_by_name(mapping_tree_node *node, char
*be_name)
int i;
mapping_tree_node *found_node = NULL;
- if (mapping_tree_freed) {
+ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
/* shutdown detected */
return NULL;
}
@@ -2857,7 +2863,7 @@ slapi_get_mapping_tree_node_configdn(const Slapi_DN *root)
{
char *dn = NULL;
- if (mapping_tree_freed) {
+ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
/* shutdown detected */
return NULL;
}
@@ -2884,7 +2890,7 @@ slapi_get_mapping_tree_node_configsdn(const Slapi_DN *root)
char *dn = NULL;
Slapi_DN *sdn = NULL;
- if (mapping_tree_freed) {
+ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) {
/* shutdown detected */
return NULL;
}
diff --git a/ldap/servers/slapd/pw_verify.c b/ldap/servers/slapd/pw_verify.c
index ab0355a..c188953 100644
--- a/ldap/servers/slapd/pw_verify.c
+++ b/ldap/servers/slapd/pw_verify.c
@@ -58,12 +58,14 @@ pw_verify_be_dn(Slapi_PBlock *pb, Slapi_Entry **referral)
int rc = SLAPI_BIND_SUCCESS;
Slapi_Backend *be = NULL;
- if (slapi_mapping_tree_select(pb, &be, referral, NULL, 0) != LDAP_SUCCESS) {
+ int mt_result = slapi_mapping_tree_select(pb, &be, referral, NULL, 0);
+ if (mt_result != LDAP_SUCCESS) {
return SLAPI_BIND_NO_BACKEND;
}
if (*referral) {
- slapi_be_Unlock(be);
+ /* If we have a referral, this is NULL */
+ PR_ASSERT(be == NULL);
return SLAPI_BIND_REFERRAL;
}
@@ -128,7 +130,7 @@ pw_validate_be_dn(Slapi_PBlock *pb, Slapi_Entry **referral)
}
if (*referral) {
- slapi_be_Unlock(be);
+ PR_ASSERT(be == NULL);
return SLAPI_BIND_REFERRAL;
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.