Skip to content

Buffer overflow in slapi_dn_find_parent_ext() #7543

Description

@IliaKash1

Hello maintainers! I have stumbled upon a global* buffer overflow in slapi_dn_find_parent_ext(). (Technically a heap buffer overflow, if triggered not by the attached example, but rather in the real-world input path.)

Something similar was mentioned before (#2531), but the error at hand still triggers at the freshest commit.

The error itself is caused by passing a string which ends after a separator to slapi_dn_find_parent_ext() (f.e. ';'). This causes DNSEPARATOR branch to execute, after ++s; the pointer is at '\0', if (*s) { does not work, and after the next s++ *s causes OOB read.

if (DNSEPARATOR(*s)) {
while (*s && DNSEPARATOR(*s)) {
++s;
}
if (*s) {
return (s);
}

Steps to reproduce:

  1. Build the project with ASAN;
export CC=clang-19
export CXX=clang++-19

autoreconf --force --install
export RUSTUP_TOOLCHAIN=stable
./configure --build=x86_64-linux-gnu --prefix=/usr --includedir=\${prefix}/include --mandir=\${prefix}/share/man --infodir=\${prefix}/share/info --sysconfdir=/etc --localstatedir=/var --disable-option-checking --disable-silent-rules --libdir=\${prefix}/lib/x86_64-linux-gnu --runstatedir=/run --disable-maintainer-mode --disable-dependency-tracking --with-openldap --with-systemd --with-systemdsystemunitdir=/lib/systemd/system --with-systemdsystemconfdir=/etc/systemd/system --with-systemdgroupname=dirsrv.target --with-tmpfiles-d=/etc/tmpfiles.d --enable-autobind --enable-cmocka --enable-icu --enable-rust --enable-asan

make

ar rsc liball.a ldap/servers/slapd/.libs/*.o
ar rsc libsvrscore.a src/svrcore/src/.libs/*.o
  1. Build the example:
clang-19 -fsanitize=address -g -O0 -I./ldap/include -I./ldap/servers/slapd $(pkg-config --cflags nspr nss openssl libsasl2) ./parent_ex.c liball.a libavl.a libsvrscore.a ./.libs/librslapd.a ./rs/rslapd/release/librslapd.a -lldap -llber -lpcre2-8 -lz $(pkg-config  --libs nspr nss openssl libsasl2) -lcrack -lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err -ldl -ljson-c -Wl,--allow-multiple-definition -o parent_ex

parent_ex.c:

#include <slap.h>
#include <slapi-plugin.h>
#include <proto-slap.h>

int main(int argc, char** argv)
{
    slapi_dn_find_parent_ext(";", 1);
    return 0;
}
  1. Launch the example
./parent_ex

Sanitizer output:

==658877==ERROR: AddressSanitizer: global-buffer-overflow on address 0x5fc904976d02 at pc 0x5fc9046c4640 bp 0x7ffefe2c4bb0 sp 0x7ffefe2c4ba8
READ of size 1 at 0x5fc904976d02 thread T0
    #0 0x5fc9046c463f in slapi_dn_find_parent_ext /orig/for_rep/389-ds-base/ldap/servers/slapd/dn.c:1603:20
    #1 0x5fc9046bce56 in main /orig/for_rep/389-ds-base/./parent_ex.c:7:5
    #2 0x754522a68249 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #3 0x754522a68304 in __libc_start_main csu/../csu/libc-start.c:360:3
    #4 0x5fc9045dd710 in _start (/orig/for_rep/389-ds-base/parent_ex+0xef710) (BuildId: e9e6ab94c6b4eb913c794bcde4b7e0bf7598ed20)

0x5fc904976d02 is located 0 bytes after global variable '.str' defined in '/orig/for_rep/389-ds-base/./parent_ex.c:7' (0x5fc904976d00) of size 2
  '.str' is ascii string ';'
SUMMARY: AddressSanitizer: global-buffer-overflow /orig/for_rep/389-ds-base/ldap/servers/slapd/dn.c:1603:20 in slapi_dn_find_parent_ext
Shadow bytes around the buggy address:
  0x5fc904976a80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x5fc904976b00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x5fc904976b80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x5fc904976c00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x5fc904976c80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x5fc904976d00:[02]f9 f9 f9 00 00 00 00 00 00 00 00 00 00 00 00
  0x5fc904976d80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x5fc904976e00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x5fc904976e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x5fc904976f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x5fc904976f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==658877==ABORTING

Suggested fixes:
A simplistic check, which prevents the next iteration from occurring, when that results in a crash.

diff --git a/ldap/servers/slapd/dn.c b/ldap/servers/slapd/dn.c
index 74d29d170..c1f577f3c 100644
--- a/ldap/servers/slapd/dn.c
+++ b/ldap/servers/slapd/dn.c
@@ -1617,6 +1617,9 @@ slapi_dn_find_parent_ext(const char *dn, int is_tombstone)
                     while (*s && DNSEPARATOR(*s)) {
                         ++s;
                     }
+                   if (!*s) {
+                       return (NULL);
+                   }
                     if (*s) {
                         return (s);
                     }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions