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:
- 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
- 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;
}
- Launch the example
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);
}
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 causesDNSEPARATORbranch to execute, after++s;the pointer is at '\0',if (*s) {does not work, and after the nexts++*scauses OOB read.389-ds-base/ldap/servers/slapd/dn.c
Lines 1616 to 1622 in cfa1a0c
Steps to reproduce:
parent_ex.c:
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==ABORTINGSuggested fixes:
A simplistic check, which prevents the next iteration from occurring, when that results in a crash.