From 823cb708e0507cf063d0750bd069c4df58a8af09 Mon Sep 17 00:00:00 2001 From: William Brown Date: Apr 27 2017 14:47:21 +0000 Subject: Ticket 49233 - Fix crash in persistent search Bug Description: During the fixes to the pblock, we accidentally introduced a free to an operation linked to a persistent search. Fix Description: NULL the operation in the PB before connection threadmain loops. https://pagure.io/389-ds-base/issue/49233 Author: wibrown Review by: tbordaz, mreynolds (Thanks!!) (cherry picked from commit 565314cde101ec1d1d71527ea1b35f12504e9c97) --- diff --git a/dirsrvtests/tests/suites/psearch/psearch_test.py b/dirsrvtests/tests/suites/psearch/psearch_test.py new file mode 100644 index 0000000..4f53bb9 --- /dev/null +++ b/dirsrvtests/tests/suites/psearch/psearch_test.py @@ -0,0 +1,53 @@ +# --- BEGIN COPYRIGHT BLOCK --- +# Copyright (C) 2016 Red Hat, Inc. +# All rights reserved. +# +# License: GPL (version 3 or any later version). +# See LICENSE for details. +# --- END COPYRIGHT BLOCK --- +# +import pytest +from lib389._constants import DEFAULT_SUFFIX +from lib389.topologies import topology_st +from lib389.idm.group import Groups +import ldap +from ldap.controls.psearch import PersistentSearchControl,EntryChangeNotificationControl + +def _run_psearch(inst, msg_id): + results = [] + while True: + try: + _, data, _, _, _, _ = inst.result4(msgid=msg_id, all=0, timeout=1.0, add_ctrls=1, add_intermediates=1, + resp_ctrl_classes={EntryChangeNotificationControl.controlType:EntryChangeNotificationControl}) + # See if there are any entry changes + for dn, entry, srv_ctrls in data: + ecn_ctrls = filter(lambda c: c.controlType == EntryChangeNotificationControl.controlType, srv_ctrls) + if ecn_ctrls: + inst.log.info('%s has changed!' % dn) + results.append(dn) + except ldap.TIMEOUT: + # There are no more results, so we timeout. + inst.log.info('No more results') + return results + +def test_psearch(topology_st): + # Create the search control + psc = PersistentSearchControl() + # do a search extended with the control + msg_id = topology_st.standalone.search_ext(base=DEFAULT_SUFFIX, scope=ldap.SCOPE_SUBTREE, attrlist=['*'], serverctrls=[psc]) + # Get the result for the message id with result4 + _run_psearch(topology_st.standalone, msg_id) + # Change an entry / add one + groups = Groups(topology_st.standalone, DEFAULT_SUFFIX) + group = groups.create(properties={'cn': 'group1', 'description': 'testgroup'}) + # Now run the result again and see what's there. + results = _run_psearch(topology_st.standalone, msg_id) + # assert our group is in the changeset. + assert(group.dn == results[0]) + + +if __name__ == '__main__': + # Run isolated + # -s for DEBUG mode + CURRENT_FILE = os.path.realpath(__file__) + pytest.main("-s %s" % CURRENT_FILE) diff --git a/ldap/servers/slapd/connection.c b/ldap/servers/slapd/connection.c index 7aa2716..f6242c3 100644 --- a/ldap/servers/slapd/connection.c +++ b/ldap/servers/slapd/connection.c @@ -1524,6 +1524,7 @@ connection_threadmain() if( op_shutdown ) { slapi_log_err(SLAPI_LOG_TRACE, "connection_threadmain", "op_thread received shutdown signal\n"); + slapi_pblock_destroy(pb); g_decr_active_threadcnt(); return; } @@ -1548,6 +1549,7 @@ connection_threadmain() case CONN_SHUTDOWN: slapi_log_err(SLAPI_LOG_TRACE, "connection_threadmain", "op_thread received shutdown signal\n"); + slapi_pblock_destroy(pb); g_decr_active_threadcnt(); return; case CONN_FOUND_WORK_TO_DO: @@ -1778,7 +1780,7 @@ done: connection_release_nolock(conn); PR_ExitMonitor(conn->c_mutex); signal_listner(); - slapi_pblock_destroy(pb); + slapi_pblock_destroy(pb); return; } /* @@ -1798,9 +1800,10 @@ done: connection_release_nolock (conn); /* psearch acquires ref to conn - release this one now */ PR_ExitMonitor(conn->c_mutex); /* ps_add makes a shallow copy of the pb - so we - * can't free it or init it here - just memset it to 0 + * can't free it or init it here - just set operation to NULL. * ps_send_results will call connection_remove_operation_ext to free it */ + slapi_pblock_set(pb, SLAPI_OPERATION, NULL); slapi_pblock_init(pb); } else { /* delete from connection operation queue & decr refcnt */