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: [email protected]
Reporter: [email protected]
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/etc/openssh-lpk.schema
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
--
You are receiving this mail because:
You are on the CC list for the issue.