https://bugs.openldap.org/show_bug.cgi?id=10373
Issue ID: 10373 Summary: pcache SEGV with pcacheTemplate ttr Product: OpenLDAP Version: unspecified Hardware: All OS: All Status: UNCONFIRMED Keywords: needs_review Severity: normal Priority: --- Component: overlays Assignee: bugs@openldap.org Reporter: bertrand@jacquin.bzh Target Milestone: ---
Hi,
I am currently setting up OpenLDAP with pcache to circumvent aggressive LDAP queries from an application and thus reduce load to the SQL database used in the backend through back-sql.so.
The setup is incomplete and likely not currently implemented properly, please don't pay too much attention in configuration details from below, however I'm noticing SEGV when pcacheTemplate are configured with ttr:
refresh_purge() attempts to dereference NULL pointer *a, leading to the SEGV:
``` $ gdb --args /usr/lib64/openldap/slapd -u ldap -h "ldapi:/// ldap:/// ldaps:///" -f /etc/openldap/slapd.conf -d stats -d pcache 688224ea.1e5f48d7 0x7fffedffb6c0 conn=1020 op=2 SEARCH RESULT tag=101 err=0 qtime=0.000166 etime=0.012879 nentries=0 text= 688224ea.1e633093 0x7fffedffb6c0 conn=1020 op=3 SRCH base="ou=<redacted>,dc=<redacted>,dc=<redacted>" scope=2 deref=0 filter="(&(objectClass=inetOrgPerson)(&(jpegPhoto=*)(|(mail=<redacted>))))" 688224ea.1e64fd20 0x7fffedffb6c0 conn=1020 op=3 SRCH attr=dn 688224ea.1e65fb45 0x7fffedffb6c0 query template of incoming query = (&(objectClass=)(&(jpegPhoto=*)(|(mail=)))) 688224ea.1e660563 0x7fffedffb6c0 Entering QC, querystr = (&(objectClass=inetOrgPerson)(&(jpegPhoto=*)(|(mail=<redacted>)))) 688224ea.1e660de7 0x7fffedffb6c0 Lock QC index = 0x555555828190 688224ea.1e6616cf 0x7fffedffb6c0 Not answerable: Unlock QC index=0x555555828190 688224ea.1e66209d 0x7fffedffb6c0 QUERY NOT ANSWERABLE 688224ea.1e6627c3 0x7fffedffb6c0 QUERY CACHEABLE 688224ea.1ed69d89 0x7fffedffb6c0 conn=1020 op=3 SEARCH RESULT tag=101 err=32 qtime=0.000009 etime=0.007587 nentries=0 text= 688224ea.1ef64669 0x7ffff4dfe6c0 conn=1020 op=4 UNBIND 688224ea.1efab72d 0x7fffedffb6c0 conn=1020 fd=30 closed
Thread 7 "slapd" received signal SIGSEGV, Segmentation fault. [Switching to Thread 0x7fffee7fc6c0 (LWP 136445)] refresh_purge (op=0x7fffee7fb610, rs=0x7fffee7fb290) at pcache.c:3392 3392 dnl->delete = ( a->a_numvals == 1 );
(gdb) bt #0 refresh_purge (op=0x7fffee7fb610, rs=0x7fffee7fb290) at pcache.c:3392 #1 refresh_purge (op=0x7fffee7fb610, rs=0x7fffee7fb290) at pcache.c:3367 #2 0x00005555555a6098 in slap_response_play (op=op@entry=0x7fffee7fb610, rs=rs@entry=0x7fffee7fb290) at result.c:573 #3 0x00005555555a7ddd in slap_send_search_entry (op=0x7fffee7fb610, rs=0x7fffee7fb290) at result.c:1078 #4 0x000055555562e007 in mdb_search (op=<optimized out>, rs=<optimized out>) at search.c:1110 #5 0x00007ffff73a6509 in refresh_query (op=0x7fffee7fb610, query=0x7fffd8131830, on=0x55555577c350) at pcache.c:3464 #6 consistency_check (ctx=<optimized out>, arg=0x5555559429a0) at pcache.c:3644 #7 0x00007ffff7f9e09d in ldap_int_thread_pool_wrapper (xpool=0x5555557aed80) at tpool.c:1059 #8 0x00007ffff7d3b86b in ?? () from /usr/lib64/libc.so.6 #9 0x00007ffff7dbc858 in ?? () from /usr/lib64/libc.so.6
(gdb) fr 0 #0 refresh_purge (op=0x7fffee7fb610, rs=0x7fffee7fb290) at pcache.c:3392 3392 dnl->delete = ( a->a_numvals == 1 );
(gdb) p *dnl $17 = { next = 0x0, dn = { bv_len = 40, bv_val = 0x7fffe403cb70 "uid=john,ou=<redacted>,dc=<redacted>,dc=<redacted>" }, delete = 80 'P' }
(gdb) p a $10 = (Attribute *) 0x0
(gdb) p ad_queryId $14 = (AttributeDescription *) 0x555555819580
(gdb) p *rs $11 = { sr_type = REP_SEARCH, sr_tag = 0, sr_msgid = 0, sr_err = 0, sr_matched = 0x0, sr_text = 0x0, sr_ref = 0x0, sr_ctrls = 0x0, sr_un = { sru_search = { r_entry = 0x7fffe403c5a0, r_attr_flags = 17, r_operational_attrs = 0x0, r_attrs = 0x7fffee7fb320, r_nentries = 0, r_v2ref = 0x0 }, sru_sasl = { r_sasldata = 0x7fffe403c5a0 }, sru_extended = { r_rspoid = 0x7fffe403c5a0 "!", r_rspdata = 0x11 } }, sr_flags = 0 } (gdb) p *rs->sr_entry $12 = { e_id = 33, e_name = { bv_len = 40, bv_val = 0x7fffe403cae0 "uid=john,ou=<redacted>,dc=<redacted>,dc=<redacted>" }, e_nname = { bv_len = 40, bv_val = 0x7fffe403cb18 "uid=john,ou=<redacted>,dc=<redacted>,dc=<redacted>" }, e_attrs = 0x7fffe403c5f0, e_ocflags = 256, e_bv = { bv_len = 0, bv_val = 0x0 }, e_private = 0x7fffe403c5a0 } (gdb) p *rs->sr_entry->e_attrs $13 = { a_desc = 0x555555781be0, a_vals = 0x7fffe403c7f8, a_nvals = 0x7fffe403c7f8, a_numvals = 1, a_flags = 12, a_next = 0x7fffe403c618 } ```
Looking further I can see that attr_find() can return NULL, however NULL are not verified in refresh_purge() after call to attr_find().
Note that I am using 2.6.8 that includes all the changes from ITS#9966 and I can't find any noticeable changes on that area between 2.6.8. and latest 2.6.9.
OpenLDAP is built on gentoo with hardened profile:
``` $ /usr/lib64/openldap/slapd -V @(#) $OpenLDAP: slapd 2.6.8 (Jul 23 2025 23:10:57) $
@localhost:/var/tmp/portage/net-nds/openldap-2.6.8-r1/work/openldap-OPENLDAP_REL_ENG_2_6_8-abi_x86_64.amd64/servers/slapd
$ /usr/lib64/libc.so.6 -V GNU C Library (Gentoo 2.41-r4 (patchset 6)) stable release version 2.41. Copyright (C) 2025 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Compiled by GNU CC version 14.3.0. libc ABIs: UNIQUE IFUNC ABSOLUTE Minimum supported kernel: 3.2.0 For bug reporting instructions, please see: https://bugs.gentoo.org/. ```
Configuration is as follow:
``` pidfile /run/openldap/slapd.pid argsfile /run/openldap/slapd.args
include /etc/openldap/schema/core.schema include /etc/openldap/schema/cosine.schema include /etc/openldap/schema/rfc2307bis.schema include /etc/openldap/schema/inetorgperson.schema include /etc/openldap/schema/rfc8284.schema
# From https://raw.githubusercontent.com/jirutka/ssh-ldap-pubkey/refs/heads/master/... include /etc/openldap/schema/openssh-lpk.schema
#loglevel stats stats2 loglevel stats
# Load dynamic modules moduleload argon2.so moduleload pw-pbkdf2.so moduleload pw-sha2.so moduleload back_sql.so moduleload pcache.so
# Transport Layer Security TLSCertificateFile /etc/ssl/ldap/openldap.crt TLSCertificateKeyFile /etc/ssl/ldap/openldap.key TLSProtocolMin 3.4 TLSCipherSuite ECDHE+CHACHA20:ECDHE+AESGCM TLSECName X448:P-384:X25519:P-256
# Default search base to use when client submits a non-base search request with an empty base DN defaultsearchbase dc=<redacted>,dc=<redacted>
# Hashes to be used in generation of user passwords password-hash {ARGON2ID}
# Specify a set of conditions to require require LDAPv3 strong disallow bind_anon
# Set of security strength factors to require security ssf=128 localSSF 256
# SASL security properties sasl-secprops noanonymous,noplain
# SASL mapping authz-regexp uid=([^@]+)@([^,]+),cn=login,cn=auth uid=$1,ou=$2,dc=<redacted>,dc=<redacted> authz-regexp uid=([^@]+)@([^,]+),cn=plain,cn=auth uid=$1,ou=$2,dc=<redacted>,dc=<redacted>
# Allow access to root over SASL access to * by dn.exact="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage by * break
# Allow service authentication from UNIX socket only access to dn.subtree="dc=local" attrs=userPassword by sockname="PATH=/var/run/ldapi" auth by anonymous auth by * none
# Allow access to top level objects access to dn.base="dc=local" by users read by * break
# Allow access to service CN access to dn.subtree="dc=local" by set.exact="this/cn & user/cn" read by * break
# Allow user authentication access to dn.subtree="dc=<redacted>,dc=<redacted>" attrs=userPassword by anonymous auth by * none
# Allow access to top level objects access to dn.base="dc=<redacted>,dc=<redacted>" by users read by * break
# Allow access to users OU access to dn.subtree="dc=<redacted>,dc=<redacted>" by set.exact="this/ou & user/ou" read by * break
# Allow services to access directory access to dn.subtree="dc=<redacted>,dc=<redacted>" by dn.exact="cn=<redacted>,dc=local" read by dn.exact="cn=<redacted>,dc=local" read by * break
# Deny everything else access to * by * none
# The config backend manages all of the configuration information for the slapd(8) daemon. database config
# Access control policy access to dn.subtree="cn=config" by dn.exact="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage by * none
# Database instance definition database mdb directory /var/lib/openldap-data/dc=local
# DN suffix of queries that will be passed to this backend database suffix dc=local
# Database instance definition database sql dbname openldap dbuser openldap dbpasswd <redacted>
# DN suffix of queries that will be passed to this backend database suffix dc=<redacted>,dc=<redacted> rootdn "uid=root,dc=<redacted>,dc=<redacted>"
# Put the database into "read-only" mode readonly yes
subtree_cond "ldap_entries.dn LIKE CONCAT('%',?)" children_cond "ldap_entries.dn LIKE CONCAT('%,',?)" dn_match_cond "ldap_entries.dn=?"
oc_query "SELECT id,name,keytbl,keycol,create_proc,delete_proc,expect_return FROM ldap_oc_mappings" at_query "SELECT name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return,sel_expr_u FROM ldap_attr_mappings WHERE oc_map_id=?" id_query "SELECT id,keyval,oc_map_id,dn FROM ldap_entries WHERE dn=?"
insentry_stmt "INSERT INTO ldap_entries (dn,oc_map_id,parent,keyval) VALUES (?,?,?,?)" delentry_stmt "DELETE FROM ldap_entries WHERE id=?" renentry_stmt "UPDATE ldap_entries SET dn=?,parent=?,keyval=? WHERE id=?" delobjclasses_stmt "DELETE FROM ldap_entry_objclasses WHERE entry_id=?"
# Do not use DN in reverse uppercased form has_ldapinfo_dn_ru no
# Caching of LDAP search requests in a local databas overlay pcache pcache mdb 65536 16 1024 60 directory /var/lib/openldap-data/pcache pcacheMaxQueries 1024
# Cache DN pcacheAttrset 0 1.1 pcacheTemplate (objectClass=) 0 3600 60 0 15 pcacheTemplate (objectClass=*) 0 3600 60 0 15 pcacheTemplate (&(objectClass=)(&(jpegPhoto=*)(|(mail=)))) 0 3600 60 0 15
pcacheAttrset 1 jid pcacheTemplate (jid=) 1 3600 60 0 15
pcacheAttrset 2 ou cn givenname sn mail telephonenumber jid description jpegphoto objectClass pcacheTemplate (&(objectClass=)(&(jpegPhoto=*)(|(mail=)))) 2 3600 60 0 15 pcacheTemplate (objectClass=*) 2 3600 60 0 15 pcacheTemplate (objectClass=) 2 3600 60 0 15
pcacheAttrset 3 ou cn givenname sn mail telephonenumber description jpegphoto objectClass pcacheTemplate (&(objectClass=)(&(jpegPhoto=*)(|(mail=)))) 3 3600 60 0 pcacheTemplate (objectClass=*) 3 3600 60 0 pcacheTemplate (objectClass=) 3 3600 60 0
pcacheAttrset 4 mail pcacheTemplate (objectClass=*) 4 3600 60 0
pcacheAttrset 5 * + pcacheTemplate (objectClass=*) 5 3600 60 0 15 pcacheTemplate (mail=) 5 3600 60 0 15 ```
Cheers, Bertrand
https://bugs.openldap.org/show_bug.cgi?id=10373
Bertrand bertrand@jacquin.bzh changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |bertrand@jacquin.bzh Version|unspecified |2.6.8 Hardware|All |x86_64 OS|All |Linux