From 5cfa136c48c477765cb20b007ad441ed21534e86 Mon Sep 17 00:00:00 2001 From: Pierre Rogier Date: Wed, 17 Apr 2024 18:18:04 +0200 Subject: [PATCH] CVE-2024-3657 --- .../tests/suites/filter/large_filter_test.py | 34 +++++- ldap/servers/slapd/back-ldbm/index.c | 111 ++++++++++-------- 2 files changed, 92 insertions(+), 53 deletions(-) diff --git a/dirsrvtests/tests/suites/filter/large_filter_test.py b/dirsrvtests/tests/suites/filter/large_filter_test.py index 964facae5..5390a0f9c 100644 --- a/dirsrvtests/tests/suites/filter/large_filter_test.py +++ b/dirsrvtests/tests/suites/filter/large_filter_test.py @@ -13,19 +13,29 @@ verify and testing Filter from a search import os import pytest +import ldap -from lib389._constants import PW_DM +from lib389._constants import PW_DM, DEFAULT_SUFFIX, ErrorLog from lib389.topologies import topology_st as topo from lib389.idm.user import UserAccounts, UserAccount from lib389.idm.account import Accounts from lib389.backend import Backends from lib389.idm.domain import Domain +from lib389.utils import get_ldapurl_from_serverid SUFFIX = 'dc=anuj,dc=com' pytestmark = pytest.mark.tier1 +def open_new_ldapi_conn(dsinstance): + ldapurl, certdir = get_ldapurl_from_serverid(dsinstance) + assert 'ldapi://' in ldapurl + conn = ldap.initialize(ldapurl) + conn.sasl_interactive_bind_s("", ldap.sasl.external()) + return conn + + @pytest.fixture(scope="module") def _create_entries(request, topo): """ @@ -159,6 +169,28 @@ def test_large_filter(topo, _create_entries, real_value): assert len(Accounts(conn, SUFFIX).filter(real_value)) == 3 +def test_long_filter_value(topo): + """Exercise large eq filter with dn syntax attributes + + :id: b069ef72-fcc3-11ee-981c-482ae39447e5 + :setup: Standalone + :steps: + 1. Try to pass filter rules as per the condition. + :expectedresults: + 1. Pass + """ + inst = topo.standalone + conn = open_new_ldapi_conn(inst.serverid) + inst.config.loglevel(vals=(ErrorLog.DEFAULT,ErrorLog.TRACE,ErrorLog.SEARCH_FILTER)) + filter_value = "a\x1Edmin" * 1025 + conn.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, f'(cn={filter_value})') + filter_value = "aAdmin" * 1025 + conn.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, f'(cn={filter_value})') + filter_value = "*" + conn.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, f'(cn={filter_value})') + inst.config.loglevel(vals=(ErrorLog.DEFAULT,)) + + if __name__ == '__main__': CURRENT_FILE = os.path.realpath(__file__) pytest.main("-s -v %s" % CURRENT_FILE) diff --git a/ldap/servers/slapd/back-ldbm/index.c b/ldap/servers/slapd/back-ldbm/index.c index 86bc825fe..bdac0a616 100644 --- a/ldap/servers/slapd/back-ldbm/index.c +++ b/ldap/servers/slapd/back-ldbm/index.c @@ -74,6 +74,32 @@ typedef struct _index_buffer_handle index_buffer_handle; #define INDEX_BUFFER_FLAG_SERIALIZE 1 #define INDEX_BUFFER_FLAG_STATS 2 +/* + * space needed to encode a byte: + * 0x00-0x31 and 0x7f-0xff requires 3 bytes: \xx + * 0x22 and 0x5C requires 2 bytes: \" and \\ + * other requires 1 byte: c + */ +static char encode_size[] = { + /* 0x00 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + /* 0x10 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + /* 0x20 */ 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 0x30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 0x40 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 0x50 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, + /* 0x60 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 0x70 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, + /* 0x80 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + /* 0x90 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + /* 0xA0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + /* 0xB0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + /* 0xC0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + /* 0xD0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + /* 0xE0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + /* 0xF0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +}; + + /* Index buffering functions */ static int @@ -802,65 +828,46 @@ index_add_mods( /* * Convert a 'struct berval' into a displayable ASCII string + * returns the printable string */ - -#define SPECIAL(c) (c < 32 || c > 126 || c == '\\' || c == '"') - const char * encode(const struct berval *data, char buf[BUFSIZ]) { - char *s; - char *last; - if (data == NULL || data->bv_len == 0) - return ""; - last = data->bv_val + data->bv_len - 1; - for (s = data->bv_val; s < last; ++s) { - if (SPECIAL(*s)) { - char *first = data->bv_val; - char *bufNext = buf; - size_t bufSpace = BUFSIZ - 4; - while (1) { - /* printf ("%lu bytes ASCII\n", (unsigned long)(s - first)); */ - if (bufSpace < (size_t)(s - first)) - s = first + bufSpace - 1; - if (s != first) { - memcpy(bufNext, first, s - first); - bufNext += (s - first); - bufSpace -= (s - first); - } - do { - if (bufSpace) { - *bufNext++ = '\\'; - --bufSpace; - } - if (bufSpace < 2) { - memcpy(bufNext, "..", 2); - bufNext += 2; - goto bail; - } - if (*s == '\\' || *s == '"') { - *bufNext++ = *s; - --bufSpace; - } else { - sprintf(bufNext, "%02x", (unsigned)*(unsigned char *)s); - bufNext += 2; - bufSpace -= 2; - } - } while (++s <= last && SPECIAL(*s)); - if (s > last) - break; - first = s; - while (!SPECIAL(*s) && s <= last) - ++s; - } - bail: - *bufNext = '\0'; - /* printf ("%lu chars in buffer\n", (unsigned long)(bufNext - buf)); */ + if (!data || !data->bv_val) { + strcpy(buf, ""); + return buf; + } + char *endbuff = &buf[BUFSIZ-4]; /* Reserve space to append "...\0" */ + char *ptout = buf; + unsigned char *ptin = (unsigned char*) data->bv_val; + unsigned char *endptin = ptin+data->bv_len; + + while (ptin < endptin) { + if (ptout >= endbuff) { + /* + * BUFSIZ(8K) > SLAPI_LOG_BUFSIZ(2K) so the error log message will be + * truncated anyway. So there is no real interrest to test if the original + * data contains no special characters and return it as is. + */ + strcpy(endbuff, "..."); return buf; } + switch (encode_size[*ptin]) { + case 1: + *ptout++ = *ptin++; + break; + case 2: + *ptout++ = '\\'; + *ptout++ = *ptin++; + break; + case 3: + sprintf(ptout, "\\%02x", *ptin++); + ptout += 3; + break; + } } - /* printf ("%lu bytes, all ASCII\n", (unsigned long)(s - data->bv_val)); */ - return data->bv_val; + *ptout = 0; + return buf; } static const char * -- 2.44.0