https://bugs.openldap.org/show_bug.cgi?id=10656
Issue ID: 10656
Summary: No mmap address hint to map above 47-bit (128TiB)
window
Product: LMDB
Version: unspecified
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: liblmdb
Assignee: bugs(a)openldap.org
Reporter: coder-wangzhen(a)qq.com
Target Milestone: ---
Created attachment 1242
--> https://bugs.openldap.org/attachment.cgi?id=1242&action=edit
Patch: add mdb_env_set_maphint() (git format-patch)
Description:
Overview:
On x86-64 hosts with 5-level paging (LA57) enabled, the kernel still
defaults to a 47-bit (128 TiB) user virtual-address window: mmap() is not
placed above 2^47 unless the caller passes an explicit hint address >= 2^47.
LMDB always calls mmap(NULL, ...) in mdb_env_map(), so a process mapping
several large environments can exhaust the 128 TiB window and get ENOMEM,
even though the workload fits in the 56-bit address space. There is no
sysctl/prctl/rlimit that lifts this default; it is opt-in per mmap call.
See https://www.kernel.org/doc/html/v5.4/x86/x86_64/5level-paging.html
Proposed:
Add a per-environment, non-persistent, advisory mmap address hint:
int mdb_env_set_maphint(MDB_env *env, void *addr);
- Default (never called, or addr == NULL): unchanged, mmap(NULL, ...).
- Set to e.g. (void *)(1ULL << 47): passed as the mmap hint so the kernel
can place the map in the full 56-bit address space.
Distinct from MDB_FIXEDMAP, which persists the address into data.mdb and is
a multi-process fixed-address scheme. The hint is advisory: the kernel may
ignore it and the environment still opens normally.
Expected:
With mdb_env_set_maphint(env, (void *)(1ULL << 47)) set before
mdb_env_open(), a single process can map environments above 2^47 and its
total VSZ can exceed 128 TiB.
Windows:
Windows x64 uses 48-bit virtual addresses (128 TiB user space) and does not
support 5-level paging, so the motivating use case (mapping above 2^47) is
Linux-only. The patch nonetheless implements the Windows path
(NtMapViewOfSection, with fallback to OS-chosen placement when the requested
address is occupied) for API consistency. Given Windows cannot map above
128 TiB anyway, is the Windows portion still wanted, or should the change be
POSIX-only?
Additional Information:
Patch attached (git format-patch against mdb.master3). Discussed on
openldap-devel:
https://lists.openldap.org/hyperkitty/list/openldap-devel@openldap.org/thre…
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10613
Issue ID: 10613
Summary: On old PowerPC Mac with Mac OS X 10.5.8 (Leopard) test
suite fails in test017-syncreplication-refresh
Product: OpenLDAP
Version: 2.6.14
Hardware: All
OS: Mac OS
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: test suite
Assignee: bugs(a)openldap.org
Reporter: Peter_Dyballa(a)Web.DE
Target Milestone: ---
This is the actual report:
>>>>> 00:07:04 Failed test017-syncreplication-refresh for mdb after 47 seconds
How to debug?
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10645
Issue ID: 10645
Summary: ldapsearch -E vlv behaviour is near useless
Product: OpenLDAP
Version: unspecified
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: client tools
Assignee: bugs(a)openldap.org
Reporter: ondra(a)mistotebe.net
Target Milestone: ---
It pretends to walk the filter when asked to continue but there are issues:
- there is no way to stop it (EOF is the same as Enter and no other options
available)
- setting "after" count to 0 has it keep issuing the same search over and over
- no end of list detection, so it happily overshoots and then fails with
rangeError
- ignores the returned position that the server sent so can't resume after
re-positioning (e.g. with value based search)
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10663
Issue ID: 10663
Summary: syncprov: double free of sync controls since ITS#10473
Product: OpenLDAP
Version: unspecified
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: overlays
Assignee: bugs(a)openldap.org
Reporter: hamano(a)osstech.co.jp
Target Milestone: ---
The fix for this ticket (RE26: 7d9b599982, master: 87197f91fc) causes the sync
state controls to be freed twice in OpenLDAP 2.6.14 and later, and in master.
## Details
Three of the four callers of `syncprov_state_ctrl()` / `syncprov_done_ctrl()`
have set `REP_CTRLS_MUSTBEFREED` since ITS#6795 and ITS#7292, so the frontend
(`send_ldap_response()` / `slap_send_search_entry()` /
`slap_send_search_reference()`) already frees each control individually with
`slap_free_ctrls()` after `slap_cleanup_play()`.
With this fix, the control lives in the same allocation as a `slap_callback`.
After `slap_freeself_cb` has freed the callback (and the control with it),
`slap_free_ctrls()` passes a pointer into the middle of the freed callback
(`&cb[1]`) to `o_tmpfree()` again.
The only leak in the original report is the `no_change:` path, which uses a
controls array on the stack and does not set `REP_CTRLS_MUSTBEFREED`.
Also, `slap_add_ctrls()` copies the pointers of an existing `sr_ctrls` into a
new array and sets `REP_CTRLS_MUSTBEFREED`, so `slap_free_ctrls()` relies on
each control being allocated on its own. Embedding the control in a callback
is not compatible with that.
## Impact
When the allocation did not fit in the slab and fell back to `ber_memalloc_x()`
(for example a long replay of a persistent search, or a refresh of large
entries), or when `o_tmpmemctx` is NULL, the interior pointer reaches libc
`free()` and the provider slapd aborts with `free(): invalid pointer`.
## Proposed fix
1. Revert this fix (87197f91fc / 7d9b599982) so that the control is allocated
on its own again, as before.
2. In the `no_change:` path, free the control after `send_ldap_result()`.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10473
Issue ID: 10473
Summary: syncprov leaks response controls
Product: OpenLDAP
Version: unspecified
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: overlays
Assignee: bugs(a)openldap.org
Reporter: ondra(a)mistotebe.net
Target Milestone: ---
syncprov_state_ctrl and syncprov_done_ctrl add controls to the response, but
noone cares to free them afterwards assuming they are allocated from the slab.
If there are many messages sent in a single run, this takes up fresh memory
that's leaked eventually.
See its8800 regression test for an example where this happens.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10657
Issue ID: 10657
Summary: libldap: sockets revert to blocking mode after an
async connect (LDAP_OPT_CONNECT_ASYNC)
Product: OpenLDAP
Version: 2.7.2
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: libraries
Assignee: bugs(a)openldap.org
Reporter: a.cudbardb(a)freeradius.org
Target Milestone: ---
Created attachment 1243
--> https://bugs.openldap.org/attachment.cgi?id=1243&action=edit
Only restore blocking mode when LDAP_OPT_CONNECT_ASYNC is off (os-ip.c,
os-local.c)
libldap puts a connection's socket back into blocking mode once an asynchronous
connect completes, even when the caller has set LDAP_OPT_CONNECT_ASYNC.
ldap_int_poll() in libraries/libldap/os-ip.c calls ldap_pvt_ndelay_off()
unconditionally once the socket is ready. That suits its original caller,
ldap_pvt_connect(), which only makes the socket non-blocking to put a timeout
on connect(), but ldap_send_server_request() and ldap_int_check_async_open()
also call ldap_int_poll() to check whether an async connect has completed, and
for those callers it switches off the non-blocking as a side-effect.
The attached patch only restores blocking mode when LDAP_OPT_CONNECT_ASYNC is
off. Synchronous callers are unaffected.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10654
Issue ID: 10654
Summary: slapo-auditlog writes password values (hashed or
cleartext) to the log
Product: OpenLDAP
Version: 2.7.2
Hardware: x86_64
OS: Linux
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: slapd
Assignee: bugs(a)openldap.org
Reporter: dns.spiros(a)gmail.com
Target Milestone: ---
Created attachment 1241
--> https://bugs.openldap.org/attachment.cgi?id=1241&action=edit
proposed patch for this ITS to apply with git-am.
slapo-auditlog records every value of every attribute in Add and Modify
operations, including the internal Modify issued by the Password Modify
extended operation. As a result userPassword hashes are written to the
audit log, and cleartext passwords too when a client sends them (absent
ppolicy hash_cleartext).
The database protects userPassword with ACLs (typically "by self write
by anonymous auth"), but the audit log is a plain file that is commonly
readable by a log group, rotated, backed up and shipped to SIEMs. Fast
schemes such as {SSHA} make the logged hashes cheap to crack offline.
This conflicts with widely used security requirements:
- CWE-532 "Insertion of Sensitive Information into Log File":
"Do not write secrets into the log files."
https://cwe.mitre.org/data/definitions/532.html
- NIST SP 800-63B-4, sec. 3.1.1.2: "Verifiers SHALL store passwords in
a form that is resistant to offline attacks." A copy of the hashes in
a log file defeats the protection given to the stored form.
https://pages.nist.gov/800-63-4/sp800-63b/authenticators/
- OWASP ASVS 5.0, req. 16.2.5 (L2): logging must not include data such
as credentials or payment details (4.0.3: req. 7.1.1).
https://github.com/OWASP/ASVS/blob/master/5.0/en/0x25-V16-Security-Logging-…
- DISA Application Security and Development STIG, V-222444
(APSC-DV-000650, CCI-000169): "The application must not write
sensitive data into the application logs"; logging passwords is a
finding.
https://www.stigviewer.com/stigs/application_security_and_development/2025-…
Other directory servers: 389-DS stopped logging cleartext passwords in
its audit log (Ticket 365, CVE-2010-3282) and since Issue 6884 (2025)
also masks password hashes (userPassword, nsslapd-rootpw, replication
credentials) in both LDIF and JSON audit logs, unconditionally.
The attached patch adds a multi-valued auditlogmask / olcAuditlogMask
option. Values of the listed attributes (and their subtypes) are
replaced by a "# <attr>: (masked)" comment line; the attribute name and
modification type are still logged, so password changes remain
auditable. A comment is used rather than a placeholder value so that
replaying the log can never set a password to a known string.
The default is empty, so behaviour is unchanged unless configured;
masking userPassword by default could be considered.
test090-auditlog and slapo-auditlog(5) are updated.
The patch is a single commit for git am. As I am not yet familiar with
the current contribution practices, its subject still carries an
ITS#XXXXX placeholder; please amend the commit message as you see fit
when applying it.
The attached patch file is derived from OpenLDAP Software. All of the
modifications to OpenLDAP Software represented in the following
patch(es) were developed by Elia Pinto <gitter.spiros(a)gmail.com>.
I have not assigned rights and/or interest in this work to any party.
I, Elia Pinto, hereby place the following modifications to OpenLDAP
Software (and only these modifications) into the public domain. Hence,
these modifications may be freely used and/or redistributed for any
purpose with or without attribution and/or other notice.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10655
Issue ID: 10655
Summary: Add a commit() that keeps the write mutex
Product: LMDB
Version: unspecified
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: enhancement
Priority: ---
Component: liblmdb
Assignee: bugs(a)openldap.org
Reporter: hyc(a)openldap.org
Target Milestone: ---
Add an mdb_txn_commit2() function that doesn't free the txn handle. This allows
callers to cleanup if the commit fails, while keeping the write lock.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10614
Issue ID: 10614
Summary: On old PowerPC Mac with macOS High Sierra, Version
10.13.6 test suite fails in
test050-syncrepl-multiprovider
Product: OpenLDAP
Version: 2.6.14
Hardware: x86_64
OS: Mac OS
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: test suite
Assignee: bugs(a)openldap.org
Reporter: Peter_Dyballa(a)Web.DE
Target Milestone: ---
This is the actual report:
>>>>> 00:10:56 Failed test050-syncrepl-multiprovider for mdb after 115 seconds
How to debug?
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10659
Issue ID: 10659
Summary: slapo-deref: the cached ACL result is shared between
the search entry and the dereferenced entries,
disclosing attribute values the client may not read
Product: OpenLDAP
Version: unspecified
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: overlays
Assignee: bugs(a)openldap.org
Reporter: hamano(a)osstech.co.jp
Target Milestone: ---
- Affected versions: 2.5.20, 2.6.16, master
## Summary
`deref_response()` in slapo-deref passes a single `AccessControlState` to
`access_allowed()` for both
the search result entry (`rs->sr_entry`) and the dereferenced entries (`e`).
The cache in
`access_allowed()` does not distinguish entries, so when an attribute that was
allowed on one entry
is evaluated on another entry, the cached result is used without evaluating the
ACLs. As a result,
a client sending the Dereference control (not an RFC,
draft-masarati-ldap-deref) can receive
attribute values in the response control that the ACLs do not allow it to read.
## Details
`servers/slapd/overlays/deref.c`:
```c
AccessControlState acl_state = ACL_STATE_INIT;
...
if ( !access_allowed( op, rs->sr_entry,
a->a_desc,
NULL, ACL_READ, &acl_state ) )
/* search result entry */
...
rc = overlay_entry_get_ov( op,
&a->a_nvals[ i ], NULL, NULL, 0, &e, dc->dc_on );
...
if (
!access_allowed( op, e, ds->ds_attributes[ j ], NULL,
ACL_READ, &acl_state ) ) /* dereferenced entry */
...
if ( !access_allowed( op, e,
aa->a_desc,
&aa->a_nvals[ k ],
ACL_READ, &acl_state ) )
```
`access_allowed_mask()` in `servers/slapd/acl.c` returns the cached
`state->as_result` as is when
`state->as_desc` and `state->as_access` match and there are no value dependent
ACLs
(`!state->as_vd_acl_present`). It does not check the entry or the value.
```c
if ( state != NULL ) {
if ( state->as_desc == desc &&
state->as_access == access &&
state->as_result != -1 &&
!state->as_vd_acl_present )
{
Debug( LDAP_DEBUG_ACL,
"=> access_allowed: result was in cache
(%s)\n",
attr );
return state->as_result;
```
`send_search_entry()` initializes an `AccessControlState` for each entry, so it
does not have this
problem. deref reuses one state across several entries, so the result for
another entry is used in
the following two cases:
1. The same attribute as derefAttr is requested from the dereferenced entries
(e.g. dereference
`member` and request `member`). The result for `member` of the search result
entry is used for
`member` of the dereferenced entries.
2. The same attribute is requested from several dereferenced entries. The
result for the first
dereferenced entry is used for the second and subsequent ones.
If an "allowed" result is cached, values the client may not read are returned;
conversely, if a
"denied" result is cached, values the client may read are not returned.
## Impact
With the deref overlay configured, and ACLs that allow or deny reading the same
attribute depending
on the entry's location (DN), a client that can search (possibly including
anonymous, depending on
the ACLs) can obtain attribute values it is not allowed to read.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10651
Issue ID: 10651
Summary: argon2 pwmod: hashed value includes trailing NUL byte
when built with libargon2
Product: OpenLDAP
Version: 2.6.16
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: slapd
Assignee: bugs(a)openldap.org
Reporter: hamano(a)osstech.co.jp
Target Milestone: ---
With libargon2 (`HAVE_LIBARGON2`), `slapd_argon2_hash()` sets
```c
hash->bv_len = scheme->bv_len + encoded_length;
```
but `argon2_encodedlen()` includes the terminating NUL, so the stored
`{ARGON2}` value ends with `\0` (and is shown base64-encoded in LDIF). The
libsodium path uses `strlen()` and is not affected.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10658
Issue ID: 10658
Summary: lutil_passwd_generate() returns uninitialized memory
as the generated password when it fails to get random
bytes
Product: OpenLDAP
Version: unspecified
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: slapd
Assignee: bugs(a)openldap.org
Reporter: hamano(a)osstech.co.jp
Target Milestone: ---
- Affected versions: 2.5.20, 2.6.16, master
## Summary
When `lutil_entropy()` fails, `lutil_passwd_generate()` returns -1 but leaves
`pw->bv_len` and the
already allocated `pw->bv_val` in place. The callers in slapd check `bv_len`
rather than the return
value, so 8 bytes of uninitialized memory are set as the new password and
returned to the client
in the Password Modify response (genPasswd).
## Details
`libraries/liblutil/passwd.c`:
```c
int lutil_passwd_generate( struct berval *pw, ber_len_t len )
{
if( len < 1 ) return -1;
pw->bv_len = len;
pw->bv_val = ber_memalloc( len + 1 );
if( pw->bv_val == NULL ) {
return -1; /* bv_len is still len */
}
if( lutil_entropy( (unsigned char *) pw->bv_val, pw->bv_len) < 0 ) {
return -1; /* bv_val is uninitialized, bv_len is
still len */
}
...
```
Callers:
- `slap_passwd_generate()` in `servers/slapd/passwd.c` ignores the return value
of
`lutil_passwd_generate()`.
- `slap_exop_passwd()` and `slap_sasl_setpass()` in `servers/slapd/sasl.c`
detect a generation
failure only by `bv_len == 0`.
So when `lutil_entropy()` fails, the uninitialized buffer (raw bytes, not even
mapped to crypt64)
is hashed and set as the new password, and returned as genPasswd.
- If `password-hash` uses a salted scheme (such as the default `{SSHA}`),
generating the salt fails
for the same reason and the operation fails with "password hash failed", so
no password is set.
- With an unsalted scheme (`{SHA}`, `{CLEARTEXT}`, ...) the password is set as
is.
- `bv_len` is also left set when `ber_memalloc()` fails (the callers then use a
NULL `bv_val`).
`lutil_entropy()` simply opens and reads `/dev/urandom`, so it fails when the
process has run out of
file descriptors (EMFILE, which can be caused remotely by opening many
connections to slapd) or in a
chroot without `/dev/urandom`.
## A better improvement: use getrandom(2) in lutil_entropy()
If `lutil_entropy()` tried `getrandom(2)` (Linux 3.17+, glibc 2.25+) first when
available, it would
not consume a file descriptor and this failure would practically no longer
occur. The randomness
comes from the same kernel CSPRNG as `/dev/urandom`.
Since `getrandom(2)` can fail as well, I think the `lutil_passwd_generate()`
fix above is needed
either way.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10650
Issue ID: 10650
Summary: A lot of tests return 0 on error
Product: OpenLDAP
Version: unspecified
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: test suite
Assignee: bugs(a)openldap.org
Reporter: ondra(a)mistotebe.net
Target Milestone: ---
Many tests contain this idiom (or, rarer, its `case $RC in` equivalent):
RC=$?
if $RC != number; then
...
exit $RC
fi
--
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=10653
Issue ID: 10653
Summary: MPR: writes made during a partition are discarded as
"not new enough" by the refresh after it heals
Product: OpenLDAP
Version: 2.6.16
Hardware: x86_64
OS: Linux
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: slapd
Assignee: bugs(a)openldap.org
Reporter: dns.spiros(a)gmail.com
Target Milestone: ---
Created attachment 1240
--> https://bugs.openldap.org/attachment.cgi?id=1240&action=edit
Attached is a patch, to be applied to the OpenLDAP repository using `git-am`,
which contains the reproducer. Details are provided in the comment.
Version: 2.6.10 (also reproduced with 2.6.16 and 2.7.2)
In a multi-provider setup, writes acknowledged by a provider while it is
partitioned from the others can be silently lost. When the partition
heals and the other providers refresh from it, the refresh first applies
a delete with the CSN of the latest delete; the adds and modifies that
follow in the same refresh carry older CSNs and are discarded as "not new
enough". Afterwards every provider reports the same contextCSN, so the
missing changes are never requested again.
Configuration:
- 3 providers, serverID 1, 2 and 3, each one replicating from the other two
- back-mdb, plain syncrepl (no accesslog/delta-syncrepl),
type=refreshAndPersist, retry="1 +", "multiprovider on"
- syncprov with "syncprov-sessionlog 2000000" and
"syncprov-checkpoint 1000 10"
- no other overlays
Steps:
1. Populate provider 1 and wait until the three databases are identical.
2. Isolate provider 1 from providers 2 and 3, closing the established
syncrepl connections and refusing new ones, so the consumers keep
retrying until the partition heals.
3. During the partition, add 20 entries on each side, one every 0.5s
(probe-A-1 .. probe-A-20 on provider 1, probe-B-1 .. probe-B-20 on
provider 2).
4. Still during the partition, on provider 1 delete cn=U1, add a member
to cn=G2, delete cn=G3 and rename cn=U4; on provider 2 modify some of
the same entries.
5. Add 5 more entries on each side (probe-A-21 .. 25, probe-B-21 .. 25).
6. Heal the partition and wait (120 seconds in my test).
Expected result:
Every write acknowledged on either side reaches all three providers.
Actual result (same on 2.6.10, 2.6.16 and 2.7.2):
- Providers 2 and 3 never receive probe-A-1 .. probe-A-20, i.e. all the
adds made on provider 1 before its first delete. probe-A-21 .. 25,
written after it, do arrive. Provider 1 has all the entries written on
provider 2.
- contextCSN is identical on all three providers, so nothing triggers a
further resync: 120 seconds later (and hours later, on the larger
cluster where I first saw it) the entries are still missing.
Log of provider 2 when its consumer of provider 1 (rid=001) reconnects:
do_syncrep1: rid=001 starting refresh (sending
cookie=rid=001,sid=002,csn=20261028085339.694898Z#000000#001#000000;20261028085354.537828Z#000000#002#000000)
do_syncrep2: rid=001 LDAP_RES_INTERMEDIATE - SYNC_ID_SET
do_syncrep2: rid=001
cookie=rid=001,sid=001,csn=20261028085339.694898Z#000000#001#000000;,delcsn=20261028085353.358697Z#000000#001#000000
syncrepl_del_nonpresent: rid=001 using
delcsn=20261028085353.358697Z#000000#001#000000
syncrepl_del_nonpresent: rid=001 be_delete cn=U1,ou=people,dc=example,dc=com
(0)
...
syncrepl_entry: rid=001 entry 'cn=probe-A-1,ou=people,dc=example,dc=com'
csn=20261028085342.792509Z#000000#001#000000 not new enough, ignored
...
syncrepl_entry: rid=001 entry 'cn=probe-A-20,ou=people,dc=example,dc=com'
csn=20261028085352.788966Z#000000#001#000000 not new enough, ignored
The cookie sent by provider 2 still has the pre-partition CSN for SID 1
(...085339...). The delete set arrives first and is applied with
delcsn=...085353.358697, the CSN of the delete of U1. From then on the
adds of the same refresh, whose CSNs are between the two (085342 ..
085352), are rejected by the check in syncrepl_entry() against
si_cookieState->cs_vals.
Notes:
- Possibly the same problem as ITS#10026 (Refresh handling can skip
entries), or another way to trigger it. The change "syncprov: assume
context is usually dirty" for ITS#10026, released in 2.6.14, does not
change this result: 2.6.16 and 2.7.2 behave like 2.6.10.
- If the partition holds the established connections instead of closing
them (as an iptables DROP does), no refresh happens and no write is
lost; that variant shows a different problem with concurrent delete and
modify, which I am reporting separately.
- I first saw this on a production-like cluster (3 providers and 1
read-only consumer, mTLS, SASL EXTERNAL, memberof and refint overlays),
where 20-22 writes made on one provider during a partition never
reached the other two; the setup above is the minimal one that still
reproduces it.
Attached is a patch, to be applied to the OpenLDAP repository using `git-am`,
which contains the reproducer. Details are provided in the comment.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10652
Issue ID: 10652
Summary: MPR: concurrent delete and modify of the same entry
leave providers permanently divergent
Product: OpenLDAP
Version: 2.6.16
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: slapd
Assignee: bugs(a)openldap.org
Reporter: dns.spiros(a)gmail.com
Target Milestone: ---
Created attachment 1239
--> https://bugs.openldap.org/attachment.cgi?id=1239&action=edit
Attached is a patch, to be applied to the OpenLDAP repository using `git-am`,
which contains the reproducer. Details are provided in the comment.
In a multi-provider setup, if one provider deletes an entry while another
provider modifies the same entry, the providers can end up in different
final states: on some of them the entry is gone, on others it exists. The
outcome depends only on the order in which each provider receives the two
changes, not on their CSNs. Afterwards every provider reports the same
contextCSN, so the difference is never resolved.
Configuration:
- 3 providers, serverID 1, 2 and 3, each one replicating from the other two
- back-mdb, plain syncrepl (no accesslog/delta-syncrepl),
type=refreshAndPersist, "multiprovider on"
- syncprov with "syncprov-sessionlog 2000000" and
"syncprov-checkpoint 1000 10"
- no other overlays
Steps:
1. Create cn=G3,ou=groups,dc=example,dc=com (groupOfNames, member U0) and
wait until it is identical on all three providers.
2. Isolate provider 1 from providers 2 and 3. The established syncrepl
connections stay open but no traffic passes (as with an iptables DROP
on established sessions), so no refresh happens when the partition
heals: the queued persist messages are just delivered.
3. On provider 1, delete G3 (entryCSN ...#001).
4. About one second later, on provider 2, modify G3 adding member U3
(entryCSN ...#002, newer than the delete).
5. Heal the partition and wait (120 seconds in my test).
Expected result:
The same outcome for G3 on all providers, whichever outcome the
replication model chooses.
Actual result (same on 2.6.10, 2.6.16 and 2.7.2):
- Provider 1, which has already deleted G3, receives the modify from
provider 2 and applies it as an add, so G3 is recreated with provider
2's entryCSN:
syncrepl_entry: rid=002 be_add cn=G3,ou=groups,dc=example,dc=com (0)
- Providers 2 and 3, which already have the modify, then receive the
delete from provider 1 and apply it, although its CSN is older than the
entryCSN of the entry being removed:
syncrepl_entry: rid=001 be_delete cn=G3,ou=groups,dc=example,dc=com (0)
Later copies of the same delete forwarded by the other provider are
dropped:
do_syncrep2: rid=003 CSN too old, ignoring
20261028084456.552508Z#000000#001#000000 (cn=G3,ou=groups,dc=example,dc=com)
- Final state: G3 exists on provider 1 and does not exist on providers 2
and 3. contextCSN is identical on all three, so nothing triggers a
further resync.
The two decisions that produce the divergence seem to be:
- a replicated delete is applied without comparing its CSN with the
entryCSN of the local entry;
- a replicated modify for an entry that no longer exists locally is
turned into an add, recreating the entry.
Notes:
- This is not ITS#9282 (deleted entry resurrected after one provider was
down): here both changes are made concurrently on running providers
and both are replicated.
- With the same test, if the partition closes the connections instead of
holding them (so the consumers refresh on reconnect), a different
problem appears: writes made on provider 1 during the partition are
never received by providers 2 and 3 ("not new enough, ignored" during
the refresh). I am reporting that separately, as it may be related to
ITS#10026.
- I first saw this on a production-like cluster (3 providers and 1
read-only consumer, mTLS, SASL EXTERNAL, memberof and refint overlays);
the setup above is the minimal one that still reproduces it.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10649
Issue ID: 10649
Summary: dap_do_free_request asserts lr->lr_refcnt == 1 after a
failed referral rebind frees the in-flight request
Product: OpenLDAP
Version: 2.5.16
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: libraries
Assignee: bugs(a)openldap.org
Reporter: subramam(a)netapp.com
Target Milestone: ---
libldap aborts in ldap_do_free_request (assert(lr->lr_refcnt == 1)) when a
referral rebind fails.
ldap_search_ext_s is chasing a referral. The rebind callback calls
ldap_start_tls_s on the same LDAP* and fails. ldap_new_connection then calls
ldap_free_connection(ld, lc, 1, 0), which frees every request in ld_requests,
including the search try_read1msg still holds. try_read1msg frees that request
again and hits the assert. The request memory is already freed (0x5a).
force == 1 should free only requests on the connection being closed, and
ldap_do_free_request should defer any positive lr_refcnt instead of requiring
it to be 1.
======================================
b) bt
#0 abort2 () at abort2.S:4
#1 0x000000080d26cb8e in __assert (func=<optimized out>, file=0x80c0763f5
"../../../../../../distro/libraries/libldap/request.c", line=979,
failedexpr=0x80c07b28b "lr->lr_refcnt == 1")
at ../../../../../../src/lib/libc/gen/assert.c:51
#2 0x000000080c0a85bc in ldap_do_free_request (arg=0x816b74180) at
../../../../../../distro/libraries/libldap/request.c:979
#3 0x000000080c0a9041 in ldap_free_request_int (ld=0x818377080,
lr=0x816b74180) at ../../../../../../distro/libraries/libldap/request.c:1022
#4 0x000000080c0aab41 in ldap_return_request (ld=0x818377080, lrx=0x816b74180,
freeit=0) at ../../../../../../distro/libraries/libldap/request.c:1726
#5 0x000000080c089db3 in try_read1msg (ld=0x818377080, msgid=6, all=1, lc=0x0,
result=0x814b4b150) at ../../../../../../distro/libraries/libldap/result.c:926
#6 0x000000080c088402 in wait4msg (ld=0x818377080, msgid=6, all=1,
timeout=0x814b4aae0, result=0x814b4b150) at
../../../../../../distro/libraries/libldap/result.c:369
#7 0x000000080c087dc2 in ldap_result (ld=0x818377080, msgid=6, all=1,
timeout=0x814b4aae0, result=0x814b4b150) at
../../../../../../distro/libraries/libldap/result.c:120
#8 0x000000080c08cd70 in ldap_pvt_search_s (ld=0x818377080, base=0x818484809
"DC=dc25home2,DC=com", scope=2, filter=0x8184847a0
"(&(objectClass=User)(uid=RefUser11))", attrs=0x814b4a730, attrsonly=0,
sctrls=0x0,
cctrls=0x0, timeout=0x814b4aae0, sizelimit=0, deref=-1, res=0x814b4b150) at
../../../../../../distro/libraries/libldap/search.c:185
#9 0x000000080c08cc33 in ldap_search_ext_s (ld=0x818377080, base=0x818484809
"DC=dc25home2,DC=com", scope=2, filter=0x8184847a0
"(&(objectClass=User)(uid=RefUser11))", attrs=0x814b4a730, attrsonly=0,
sctrls=0x0,
cctrls=0x0, timeout=0x814b4aae0, sizelimit=0, res=0x814b4b150) at
../../../../../../distro/libraries/libldap/search.c:150
==================================================
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10640
Issue ID: 10640
Summary: paged results requests with size 0 are undefined in
RFC2696
Product: OpenLDAP
Version: unspecified
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: ---
Apart from "abandoning" the paged result state (and even then, there's no
indication what the result should be), the behaviour for a cookie-less paged
search with size is completely unspecified. We should probably reject that on
parsing.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10648
Issue ID: 10648
Summary: More fixes to pcache
Product: OpenLDAP
Version: 2.6.15
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: overlays
Assignee: bugs(a)openldap.org
Reporter: aweits(a)rit.edu
Target Milestone: ---
Created attachment 1237
--> https://bugs.openldap.org/attachment.cgi?id=1237&action=edit
Fixes for pcache.c
Hello, I have some more fixes for the pcache overlay for issues we're seen.
These are based on 2.6.15.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10647
Issue ID: 10647
Summary: roundrobin_remove_backend does not clear "next
backend" indicator on removing last backend
Product: OpenLDAP
Version: unspecified
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: lloadd
Assignee: bugs(a)openldap.org
Reporter: ondra(a)mistotebe.net
Target Milestone: ---
tier->t_nbackends is decremented unconditionally *after* the removal, it should
decrement before and only if b was actually in the list.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10639
Issue ID: 10639
Summary: Change --enable-balancer to default to mod
Product: OpenLDAP
Version: unspecified
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: lloadd
Assignee: bugs(a)openldap.org
Reporter: ondra(a)mistotebe.net
Target Milestone: ---
Preferably in 2.7.x as well but that will need an admin guide entry.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10646
Quanah Gibson-Mount <quanah(a)openldap.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Group|OpenLDAP-devs |
Keywords|needs_review |
Status|RESOLVED |VERIFIED
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10618
Issue ID: 10618
Summary: [PATCH] improved docs for LDAP proxied authorization
Product: OpenLDAP
Version: unspecified
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: documentation
Assignee: bugs(a)openldap.org
Reporter: equinox-openldap(a)diac24.net
Target Milestone: ---
Spent more time getting PAC to work than should've been necessary, so here's 2
small documentation patches (against git master, ba00b19c2ae4) to remove
stumbling blocks.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10643
Issue ID: 10643
Summary: DUPSORT page counts remain inflated after deleting a
duplicate tree
Product: LMDB
Version: unspecified
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: liblmdb
Assignee: bugs(a)openldap.org
Reporter: ledvinap(a)gmail.com
Target Milestone: ---
b048b7e (ITS#9388) updates the parent’s page counts only when the duplicate
child tree still contains entries. Whole-set deletion and deletion of the last
value skip adjustment.
Fix: subtract counts still in NODEDATA(leaf) after successful mdb_drop0().
AI discovery/fix; This report is fully authored by me.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10615
Issue ID: 10615
Summary: Stale reads with nested LMDB transactions on OpenBSD
Product: LMDB
Version: unspecified
Hardware: Other
OS: Other
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: liblmdb
Assignee: bugs(a)openldap.org
Reporter: wiesche89(a)googlemail.com
Target Milestone: ---
On OpenBSD 7.9, LMDB reads can return stale data after writes through the file
descriptor when using nested transactions
Reproduced with heed 0.22.1 and lmdb-master-sys 0.2.6
Adding msync(..., MS_INVALIDATE) after data and metadata writes fixes it in my
tests
MDB_WRITEMAP also avoids it, but does not support nested write transactions
Proposed fix:
https://github.com/meilisearch/lmdb/pull/5
Backport:
https://github.com/wiesche89/lmdb/commit/52b4d64d5ab39952a4105151fd3b454019…
Reported here:
https://github.com/meilisearch/heed/issues/383
--
You are receiving this mail because:
You are on the CC list for the issue.