|
|
081b2d |
From dcf75750dff23e848cde2ae63a0778b123de6dd7 Mon Sep 17 00:00:00 2001
|
|
|
081b2d |
From: William Brown <firstyear@redhat.com>
|
|
|
081b2d |
Date: Thu, 2 Nov 2017 13:32:41 +1000
|
|
|
081b2d |
Subject: [PATCH] Ticket 49436 - double free in COS in some conditions
|
|
|
081b2d |
|
|
|
081b2d |
Bug Description: virtualattrs and COS have some serious memory
|
|
|
081b2d |
ownership issues. What was happening is that COS with multiple
|
|
|
081b2d |
attributes using the same sp_handle would cause a structure
|
|
|
081b2d |
to be registered twice. During shutdown we would then trigger
|
|
|
081b2d |
a double free in the process.
|
|
|
081b2d |
|
|
|
081b2d |
Fix Description: Change the behaviour of sp_handles to use a
|
|
|
081b2d |
handle *per* attribute we register to guarantee the assocation
|
|
|
081b2d |
between them.
|
|
|
081b2d |
|
|
|
081b2d |
https://pagure.io/389-ds-base/issue/49436
|
|
|
081b2d |
|
|
|
081b2d |
Author: wibrown
|
|
|
081b2d |
|
|
|
081b2d |
Review by: mreynolds, vashirov (Thanks!)
|
|
|
081b2d |
|
|
|
081b2d |
(cherry pick from commit ee4428a3f5d2d8e37a7107c7dce9d622fc17d41c)
|
|
|
081b2d |
---
|
|
|
081b2d |
dirsrvtests/tests/suites/cos/indirect_cos_test.py | 43 +++++++----------------
|
|
|
081b2d |
ldap/servers/plugins/cos/cos_cache.c | 32 +++++++++--------
|
|
|
081b2d |
ldap/servers/plugins/roles/roles_cache.c | 8 ++---
|
|
|
081b2d |
ldap/servers/slapd/vattr.c | 28 +++++++++------
|
|
|
081b2d |
4 files changed, 51 insertions(+), 60 deletions(-)
|
|
|
081b2d |
|
|
|
081b2d |
diff --git a/dirsrvtests/tests/suites/cos/indirect_cos_test.py b/dirsrvtests/tests/suites/cos/indirect_cos_test.py
|
|
|
081b2d |
index 1aac6b8ed..452edcdf8 100644
|
|
|
081b2d |
--- a/dirsrvtests/tests/suites/cos/indirect_cos_test.py
|
|
|
081b2d |
+++ b/dirsrvtests/tests/suites/cos/indirect_cos_test.py
|
|
|
081b2d |
@@ -7,6 +7,7 @@ import subprocess
|
|
|
081b2d |
|
|
|
081b2d |
from lib389 import Entry
|
|
|
081b2d |
from lib389.idm.user import UserAccounts
|
|
|
081b2d |
+from lib389.idm.domain import Domain
|
|
|
081b2d |
from lib389.topologies import topology_st as topo
|
|
|
081b2d |
from lib389._constants import (DEFAULT_SUFFIX, DN_DM, PASSWORD, HOST_STANDALONE,
|
|
|
081b2d |
SERVERID_STANDALONE, PORT_STANDALONE)
|
|
|
081b2d |
@@ -48,14 +49,8 @@ def check_user(inst):
|
|
|
081b2d |
def setup_subtree_policy(topo):
|
|
|
081b2d |
"""Set up subtree password policy
|
|
|
081b2d |
"""
|
|
|
081b2d |
- try:
|
|
|
081b2d |
- topo.standalone.modify_s("cn=config", [(ldap.MOD_REPLACE,
|
|
|
081b2d |
- 'nsslapd-pwpolicy-local',
|
|
|
081b2d |
- 'on')])
|
|
|
081b2d |
- except ldap.LDAPError as e:
|
|
|
081b2d |
- log.error('Failed to set fine-grained policy: error {}'.format(
|
|
|
081b2d |
- e.message['desc']))
|
|
|
081b2d |
- raise e
|
|
|
081b2d |
+
|
|
|
081b2d |
+ topo.standalone.config.set('nsslapd-pwpolicy-local', 'on')
|
|
|
081b2d |
|
|
|
081b2d |
log.info('Create password policy for subtree {}'.format(OU_PEOPLE))
|
|
|
081b2d |
try:
|
|
|
081b2d |
@@ -68,15 +63,9 @@ def setup_subtree_policy(topo):
|
|
|
081b2d |
OU_PEOPLE, e.message['desc']))
|
|
|
081b2d |
raise e
|
|
|
081b2d |
|
|
|
081b2d |
- log.info('Add pwdpolicysubentry attribute to {}'.format(OU_PEOPLE))
|
|
|
081b2d |
- try:
|
|
|
081b2d |
- topo.standalone.modify_s(DEFAULT_SUFFIX, [(ldap.MOD_REPLACE,
|
|
|
081b2d |
- 'pwdpolicysubentry',
|
|
|
081b2d |
- PW_POLICY_CONT_PEOPLE2)])
|
|
|
081b2d |
- except ldap.LDAPError as e:
|
|
|
081b2d |
- log.error('Failed to pwdpolicysubentry pw policy '
|
|
|
081b2d |
- 'policy for {}: error {}'.format(OU_PEOPLE, e.message['desc']))
|
|
|
081b2d |
- raise e
|
|
|
081b2d |
+ domain = Domain(topo.standalone, DEFAULT_SUFFIX)
|
|
|
081b2d |
+ domain.replace('pwdpolicysubentry', PW_POLICY_CONT_PEOPLE2)
|
|
|
081b2d |
+
|
|
|
081b2d |
time.sleep(1)
|
|
|
081b2d |
|
|
|
081b2d |
|
|
|
081b2d |
@@ -116,12 +105,9 @@ def setup(topo, request):
|
|
|
081b2d |
"""
|
|
|
081b2d |
log.info('Add custom schema...')
|
|
|
081b2d |
try:
|
|
|
081b2d |
- ATTR_1 = ("( 1.3.6.1.4.1.409.389.2.189 NAME 'x-department' " +
|
|
|
081b2d |
- "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )")
|
|
|
081b2d |
- ATTR_2 = ("( 1.3.6.1.4.1.409.389.2.187 NAME 'x-en-ou' " +
|
|
|
081b2d |
- "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )")
|
|
|
081b2d |
- OC = ("( xPerson-oid NAME 'xPerson' DESC '' SUP person STRUCTURAL MAY " +
|
|
|
081b2d |
- "( x-department $ x-en-ou ) X-ORIGIN 'user defined' )")
|
|
|
081b2d |
+ ATTR_1 = (b"( 1.3.6.1.4.1.409.389.2.189 NAME 'x-department' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )")
|
|
|
081b2d |
+ ATTR_2 = (b"( 1.3.6.1.4.1.409.389.2.187 NAME 'x-en-ou' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )")
|
|
|
081b2d |
+ OC = (b"( xPerson-oid NAME 'xPerson' DESC '' SUP person STRUCTURAL MAY ( x-department $ x-en-ou ) X-ORIGIN 'user defined' )")
|
|
|
081b2d |
topo.standalone.modify_s("cn=schema", [(ldap.MOD_ADD, 'attributeTypes', ATTR_1),
|
|
|
081b2d |
(ldap.MOD_ADD, 'attributeTypes', ATTR_2),
|
|
|
081b2d |
(ldap.MOD_ADD, 'objectClasses', OC)])
|
|
|
081b2d |
@@ -142,14 +128,9 @@ def setup(topo, request):
|
|
|
081b2d |
'homeDirectory': '/home/test_user',
|
|
|
081b2d |
'seeAlso': 'cn=cosTemplate,dc=example,dc=com'
|
|
|
081b2d |
}
|
|
|
081b2d |
- users.create(properties=user_properties)
|
|
|
081b2d |
- try:
|
|
|
081b2d |
- topo.standalone.modify_s(TEST_USER_DN, [(ldap.MOD_ADD,
|
|
|
081b2d |
- 'objectclass',
|
|
|
081b2d |
- 'xPerson')])
|
|
|
081b2d |
- except ldap.LDAPError as e:
|
|
|
081b2d |
- log.fatal('Failed to add objectclass to user')
|
|
|
081b2d |
- raise e
|
|
|
081b2d |
+ user = users.create(properties=user_properties)
|
|
|
081b2d |
+
|
|
|
081b2d |
+ user.add('objectClass', 'xPerson')
|
|
|
081b2d |
|
|
|
081b2d |
# Setup COS
|
|
|
081b2d |
log.info("Setup indirect COS...")
|
|
|
081b2d |
diff --git a/ldap/servers/plugins/cos/cos_cache.c b/ldap/servers/plugins/cos/cos_cache.c
|
|
|
081b2d |
index 9ae15db15..662dace35 100644
|
|
|
081b2d |
--- a/ldap/servers/plugins/cos/cos_cache.c
|
|
|
081b2d |
+++ b/ldap/servers/plugins/cos/cos_cache.c
|
|
|
081b2d |
@@ -109,9 +109,6 @@ void *cos_get_plugin_identity(void);
|
|
|
081b2d |
#define COSTYPE_INDIRECT 3
|
|
|
081b2d |
#define COS_DEF_ERROR_NO_TEMPLATES -2
|
|
|
081b2d |
|
|
|
081b2d |
-/* the global plugin handle */
|
|
|
081b2d |
-static volatile vattr_sp_handle *vattr_handle = NULL;
|
|
|
081b2d |
-
|
|
|
081b2d |
/* both variables are protected by change_lock */
|
|
|
081b2d |
static int cos_cache_notify_flag = 0;
|
|
|
081b2d |
static PRBool cos_cache_at_work = PR_FALSE;
|
|
|
081b2d |
@@ -323,16 +320,6 @@ cos_cache_init(void)
|
|
|
081b2d |
views_api = 0;
|
|
|
081b2d |
}
|
|
|
081b2d |
|
|
|
081b2d |
- if (slapi_vattrspi_register((vattr_sp_handle **)&vattr_handle,
|
|
|
081b2d |
- cos_cache_vattr_get,
|
|
|
081b2d |
- cos_cache_vattr_compare,
|
|
|
081b2d |
- cos_cache_vattr_types) != 0) {
|
|
|
081b2d |
- slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM,
|
|
|
081b2d |
- "cos_cache_init - Cannot register as service provider\n");
|
|
|
081b2d |
- ret = -1;
|
|
|
081b2d |
- goto out;
|
|
|
081b2d |
- }
|
|
|
081b2d |
-
|
|
|
081b2d |
if (PR_CreateThread(PR_USER_THREAD,
|
|
|
081b2d |
cos_cache_wait_on_change,
|
|
|
081b2d |
NULL,
|
|
|
081b2d |
@@ -860,8 +847,23 @@ cos_dn_defs_cb(Slapi_Entry *e, void *callback_data)
|
|
|
081b2d |
dnVals[valIndex]->bv_val);
|
|
|
081b2d |
}
|
|
|
081b2d |
|
|
|
081b2d |
- slapi_vattrspi_regattr((vattr_sp_handle *)vattr_handle,
|
|
|
081b2d |
- dnVals[valIndex]->bv_val, NULL, NULL);
|
|
|
081b2d |
+ /*
|
|
|
081b2d |
+ * Each SP_handle is associated to one and only one vattr.
|
|
|
081b2d |
+ * We could consider making this a single function rather
|
|
|
081b2d |
+ * than the double-call.
|
|
|
081b2d |
+ */
|
|
|
081b2d |
+
|
|
|
081b2d |
+ vattr_sp_handle *vattr_handle = NULL;
|
|
|
081b2d |
+
|
|
|
081b2d |
+ if (slapi_vattrspi_register((vattr_sp_handle **)&vattr_handle,
|
|
|
081b2d |
+ cos_cache_vattr_get,
|
|
|
081b2d |
+ cos_cache_vattr_compare,
|
|
|
081b2d |
+ cos_cache_vattr_types) != 0) {
|
|
|
081b2d |
+ slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_init - Cannot register as service provider for %s\n", dnVals[valIndex]->bv_val);
|
|
|
081b2d |
+ } else {
|
|
|
081b2d |
+ slapi_vattrspi_regattr((vattr_sp_handle *)vattr_handle, dnVals[valIndex]->bv_val, NULL, NULL);
|
|
|
081b2d |
+ }
|
|
|
081b2d |
+
|
|
|
081b2d |
} /* if(attrType is cosAttribute) */
|
|
|
081b2d |
|
|
|
081b2d |
/*
|
|
|
081b2d |
diff --git a/ldap/servers/plugins/roles/roles_cache.c b/ldap/servers/plugins/roles/roles_cache.c
|
|
|
081b2d |
index 59f5a6081..1e5865af8 100644
|
|
|
081b2d |
--- a/ldap/servers/plugins/roles/roles_cache.c
|
|
|
081b2d |
+++ b/ldap/servers/plugins/roles/roles_cache.c
|
|
|
081b2d |
@@ -47,9 +47,6 @@ static char *allUserAttributes[] = {
|
|
|
081b2d |
/* views scoping */
|
|
|
081b2d |
static void **views_api;
|
|
|
081b2d |
|
|
|
081b2d |
-/* Service provider handler */
|
|
|
081b2d |
-static vattr_sp_handle *vattr_handle = NULL;
|
|
|
081b2d |
-
|
|
|
081b2d |
/* List of nested roles */
|
|
|
081b2d |
typedef struct _role_object_nested
|
|
|
081b2d |
{
|
|
|
081b2d |
@@ -224,6 +221,10 @@ roles_cache_init()
|
|
|
081b2d |
so that we update the corresponding cache */
|
|
|
081b2d |
slapi_register_backend_state_change(NULL, roles_cache_trigger_update_suffix);
|
|
|
081b2d |
|
|
|
081b2d |
+ /* Service provider handler - only used once! and freed by vattr! */
|
|
|
081b2d |
+ vattr_sp_handle *vattr_handle = NULL;
|
|
|
081b2d |
+
|
|
|
081b2d |
+
|
|
|
081b2d |
if (slapi_vattrspi_register((vattr_sp_handle **)&vattr_handle,
|
|
|
081b2d |
roles_sp_get_value,
|
|
|
081b2d |
roles_sp_compare_value,
|
|
|
081b2d |
@@ -622,7 +623,6 @@ roles_cache_stop()
|
|
|
081b2d |
current_role = next_role;
|
|
|
081b2d |
}
|
|
|
081b2d |
slapi_rwlock_unlock(global_lock);
|
|
|
081b2d |
- slapi_ch_free((void **)&vattr_handle);
|
|
|
081b2d |
roles_list = NULL;
|
|
|
081b2d |
|
|
|
081b2d |
slapi_log_err(SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_stop\n");
|
|
|
081b2d |
diff --git a/ldap/servers/slapd/vattr.c b/ldap/servers/slapd/vattr.c
|
|
|
081b2d |
index 82deb41fe..432946c79 100644
|
|
|
081b2d |
--- a/ldap/servers/slapd/vattr.c
|
|
|
081b2d |
+++ b/ldap/servers/slapd/vattr.c
|
|
|
081b2d |
@@ -1864,7 +1864,12 @@ vattr_map_create(void)
|
|
|
081b2d |
void
|
|
|
081b2d |
vattr_map_entry_free(vattr_map_entry *vae)
|
|
|
081b2d |
{
|
|
|
081b2d |
- slapi_ch_free((void **)&(vae->sp_list));
|
|
|
081b2d |
+ vattr_sp_handle *list_entry = vae->sp_list;
|
|
|
081b2d |
+ while (list_entry != NULL) {
|
|
|
081b2d |
+ vattr_sp_handle *next_entry = list_entry->next;
|
|
|
081b2d |
+ slapi_ch_free((void **)&list_entry);
|
|
|
081b2d |
+ list_entry = next_entry;
|
|
|
081b2d |
+ }
|
|
|
081b2d |
slapi_ch_free_string(&(vae->type_name));
|
|
|
081b2d |
slapi_ch_free((void **)&vae;;
|
|
|
081b2d |
}
|
|
|
081b2d |
@@ -2143,16 +2148,9 @@ slapi_vattr_schema_check_type(Slapi_Entry *e, char *type)
|
|
|
081b2d |
vattr_map_entry *
|
|
|
081b2d |
vattr_map_entry_new(char *type_name, vattr_sp_handle *sph, void *hint)
|
|
|
081b2d |
{
|
|
|
081b2d |
- vattr_map_entry *result = NULL;
|
|
|
081b2d |
- vattr_sp_handle *sp_copy = NULL;
|
|
|
081b2d |
-
|
|
|
081b2d |
- sp_copy = (vattr_sp_handle *)slapi_ch_calloc(1, sizeof(vattr_sp_handle));
|
|
|
081b2d |
- sp_copy->sp = sph->sp;
|
|
|
081b2d |
- sp_copy->hint = hint;
|
|
|
081b2d |
-
|
|
|
081b2d |
- result = (vattr_map_entry *)slapi_ch_calloc(1, sizeof(vattr_map_entry));
|
|
|
081b2d |
+ vattr_map_entry *result = (vattr_map_entry *)slapi_ch_calloc(1, sizeof(vattr_map_entry));
|
|
|
081b2d |
result->type_name = slapi_ch_strdup(type_name);
|
|
|
081b2d |
- result->sp_list = sp_copy;
|
|
|
081b2d |
+ result->sp_list = sph;
|
|
|
081b2d |
|
|
|
081b2d |
/* go get schema */
|
|
|
081b2d |
result->objectclasses = vattr_map_entry_build_schema(type_name);
|
|
|
081b2d |
@@ -2273,6 +2271,16 @@ we'd need to hold a lock on the read path, which we don't want to do.
|
|
|
081b2d |
So any SP which relinquishes its need to handle a type needs to continue
|
|
|
081b2d |
to handle the calls on it, but return nothing */
|
|
|
081b2d |
/* DBDB need to sort out memory ownership here, it's not quite right */
|
|
|
081b2d |
+/*
|
|
|
081b2d |
+ * This function was inconsistent. We would allocated and "kind of",
|
|
|
081b2d |
+ * copy the sp_handle here for the vattr_map_entry_new path. But we
|
|
|
081b2d |
+ * would "take ownership" for the existing entry and the list addition
|
|
|
081b2d |
+ * path. Instead now, EVERY sp_handle we take, we take ownership of
|
|
|
081b2d |
+ * and the CALLER must allocate a new one each time.
|
|
|
081b2d |
+ *
|
|
|
081b2d |
+ * Better idea, is that regattr should just take the fn pointers
|
|
|
081b2d |
+ * and callers never *see* the sp_handle structure at all.
|
|
|
081b2d |
+ */
|
|
|
081b2d |
|
|
|
081b2d |
int
|
|
|
081b2d |
vattr_map_sp_insert(char *type_to_add, vattr_sp_handle *sp, void *hint)
|
|
|
081b2d |
--
|
|
|
081b2d |
2.13.6
|
|
|
081b2d |
|