dirsrvtests/tickets/ticket48226_test.py | 239 ++++++++++++++++++++++++++++++++ ldap/servers/slapd/valueset.c | 5 2 files changed, 242 insertions(+), 2 deletions(-)
New commits: commit dfcfa5521e44604991c48808ff613394712b34ee Author: Noriko Hosoi nhosoi@redhat.com Date: Thu Jul 16 10:41:53 2015 -0700
Ticket #48226 - CI test: added test cases for ticket 48226
Description: In MMR, double free coould occur under some special condition
This test script was written by thierry bordaz tbordaz@redhat.com. A small modification to check the memory leak was added.
(cherry picked from commit f5d24450477f8341261c3e5cb5c54ec1ab83328f) (cherry picked from commit 8600a5eabc78848ad1bf0a9c2014823d0cd6cedc)
diff --git a/dirsrvtests/tickets/ticket48226_test.py b/dirsrvtests/tickets/ticket48226_test.py new file mode 100644 index 0000000..87814e7 --- /dev/null +++ b/dirsrvtests/tickets/ticket48226_test.py @@ -0,0 +1,239 @@ +# --- BEGIN COPYRIGHT BLOCK --- +# Copyright (C) 2015 Red Hat, Inc. +# All rights reserved. +# +# License: GPL (version 3 or any later version). +# See LICENSE for details. +# --- END COPYRIGHT BLOCK --- +# +import os +import sys +import time +import ldap +import logging +import pytest +from lib389 import DirSrv, Entry, tools, tasks +from lib389.tools import DirSrvTools +from lib389._constants import * +from lib389.properties import * +from lib389.tasks import * +from lib389.utils import * + +logging.getLogger(__name__).setLevel(logging.DEBUG) +log = logging.getLogger(__name__) + +installation1_prefix = None + + +class TopologyReplication(object): + def __init__(self, master1, master2): + master1.open() + self.master1 = master1 + master2.open() + self.master2 = master2 + + +@pytest.fixture(scope="module") +def topology(request): + global installation1_prefix + os.environ['USE_VALGRIND'] = '1' + if installation1_prefix: + args_instance[SER_DEPLOYED_DIR] = installation1_prefix + + # Creating master 1... + master1 = DirSrv(verbose=False) + if installation1_prefix: + args_instance[SER_DEPLOYED_DIR] = installation1_prefix + args_instance[SER_HOST] = HOST_MASTER_1 + args_instance[SER_PORT] = PORT_MASTER_1 + args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_1 + args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX + args_master = args_instance.copy() + master1.allocate(args_master) + instance_master1 = master1.exists() + if instance_master1: + master1.delete() + master1.create() + master1.open() + master1.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_1) + + # Creating master 2... + master2 = DirSrv(verbose=False) + if installation1_prefix: + args_instance[SER_DEPLOYED_DIR] = installation1_prefix + args_instance[SER_HOST] = HOST_MASTER_2 + args_instance[SER_PORT] = PORT_MASTER_2 + args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_2 + args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX + args_master = args_instance.copy() + master2.allocate(args_master) + instance_master2 = master2.exists() + if instance_master2: + master2.delete() + master2.create() + master2.open() + master2.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_2) + + # + # Create all the agreements + # + # Creating agreement from master 1 to master 2 + properties = {RA_NAME: r'meTo_$host:$port', + RA_BINDDN: defaultProperties[REPLICATION_BIND_DN], + RA_BINDPW: defaultProperties[REPLICATION_BIND_PW], + RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD], + RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]} + m1_m2_agmt = master1.agreement.create(suffix=SUFFIX, host=master2.host, port=master2.port, properties=properties) + if not m1_m2_agmt: + log.fatal("Fail to create a master -> master replica agreement") + sys.exit(1) + log.debug("%s created" % m1_m2_agmt) + + # Creating agreement from master 2 to master 1 + properties = {RA_NAME: r'meTo_$host:$port', + RA_BINDDN: defaultProperties[REPLICATION_BIND_DN], + RA_BINDPW: defaultProperties[REPLICATION_BIND_PW], + RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD], + RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]} + m2_m1_agmt = master2.agreement.create(suffix=SUFFIX, host=master1.host, port=master1.port, properties=properties) + if not m2_m1_agmt: + log.fatal("Fail to create a master -> master replica agreement") + sys.exit(1) + log.debug("%s created" % m2_m1_agmt) + + # Allow the replicas to get situated with the new agreements... + time.sleep(5) + + # + # Initialize all the agreements + # + master1.agreement.init(SUFFIX, HOST_MASTER_2, PORT_MASTER_2) + master1.waitForReplInit(m1_m2_agmt) + + # Check replication is working... + if master1.testReplication(DEFAULT_SUFFIX, master2): + log.info('Replication is working.') + else: + log.fatal('Replication is not working.') + assert False + + # Clear out the tmp dir + master1.clearTmpDir(__file__) + + return TopologyReplication(master1, master2) + +def test_ticket11111_set_purgedelay(topology): + args = {REPLICA_PURGE_DELAY: '5', + REPLICA_PURGE_INTERVAL: '5'} + try: + topology.master1.replica.setProperties(DEFAULT_SUFFIX, None, None, args) + except: + log.fatal('Failed to configure replica') + assert False + try: + topology.master2.replica.setProperties(DEFAULT_SUFFIX, None, None, args) + except: + log.fatal('Failed to configure replica') + assert False + topology.master1.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-auditlog-logging-enabled', 'on')]) + topology.master2.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-auditlog-logging-enabled', 'on')]) + topology.master1.restart(10) + topology.master2.restart(10) + + +def test_ticket11111_1(topology): + name = 'test_entry' + dn = "cn=%s,%s" % (name, SUFFIX) + + topology.master1.add_s(Entry((dn , { + 'objectclass': "top person".split(), + 'sn': name, + 'cn': name}))) + + # First do an update that is replicated + mods = [(ldap.MOD_ADD, 'description', '5')] + topology.master1.modify_s(dn, mods) + + nbtry = 0 + while (nbtry <= 10): + try: + ent = topology.master2.getEntry(dn, ldap.SCOPE_BASE, "(objectclass=*)", ['description']) + if ent.hasAttr('description') and ent.getValue('description') == '5': + break + except ldap.NO_SUCH_OBJECT: + pass + nbtry = nbtry + 1 + time.sleep(1) + assert nbtry <= 10 + + # Stop M2 so that it will not receive the next update + topology.master2.stop(10) + + # ADD a new value that is not replicated + mods = [(ldap.MOD_DELETE, 'description', '5')] + topology.master1.modify_s(dn, mods) + + # Stop M1 so that it will keep del '5' that is unknown from master2 + topology.master1.stop(10) + + # Get the sbin directory so we know where to replace 'ns-slapd' + sbin_dir = get_sbin_dir(prefix=topology.master2.prefix) + + # Enable valgrind + valgrind_enable(sbin_dir) + + # start M2 to do the next updates + topology.master2.start(10) + + # ADD 'description' by '5' + mods = [(ldap.MOD_DELETE, 'description', '5')] + topology.master2.modify_s(dn, mods) + + # DEL 'description' by '5' + mods = [(ldap.MOD_ADD, 'description', '5')] + topology.master2.modify_s(dn, mods) + + # sleep of purgedelay so that the next update will purge the CSN_7 + time.sleep(6) + + # ADD 'description' by '8' that purge the state info + mods = [(ldap.MOD_ADD, 'description', '6')] + topology.master2.modify_s(dn, mods) + + if valgrind_check_leak(topology.master2, 'csnset_dup'): + log.error('test_csnset_dup: Memory leak is present!') + else: + log.info('test_csnset_dup: No leak is present!') + + if valgrind_check_leak(topology.master2, 'Invalid'): + log.info('Valgrind reported invalid!') + else: + log.info('Valgrind is happy!') + + #log.info("You can attach yourself") + #time.sleep(60) + + # Enable valgrind + valgrind_disable(sbin_dir) + + topology.master1.start(10) + + +def test_ticket11111_final(topology): + topology.master1.delete() + topology.master2.delete() + log.info('Testcase PASSED') + + +def run_isolated(): + global installation1_prefix + installation1_prefix = None + + topo = topology(True) + test_ticket11111_set_purgedelay(topo) + test_ticket11111_1(topo) + + +if __name__ == '__main__': + run_isolated() +
commit de1b027c39e6b80bdfdf02f1a12854587730aff8 Author: Noriko Hosoi nhosoi@redhat.com Date: Thu Jul 16 10:34:47 2015 -0700
Ticket #48226 - In MMR, double free coould occur under some special condition
Bug description: In a replicated topology, a authenticated user that have write access on an entry can send a series of operations that crash the server. The crash is due to an access to a already freed buffer. Fix description: To avoid the double free, duplicate a CSNSet and assign it to the Slapi_Value.
https://fedorahosted.org/389/ticket/48226
Reviewed by rmeggins@redhat.com (Thank you, Rich!!)
(cherry picked from commit a0f8e0f981a046882db299a7a6d6d1c01bc19571) (cherry picked from commit bdbc81e62eb8d7b8dfb298c7ba983cf86353fe66)
diff --git a/ldap/servers/slapd/valueset.c b/ldap/servers/slapd/valueset.c index 9d77b0c..fb7a99b 100644 --- a/ldap/servers/slapd/valueset.c +++ b/ldap/servers/slapd/valueset.c @@ -1444,8 +1444,9 @@ valueset_update_csn_for_valuearray_ext(Slapi_ValueSet *vs, const Slapi_Attr *a, if(v) { value_update_csn(v,t,csn); - if (csnref_updated) - valuestoupdate[i]->v_csnset = (CSNSet *)value_get_csnset(v); + if (csnref_updated) { + valuestoupdate[i]->v_csnset = csnset_dup(value_get_csnset(v)); + } valuearrayfast_add_value_passin(&vaf_valuesupdated,valuestoupdate[i]); valuestoupdate[i]= NULL; del_count++;
389-commits@lists.fedoraproject.org