Bug 1832678

Summary: mod_ldap: High CPU usage at apr_ldap_rebind_remove()
Product: Red Hat Enterprise Linux 7 Reporter: asah
Component: httpdAssignee: Luboš Uhliarik <luhliari>
Status: CLOSED WONTFIX QA Contact: RHEL Stacks Subsystem QE <rhel-stacks-subsystem-qe>
Severity: medium Docs Contact:
Priority: unspecified    
Version: 7.7CC: aollebla, jorton, luhliari
Target Milestone: rc   
Target Release: ---   
Hardware: x86_64   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of:
: 1847585 (view as bug list) Environment:
Last Closed: 2020-09-03 10:22:53 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 1847585, 2098056    

Description asah 2020-05-07 04:12:52 UTC
Description of problem:

In uldap_connection_unbind, apr_ldap_rebind_remove() is always passed
NULL since ldc->ldap is either NULL on entry or is set to NULL.

This thread is expensive as apr_ldap_rebind_remove() acquires a mutex and iterates a linked list
trying to find a rebind reference matching NULL 

~~~
173:    while ((tmp_xref) && (tmp_xref->index != ld)) {
174:        prev = tmp_xref;
175:        tmp_xref = tmp_xref->next;
176:    }

173         while ((tmp_xref) && (tmp_xref->index != ld)) {
**(gdb) p ld
$1 = (LDAP *) 0x0**
(gdb) p tmp_xref
$2 = (apr_ldap_rebind_entry_t *) 0x7f256418eea0
(gdb) p tmp_xref->index
$3 = (LDAP *) 0x7f254c00b2c0
(gdb) p tmp_xref->next
$4 = (struct apr_ldap_rebind_entry *) 0x7f256418eea0
(gdb) n
175             tmp_xref = tmp_xref->next;
(gdb) n
173         while ((tmp_xref) && (tmp_xref->index != ld)) {
(gdb) p tmp_xref
$5 = (apr_ldap_rebind_entry_t *) 0x7f256418eea0
(gdb)
~~~


http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ldap/util_ldap.c
~~~

static apr_status_t uldap_connection_unbind(void *param)
{
    util_ldap_connection_t *ldc = param;

    if (ldc) {
        if (ldc->ldap) {          # if not NULL            
            if (ldc->r) { 
                ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, ldc->r, "LDC %pp unbind", ldc); 
            }
            ldap_unbind_s(ldc->ldap);
            **ldc->ldap = NULL**;     # Note the assignment
        }
        ldc->bound = 0;

        /* forget the rebind info for this conn */
        if (ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) {   # if we get into this block,
            **apr_ldap_rebind_remove(ldc->ldap)**;  # <--- Passes NULL always
            apr_pool_clear(ldc->rebind_pool);
        }
    }

    return APR_SUCCESS;
}

~~~


LDAPReferrals Off is a workaround to avoid this loop.