https://bugs.openldap.org/show_bug.cgi?id=10581
Issue ID: 10581
Summary: Mismatch of crypt() prototype on PPC Mac OS X 10.5.8,
Leopard
Product: OpenLDAP
Version: 2.6.14
Hardware: Other
OS: Mac OS
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: build
Assignee: bugs(a)openldap.org
Reporter: Peter_Dyballa(a)Web.DE
Target Milestone: ---
This happens with OpenLDAP versions 2.6.13 and 2.61.4:
/opt/local/bin/gcc-mp-15 -pipe -Os -arch ppc -I../../include
-I../../include -isystem/opt/local/include/LegacySupport -I/opt/local/include
-I/opt/local/include/db48 -I/opt/local/include/openssl -DBIND_8_COMPAT
-DMDB_FDATASYNC=fsync -DMDB_DSYNC=O_SYNC -c -o passwd.o passwd.c
In file included from passwd.c:38:
../../include/ac/crypt.h:26:23: error: conflicting types for 'crypt'; have
'char *(void)'
26 | extern char *(crypt)();
| ^~~~~
In file included from /opt/local/include/LegacySupport/unistd.h:87,
from ../../include/ac/unistd.h:25,
from passwd.c:34:
/usr/include/unistd.h:424:10: note: previous declaration of 'crypt' with type
'char *(const char *, const char *)'
424 | char *crypt(const char *, const char *);
| ^~~~~
passwd.c: In function 'lutil_crypt':
passwd.c:627:20: error: too many arguments to function 'crypt'; expected 0,
have 2
627 | char *cr = crypt( key, salt );
| ^~~~~ ~~~
../../include/ac/crypt.h:26:23: note: declared here
26 | extern char *(crypt)();
| ^~~~~
make[2]: *** [passwd.o] Error 1
make[2]: Leaving directory
`/opt/local/var/macports/build/openldap-afe672a1/work/openldap-2.6.14/libraries/liblutil'
make[1]: *** [all-common] Error 1
make[1]: Leaving directory
`/opt/local/var/macports/build/openldap-afe672a1/work/openldap-2.6.14/libraries'
make: *** [all-common] Error 1
make: Leaving directory
`/opt/local/var/macports/build/openldap-afe672a1/work/openldap-2.6.14'
Command failed: cd
"/opt/local/var/macports/build/openldap-afe672a1/work/openldap-2.6.14" &&
/usr/bin/make -w all
Exit code: 2
On Leopard /usr/include/unistd.h has:
char *crypt(const char *, const char *);
So I ended applying this simple patch:
--- include/ac/crypt.h~ 2026-08-06 18:45:16.000000000 +0200
+++ include/ac/crypt.h 2026-08-30 11:21:21.000000000 +0200
@@ -22,8 +22,6 @@
/* crypt() may be defined in a separate include file */
#ifdef HAVE_CRYPT_H
# include <crypt.h>
-#else
- extern char *(crypt)();
#endif
#endif /* _AC_CRYPT_H */
This happens when using the MacPorts package manager. The issue can be viewed
(and also commented) here: https://trac.macports.org/ticket/73673.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10495
Issue ID: 10495
Summary: Environment variable for Systemd is ignored by
configure
Product: OpenLDAP
Version: 2.6.13
Hardware: All
OS: Linux
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: build
Assignee: bugs(a)openldap.org
Reporter: openldap.aftermost863(a)passinbox.com
Target Milestone: ---
Hello,
When using the configure script to generate the Makefile, the documentation in
the --help option states that the environment variable 'systemdsystemunitdir'
can be used to override the default system path for Systemd units.
However, this does not work: if I export the variable with a valid existing
path (e.g. 'export systemdsystemunitdir=/tmp/test') and then run ./configure,
the variable is found but is ignored in the output variables and is therefore
not used in the Makefile.
config.log:
...
## ---------------- ##
## Cache variables. ##
## ---------------- ##
...
ac_cv_env_systemdsystemunitdir_set=set
ac_cv_env_systemdsystemunitdir_value=/tmp/test
...
## ----------------- ##
## Output variables. ##
## ----------------- ##
...
systemdsystemunitdir='/usr/lib/systemd/system'
...
The configure script seems to override that variable on line 23942:
systemdsystemunitdir=
I don’t quite understand why this line is there, and it seems suspicious to me.
However, if I remove it and run ./configure again in the exact same shell,
config.log now shows the correct path in the output variables, and the Makefile
uses it correctly afterward:
...
## ---------------- ##
## Cache variables. ##
## ---------------- ##
...
ac_cv_env_systemdsystemunitdir_set=set
ac_cv_env_systemdsystemunitdir_value=/tmp/test
...
pkg_cv_systemdsystemunitdir=/tmp/test
## ----------------- ##
## Output variables. ##
## ----------------- ##
...
systemdsystemunitdir='/tmp/test'
I had this issue on both Debian 13 (using bash) and Arch Linux (using zsh).
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10597
Issue ID: 10597
Summary: slapo-accesslog frees a shared `entryUUID` value from
operations that do not hold the mutex guarding it,
causing a double free and heap corruption. Introduced
in 2.6.14 by the fix for ITS#10482.
Product: OpenLDAP
Version: 2.6.14
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: overlays
Assignee: bugs(a)openldap.org
Reporter: bohdan.kmit(a)kiteworks.com
Target Milestone: ---
Created attachment 1212
--> https://bugs.openldap.org/attachment.cgi?id=1212&action=edit
Patch
# Symptom
`slapd` terminates with SIGSEGV under concurrent write and search load. glibc
reports the corruption at whatever the process allocates next, so the message
varies:
```
double free or corruption (out)
malloc(): unaligned fastbin chunk detected
malloc(): unaligned tcache chunk detected
free(): invalid pointer
```
Of ten cores collected from one instance, nine abort inside `malloc()` or
`calloc()` at unrelated allocation sites and carry no information about the
origin. One caught the faulting free itself:
```
#4 free ()
#5 accesslog_response (op=<optimized out>, rs=...) at accesslog.c:2034
#6 ...
#8 slap_send_ldap_result ()
```
(line 2034 in 2.6.15; the equivalent is 2176 in current master.)
# Analysis
`accesslog_response()` ends with:
```c
skip:
if ( !BER_BVISNULL( &li->li_uuid ) ) {
ber_memfree( li->li_uuid.bv_val );
BER_BVZERO( &li->li_uuid );
}
if ( lo->mask & LOG_OP_WRITES ) {
/* We haven't transitioned to li_log_mutex yet */
ldap_pvt_thread_mutex_unlock( &li->li_op_rmutex );
}
return SLAP_CB_CONTINUE;
```
`li_uuid` is a field of the shared `log_info` instance, not of the operation.
Access to it is asymmetric:
* Write operations (`bi_op_add`, `bi_op_delete`, `bi_op_modify`, `bi_op_modrdn`
→ `accesslog_op_mod()`) acquire `li_op_rmutex` and populate `li_uuid` with
`ber_dupbv()` while holding it. They still hold it on entry to
`accesslog_response()`, free under it at `skip:`, and release it immediately
after. This is correct.
* Non-write operations (`bi_op_bind`, `bi_op_compare`, `bi_op_search`,
`bi_extended` → `accesslog_op_misc()`) take no lock at all.
`accesslog_response()` acquires `li_op_rmutex` for them only part-way through
the function, and **all four `goto skip` sites precede that acquisition**
(master: 1656, 1661, 1671, 1683 versus the lock at 1693). Such an operation
therefore reaches `skip:` holding no lock, and frees a pointer it never set.
The `goto skip` conditions reachable this way are:
| site | condition |
|------|-----------------------------------------------------|
| 1656 | log database absent or not open |
| 1661 | `op->o_dont_replicate` |
| 1671 | `li_success` configured and the operation failed |
| 1683 | operation not in `li_ops` and no matching `logbase` |
Two consequences follow:
1. Two non-write operations completing concurrently both observe a non-NULL
`li_uuid` and both call `ber_memfree()` on it — a double free.
2. A non-write operation can free it in the window between a write operation
storing the value and that write operation taking ownership of it (master
1716–1718, under both mutexes). The write path then works with, and frees, a
dangling pointer.
Either way the allocator's free lists are corrupted, and the failure surfaces
later at an unrelated allocation, which is why almost every core points
somewhere innocent.
The exposure depends strongly on configuration. With `olcAccessLogOps: writes`,
searches are not in `li_ops`, so **every search** fails the test at 1673 and
takes `goto skip` at 1683. A read-heavy workload therefore executes the
unlocked free at close to search rate. Note that 1683 is unreachable for write
operations, since `accesslog_op_mod()` applies the same test before registering
the callback.
Access to the tree of related state is otherwise correct: every use of
`li_mincsn`, `li_sids` and `li_numcsns` in `log_old_lookup()`,
`accesslog_purge()`, `accesslog_response()` and `accesslog_db_root()` is
serialised by `li_log_mutex`, and no locked region in the file contains a
`return` or `goto` that bypasses its unlock. `li_uuid` is the only unserialised
mutation.
# Regression
The unconditional free was added by:
```
5c4e7f2f1a ITS#10482 slapo-accesslog: do not leak entryUUID (2026-03-31)
ab4e53e54b same, backported to the 2.6 branch
```
That commit consists solely of those four lines. It plugs a genuine leak but
places the release on a path reachable without the mutex.
# Affected versions
| release | affected |
|--------------|----------|
| 2.6.13 | no |
| 2.6.14 | yes |
| 2.6.15 | yes |
| 2.7.0, 2.7.1 | yes |
| master | yes |
Observed on 2.6.15, x86-64, glibc, back-mdb, with `syncprov` and `accesslog` on
the same database and delta-syncrepl consumers reading the accesslog.
# Reproduction
Configuration: `accesslog` over back-mdb with `olcAccessLogOps: writes` and
`olcAccessLogSuccess: TRUE`.
Load: six concurrent MODIFY streams cycling over four DNs (to maximise
same-target concurrency), two more spread over twenty DNs, one stream of ADDs
of existing entries (returning `entryAlreadyExists`), and twelve concurrent
search streams over the same subtree.
Result: SIGSEGV within **13–24 seconds**, repeatably — effectively one crash
per load application.
Two observations that isolate the mechanism:
* The **same write load with no search streams ran 300 seconds without a
fault.** Searches are required, because only non-write operations take the
unlocked path.
* Instances receiving the identical replicated write stream but carrying **no
local search traffic** ran 68 minutes without a fault, while an instance with
local searches plus the same replicated writes crashed.
`MALLOC_CHECK_` does not help: by the time of the second free the chunk has
typically been handed to another allocation, so it is a valid live chunk and
nothing is flagged at the free.
# Proposed fix
Free the value only on the path that owns it and already holds the mutex:
```diff
skip:
- if ( !BER_BVISNULL( &li->li_uuid ) ) {
- ber_memfree( li->li_uuid.bv_val );
- BER_BVZERO( &li->li_uuid );
- }
if ( lo->mask & LOG_OP_WRITES ) {
+ /* Only this path holds li_op_rmutex, which guards li_uuid */
+ if ( !BER_BVISNULL( &li->li_uuid ) ) {
+ ber_memfree( li->li_uuid.bv_val );
+ BER_BVZERO( &li->li_uuid );
+ }
/* We haven't transitioned to li_log_mutex yet */
ldap_pvt_thread_mutex_unlock( &li->li_op_rmutex );
}
```
Non-write operations never populate `li_uuid`, so they have nothing to release;
the leak ITS#10482 addressed remains fixed for the write path, which is the
only producer. Because every `goto skip` precedes the mutex acquisition, no
path can now reach the label holding the lock without releasing it.
# Related observation, not addressed by this patch
`li_old` has the same missing release. `accesslog_op_mod()` assigns `li->li_old
= entry_dup( e )` without freeing any previous value, `accesslog_response()`
moves it out only on the non-skip path, and neither `skip:` nor
`accesslog_db_destroy()` releases it. A write operation whose response takes
`goto skip` therefore strands an `Entry`, which the next write overwrites and
leaks. This requires `olcAccessLogOld` to be configured and is a leak only — no
unserialised free, so no corruption. Reported for completeness rather than
fixed here.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10608
Issue ID: 10608
Summary: back-mdb: cached per-thread read txns of a database
deleted via cn=config are never released -> err=80
"internal error" on new databases
Product: OpenLDAP
Version: 2.6.13
Hardware: x86_64
OS: Linux
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: backends
Assignee: bugs(a)openldap.org
Reporter: coding(a)markus-mazurczak.de
Target Milestone: ---
Created attachment 1218
--> https://bugs.openldap.org/attachment.cgi?id=1218&action=edit
Patch: 0002-back-mdb-purge-reader-keys-on-db-close
SUMMARY
=======
When a back-mdb database is removed at runtime with an ldapdelete of its
olcDatabase entry in cn=config, only the thread that performs the delete
releases its cached read transaction for that database. Every other worker
thread keeps its cached entry for good: the key is the (now freed) MDB_env
pointer and the value a read txn of the closed environment.
The leak accumulates with every database that is created, read and deleted.
Once a worker thread has collected about 32 such dead entries, operations on
any NEWLY created database fail in that thread with
RESULT tag=97 err=80 qtime=0.000020 etime=0.000082 text=internal error
(on glibc builds the result code is err=12, see below). Databases whose
entry was cached before the slots filled up keep working, so the failure
looks random: it hits only new databases and only some threads.
This is the typical life cycle of a multi-tenant directory that provisions
one mdb database per tenant through cn=config. In our production server the
first bind to a freshly provisioned tenant failed sporadically with err=80
after a few hundred tenant create/delete cycles; restarting slapd made it go
away until the slots filled again.
ANALYSIS
========
mdb_opinfo_get() caches one read txn per worker thread and database in the
thread-pool context, keyed by the environment pointer
(servers/slapd/back-mdb/id2entry.c, openldap-2.6.13):
790 if ( ldap_pvt_thread_pool_getkey( ctx, mdb->mi_dbenv, &data, NULL ) )
{
... mdb_txn_begin( ..., MDB_RDONLY, &moi->moi_txn ) ...
808 if ( ( rc = ldap_pvt_thread_pool_setkey( ctx, mdb->mi_dbenv,
data, mdb_reader_free, NULL, NULL ) ) ) {
...
812 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: thread_pool_setkey
failed err (%d)\n", rc );
return rc;
}
} else {
moi->moi_txn = data;
818 renew = 1;
}
...
827 rc = mdb_txn_renew( moi->moi_txn );
828 assert(!rc);
When the database is closed, mdb_db_close() releases only the key of the
calling thread (servers/slapd/back-mdb/init.c):
349 mdb_reader_flush( mdb->mi_dbenv );
mdb_reader_flush() (id2entry.c:687) looks up ldap_pvt_thread_pool_context(),
i.e. the current thread. The only place in back-mdb that clears the key in
all threads is the olcDbDirectory handler (config.c:630), which calls
ldap_pvt_thread_pool_purgekey() -- documented as "May only be called while
the pool is paused" (libraries/libldap/tpool.c:1424).
Deleting a database through cn=config does not purge. config_back_delete()
pauses the server and then calls
bconfig.c:6881 ce->ce_be->bd_info->bi_db_close( ce->ce_be, NULL );
bconfig.c:6884 backend_destroy_one( ce->ce_be, 1);
so mdb_db_close() runs while the pool is paused, but still only flushes the
deleting thread. Every other thread that ever read from that database keeps
a dangling {env pointer -> txn} entry.
Two consequences, both observed:
1. Slot exhaustion. A thread context has MAXKEYS = 32 key slots
(tpool.c:52). Dead entries are never removed, so after roughly 32 deleted
databases per thread, ldap_pvt_thread_pool_setkey() returns ENOMEM
(tpool.c:1412) for every new database. mdb_opinfo_get() returns that value
and mdb_bind() answers with it and "internal error" (bind.c:62). The log
shows
mdb_opinfo_get: thread_pool_setkey failed err (12)
RESULT tag=97 err=12 ... text=internal error
The raw errno ends up as the LDAP result code (12 is
unavailableCriticalExtension), which is a small secondary issue.
2. Stale txn reuse (ABA). With an allocator that hands out a freed address
again right away (musl), the MDB_env of a newly created database often
gets the address of a deleted one. getkey() then finds the dead entry,
mdb_opinfo_get() takes the renew path with a txn that belongs to the closed
environment, and the assert(!rc) after mdb_txn_renew() is compiled out in
release builds. The next access fails; with a debug print in mdb_bind()
we see
bind/dn2entry: rc=MDB_BAD_DBI: The specified DBI handle was
closed/changed unexpectedly(-30780)
RESULT tag=97 err=80 ... text=internal error
This is what production (Alpine) shows. Continuing with a txn object of a
destroyed environment is also a memory-safety problem in itself; we did
not see an AddressSanitizer report in our runs (ASan's quarantine prevents
the address reuse), so we do not claim more than the observed behaviour.
REPRODUCTION
============
Self-contained script: stale-reader-test.sh (attached). It needs slapd,
slapadd, slappasswd and the ldap client tools, and runs in a throw-away
container:
1. start slapd with a cn=config database and olcThreads: 2 (or 16)
2. create a long-lived database "dc=steady" and bind to it once
3. repeat 60 times:
- ldapadd olcDatabase=mdb (olcSuffix dc=cN, own olcDbDirectory)
- add dc=cN and cn=admin,dc=cN (simpleSecurityObject)
- 8 simple binds as cn=admin,dc=cN (spread over the worker threads)
- one bind to dc=steady
- ldapdelete the olcDatabase entry of dc=cN, remove its directory
4. count failed binds
# Alpine 3.23 package build of 2.6.13, back_mdb as module
podman run --rm --entrypoint bash -v ./stale-reader-test.sh:/t.sh:ro,z \
-e CYCLES=60 -e BINDS=8 -e MODULES=1 <image> /t.sh
# source build (back-mdb built in), e.g. with AddressSanitizer
podman run --rm -v ./stale-reader-test.sh:/t.sh:ro,z \
-e CYCLES=60 -e BINDS=8 -e THREADS=4 -e MODULES=0 <image> bash /t.sh
Results. All builds contain the ITS#10607 patch (without it, concurrent
cn=config writes crash slapd); the pairs differ only in the attached patch:
build threads cycles x binds failed binds first
---------------------------- ------- -------------- ------------- -----
Alpine 2.6.13 (musl) 2 60 x 8 137 (err=80) 34
Alpine 2.6.13 (musl) 16 200 x 40 4079 (err=80) 34
Alpine 2.6.13 + patch 16 200 x 40 0 -
Alpine 2.6.13 + patch 2 60 x 8 0 -
source build, glibc + ASan 4 60 x 8 57 (err=12) 51
source build, glibc + ASan + patch 4 60 x 8 0 -
Binds to the long-lived database dc=steady never failed in any run, which is
why the problem is easy to miss: only new databases are affected.
On our production server (Alpine, 16 threads) the same sequence with 80
cycles x 40 binds against the patched build ran 3200 binds without a single
failure and without any err=80 in the log.
The first failure appears after about 30 cycles because every cycle leaves
one dead key in each thread that served a read from that database, and a
thread context also holds a few unrelated keys (e.g. the search stack).
PATCH
=====
In mdb_db_close(), purge the key from all threads when the pool is paused,
which is the case when the database is deleted via cn=config; otherwise keep
the existing per-thread flush (shutdown, slap tools). This mirrors what the
olcDbDirectory handler in back-mdb/config.c already does.
if ( ( slapMode & SLAP_SERVER_MODE ) &&
ldap_pvt_thread_pool_pausing( &connection_pool ) > 0 )
ldap_pvt_thread_pool_purgekey( mdb->mi_dbenv );
else
mdb_reader_flush( mdb->mi_dbenv );
ldap_pvt_thread_pool_purgekey() calls the key's free function
(mdb_reader_free -> mdb_txn_abort) for every thread while the environment is
still open, so the cached read txns are ended before mdb_env_close() instead
of outliving it.
The patch applies with -p1 to openldap-2.6.13 (on its own or on top of the
ITS#10607 patch), to OPENLDAP_REL_ENG_2_6 and to master (hunk offset 30
lines).
Verification with the patch applied:
- stale-reader-test.sh: 0 failed binds (tables above), AddressSanitizer clean
- the concurrent cn=config load test from ITS#10607 (4 parallel
create/overlay/modify/delete loops plus continuous binds to an unrelated
database), which exercises the new purgekey path under concurrency:
Alpine build, 150 s: 13083 database cycles, 0 of 19606 binds rejected,
no crash
glibc + ASan, 120 s: 9579 database cycles, 0 of 14565 binds rejected,
AddressSanitizer clean
- server restart with existing databases and our orphaned-directory start
test: unchanged behaviour
Open points, happy to adjust:
- The check could live in config_back_delete() instead (it knows it is
removing a database while paused); putting it into mdb_db_close() keeps
the knowledge about the key inside back-mdb, like config.c:630.
- mdb_bind() and friends return the raw errno from mdb_opinfo_get() as LDAP
result code (err=12). Mapping it to LDAP_OTHER would be more accurate;
not part of this patch.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10611
Issue ID: 10611
Summary: slappasswd with sha2 can generate wrong hashes
Product: OpenLDAP
Version: 2.6.14
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: contrib
Assignee: bugs(a)openldap.org
Reporter: ondra(a)mistotebe.net
Target Milestone: ---
Depending on compiler version and build flags, SHA256 and SSHA256 can generate
the wrong hash. e.g. hashing password `test`:
- local build (./servers/slapd/slapd -Tp -o
module-load=./contrib/slapd-modules/passwd/sha2/pw-sha2.la -h '{SHA256}' -s
test): `{SHA256}AFQU1hg1xqCsA68tVBURFs7dJbJ25QC/Ancq/MQQXKM=`
- independent (echo -n 'test' | openssl dgst -sha256 -binary | base64):
`n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=`
The issue appears to be pointer aliasing violation that the compiler optimises
through. Other implementations already carry a fix, so we can apply that.
None of the known packages (Symas, LTB, Debian) that I tested were affected,
they emit the correct hash but this appears to have been quietly patched around
by setting `OPT=-fno-strict-aliasing` without a report I can see here[0]
[0].
https://salsa.debian.org/openldap-team/openldap/-/blob/master/debian/rules?…
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10590
Issue ID: 10590
Summary: sssvlv rejects multiple sort keys with protocolError
in OpenLDAP 2.6.15
Product: OpenLDAP
Version: 2.6.15
Hardware: x86_64
OS: Linux
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: overlays
Assignee: bugs(a)openldap.org
Reporter: christian(a)roessner.email
Target Milestone: ---
Created attachment 1204
--> https://bugs.openldap.org/attachment.cgi?id=1204&action=edit
repro.go: anonymous RootDSE one-key versus two-key sorting (go-ldap v3.4.14)
OpenLDAP 2.6.15 with the sssvlv overlay rejects a valid server-side sorting
control containing two keys with:
LDAP Result Code 2 "Protocol Error": serverSort control: decoding error
A single key succeeds. Two keys fail with and without the simple paged results
control. Reproduced using go-ldap/v3 v3.4.14, including an anonymous RootDSE
base search. Tested pairs: cn + uid and uniqueIdentifier + uid, with
caseIgnoreOrderingMatch explicitly selected for both keys.
The application binds before requesting its initial sorted page, so this
presents to users as a connection failure despite successful authentication.
Environment: OpenLDAP 2.6.15 in a Linux x86_64 container (chrroessner/openldap
LTS), on an AlmaLinux 10.2 host; client Go / macOS x86_64. The configuration
loads sssvlv and enables overlay sssvlv. No sort-key limit override is
configured (default five). A pristine upstream build has not yet been run for
comparison.
REPRODUCTION
The attached repro.go sends only anonymous RootDSE searches, without reading
directory accounts or writing data. Run against a disposable local server with
sssvlv registered and a localhost LDAP listener on port 1389:
mkdir ldap-sort-repro && cd ldap-sort-repro
go mod init example.org/ldap-sort-repro
go get github.com/go-ldap/ldap/v3@v3.4.14
# Copy the attached repro.go into this directory.
go run .
Expected: valid one-key and two-key requests are accepted.
Observed on 2.6.15: the one-key case succeeds; both two-key cases return the
diagnostic above.
SUSPECTED CAUSE
In servers/slapd/overlays/sssvlv.c, build_key(), comparison of upstream tags
OPENLDAP_REL_ENG_2_6_13 and OPENLDAP_REL_ENG_2_6_15 shows the closing
ber_scanf(ber, "}") replaced with:
if (( tag = ber_peek_tag( ber, &len )) != LBER_DEFAULT ) {
rs->sr_text = "serverSort control: decoding error";
rs->sr_err = LDAP_PROTOCOL_ERROR;
return rs->sr_err;
}
The parser still shares the enclosing SortKeyList BER cursor across keys. After
the first valid key, the next key's SEQUENCE remains in the cursor, so this
check rejects a valid second key. This source change matches the observed
diagnostic. The initial sequence handling also changed from ber_scanf to
ber_skip_tag.
The intended validation appears to require enforcing the boundary of the
current SortKey SEQUENCE, while permitting the next key in SortKeyList. Simply
accepting arbitrary trailing BER would not be an appropriate fix.
Source:
https://git.openldap.org/openldap/openldap/-/blob/OPENLDAP_REL_ENG_2_6_15/s…
Potentially related: ITS#10564, which records the sss_parseCtrl tightening
(RE26 commit 6c0323aa). This report concerns rejection of valid sibling sort
keys, not the malformed-input issue reported there.
The release branch and current master source inspected on 2026-09-14 contain
the same build_key() end-of-input check. This is source inspection, not a
master runtime test. No live comparison against 2.6.13 was performed, so this
report does not claim a verified first affected release.
TEMPORARY CLIENT MITIGATION
On the exact diagnostic above, retry only an initial search (no active paging
cookie) with the primary sort key alone. Preserve that key for subsequent pages
and cursor release. This drops the UID tie-breaker for equal primary values.
Other errors remain visible.
Suggested regression coverage: two and three keys, optional
orderingRule/reverseOrder, paging continuation and cursor release, plus
malformed/trailing BER rejection.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10573
Issue ID: 10573
Summary: OpenLDAP 2.7.0 fails to build with MSVC when
preprocessing symbol version maps
Product: OpenLDAP
Version: 2.7.0
Hardware: All
OS: Windows
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: build
Assignee: bugs(a)openldap.org
Reporter: openldap-msvc-673e3a64ee4f43(a)emalupe.com
Target Milestone: ---
OpenLDAP 2.7.0 fails to build with MSVC while generating the liblber symbol
version map. The regression appears to have been introduced by commit
8651f98a08c37bea6ee9be78acececd52bac66a0 (ITS#9739).
The new rules in libraries/liblber/Makefile.in and
libraries/libldap/Makefile.in invoke:
$(CPP) -x c -o $@ $(LT_CPPFLAGS) $(srcdir)/$(SYMBOL_VERSION_SCRIPT).in
The -x c option is specific to GCC/Clang. When Autoconf's configured C
preprocessor is MSVC (cl -E), cl ignores -x and treats the following c as an
input filename:
cl : Command line warning D9002 : ignoring unknown option '-x'
c1: fatal error C1083: Cannot open source file: 'c': No such file or
directory
make[2]: *** [Makefile:301: lber.map] Error 2
This was reproduced with OpenLDAP 2.7.0 and Visual Studio 2026/MSVC 14.51 on
Windows. OpenLDAP 2.6.13 builds successfully with the same compiler setup
because it does not preprocess these map files.
The same non-portable invocation is present in both the liblber and libldap
map-generation rules and remains in the current OPENLDAP_REL_ENG_2_7 and master
branches.
Could the hard-coded compiler language option be removed or replaced with a
configure-detected, compiler-portable way to preprocess the .map.in files?
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10600
Issue ID: 10600
Summary: Deferred referral work can be attached to the wrong
LDAP request
Product: OpenLDAP
Version: 2.7.1
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: libraries
Assignee: bugs(a)openldap.org
Reporter: simon.pichugin(a)gmail.com
Target Milestone: ---
When two operations receive referrals to the same connection while an anonymous
rebind is in progress, lconn_rebind_queue stores URL arrays without retaining
the request that owns each deferred referral. When the queue is drained, it
uses the request context performing the rebind, so a child search can be
attached to the wrong operation.
How to reproduce
Start two asynchronous searches on one LDAP handle. Have the origin return
referrals for both operations to the same target, timing the second referral so
it arrives while the target connection is performing the first anonymous bind.
Let the target accept the bind and return successful results for both referred
searches. Operation A receives its final result, while operation B has no
deliverable final result and reaches its caller-supplied timeout.
We reproduced this using public asynchronous APIs on one LDAP handle. The
target validated both child search IDs and base DNs. Operation A completed, but
operation B had no deliverable final result and timed out.
Short result
client_search_ids=1,2
origin_search_ids=1,2
target_verified_anonymous_bind id=4
origin_sent_b_referral_during_a_bind
target_child_search_ids=3,5
target_child_search_bases=dc=target-a,dc=target-b
operation_a_result=101 errno=0
operation_b_result=0 errno=-5 expected_timeout=-5
The test was generated using AI, so I can't share it here as per OpenLDAP's
Policy on AI Contributions. Hence, describing the process with words.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10610
Issue ID: 10610
Summary: If double free if ldapi: socket name is too long
Product: OpenLDAP
Version: 2.6.14
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: slapd
Assignee: bugs(a)openldap.org
Reporter: ondra(a)mistotebe.net
Target Milestone: ---
slap_get_listener_addresses() frees the *sal on error and then its caller does
the same. slap_get_listener_addresses() should just zero it afterwards? Also
the error message lacks a trailing newline.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10593
Issue ID: 10593
Summary: VLV response formatting can read past a stack buffer
and crash ldapsearch
Product: OpenLDAP
Version: 2.7.1
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: client tools
Assignee: bugs(a)openldap.org
Reporter: simon.pichugin(a)gmail.com
Target Milestone: ---
Created attachment 1209
--> https://bugs.openldap.org/attachment.cgi?id=1209&action=edit
full asan and search results
print_vlv() formats the server-provided VLV contextID into a fixed stack
buffer. If snprintf() truncates the output, its required length is passed to
the LDIF writer, which reads past the end of the buffer.
We reproduced this with an unmodified ldapsearch that explicitly requested
server-side sorting on cn and a VLV window. The server verified both request
controls, returned one valid entry, then returned SSS success and a valid VLV
success response with a large server-defined contextID. A 16 KiB contextID
produced an ASan stack-buffer-overflow. A 64 KiB contextID crashed a
non-sanitized, optimized client with SIGSEGV in all five runs.
This is different from the SSS case. A VLV contextID is an opaque value
selected by the server, and the VLV specification does not set a size limit.
The triggering response does not need to mismatch caller input or violate the
defined control sequence. The client must opt into VLV, and a 64 KiB contextID
is unusual.
Short ASan trace
ERROR: AddressSanitizer: stack-buffer-overflow
READ of size 1
#0 ldif_sput_wrap libraries/libldap/ldif.c:622
#1 ldif_put_wrap libraries/libldap/ldif.c:705
#2 tool_write_ldif clients/tools/common.c:2791
#3 print_vlv clients/tools/common.c:2264
#4 tool_print_ctrls clients/tools/common.c:2781
SUMMARY: AddressSanitizer: stack-buffer-overflow libraries/libldap/ldif.c:622
in ldif_sput_wrap
Short native trace
Program received signal SIGSEGV, Segmentation fault.
#0 ldif_sput_wrap libraries/libldap/ldif.c:579
#1 ldif_put_wrap libraries/libldap/ldif.c:705
#2 tool_write_ldif clients/tools/common.c:2791
#3 print_vlv clients/tools/common.c:2264
#4 tool_print_ctrls clients/tools/common.c:2781
#5 print_result clients/tools/ldapsearch.c:2426
#6 dosearch clients/tools/ldapsearch.c:1840
#7 main clients/tools/ldapsearch.c:1550
--
You are receiving this mail because:
You are on the CC list for the issue.