diff --git a/0006-CVE-2024-2199.patch b/0006-CVE-2024-2199.patch new file mode 100644 index 0000000..d980f8c --- /dev/null +++ b/0006-CVE-2024-2199.patch @@ -0,0 +1,108 @@ +From 23956cfb86a312318667fb9376322574fa8ec7f4 Mon Sep 17 00:00:00 2001 +From: James Chapman +Date: Wed, 1 May 2024 15:01:33 +0100 +Subject: [PATCH] CVE-2024-2199 + +--- + .../tests/suites/password/password_test.py | 56 +++++++++++++++++++ + ldap/servers/slapd/modify.c | 8 ++- + 2 files changed, 62 insertions(+), 2 deletions(-) + +diff --git a/dirsrvtests/tests/suites/password/password_test.py b/dirsrvtests/tests/suites/password/password_test.py +index 1245feb31..e4abd9907 100644 +--- a/dirsrvtests/tests/suites/password/password_test.py ++++ b/dirsrvtests/tests/suites/password/password_test.py +@@ -63,6 +63,62 @@ def test_password_delete_specific_password(topology_st): + log.info('test_password_delete_specific_password: PASSED') + + ++def test_password_modify_non_utf8(topology_st): ++ """Attempt a modify of the userPassword attribute with ++ an invalid non utf8 value ++ ++ :id: a31af9d5-d665-42b9-8d6e-fea3d0837d36 ++ :setup: Standalone instance ++ :steps: ++ 1. Add a user if it doesnt exist and set its password ++ 2. Verify password with a bind ++ 3. Modify userPassword attr with invalid value ++ 4. Attempt a bind with invalid password value ++ 5. Verify original password with a bind ++ :expectedresults: ++ 1. The user with userPassword should be added successfully ++ 2. Operation should be successful ++ 3. Server returns ldap.UNWILLING_TO_PERFORM ++ 4. Server returns ldap.INVALID_CREDENTIALS ++ 5. Operation should be successful ++ """ ++ ++ log.info('Running test_password_modify_non_utf8...') ++ ++ # Create user and set password ++ standalone = topology_st.standalone ++ users = UserAccounts(standalone, DEFAULT_SUFFIX) ++ if not users.exists(TEST_USER_PROPERTIES['uid'][0]): ++ user = users.create(properties=TEST_USER_PROPERTIES) ++ else: ++ user = users.get(TEST_USER_PROPERTIES['uid'][0]) ++ user.set('userpassword', PASSWORD) ++ ++ # Verify password ++ try: ++ user.bind(PASSWORD) ++ except ldap.LDAPError as e: ++ log.fatal('Failed to bind as {}, error: '.format(user.dn) + e.args[0]['desc']) ++ assert False ++ ++ # Modify userPassword with an invalid value ++ password = b'tes\x82t-password' # A non UTF-8 encoded password ++ with pytest.raises(ldap.UNWILLING_TO_PERFORM): ++ user.replace('userpassword', password) ++ ++ # Verify a bind fails with invalid pasword ++ with pytest.raises(ldap.INVALID_CREDENTIALS): ++ user.bind(password) ++ ++ # Verify we can still bind with original password ++ try: ++ user.bind(PASSWORD) ++ except ldap.LDAPError as e: ++ log.fatal('Failed to bind as {}, error: '.format(user.dn) + e.args[0]['desc']) ++ assert False ++ ++ log.info('test_password_modify_non_utf8: PASSED') ++ + if __name__ == '__main__': + # Run isolated + # -s for DEBUG mode +diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c +index a20984e0b..fb65d58b3 100644 +--- a/ldap/servers/slapd/modify.c ++++ b/ldap/servers/slapd/modify.c +@@ -762,8 +762,10 @@ op_shared_modify(Slapi_PBlock *pb, int pw_change, char *old_pw) + * flagged - leave mod attributes alone */ + if (!repl_op && !skip_modified_attrs && lastmod) { + modify_update_last_modified_attr(pb, &smods); ++ slapi_pblock_set(pb, SLAPI_MODIFY_MODS, slapi_mods_get_ldapmods_byref(&smods)); + } + ++ + if (0 == slapi_mods_get_num_mods(&smods)) { + /* nothing to do - no mods - this is not an error - just + send back LDAP_SUCCESS */ +@@ -930,8 +932,10 @@ op_shared_modify(Slapi_PBlock *pb, int pw_change, char *old_pw) + + /* encode password */ + if (pw_encodevals_ext(pb, sdn, va)) { +- slapi_log_err(SLAPI_LOG_CRIT, "op_shared_modify", "Unable to hash userPassword attribute for %s.\n", slapi_entry_get_dn_const(e)); +- send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "Unable to store attribute \"userPassword\" correctly\n", 0, NULL); ++ slapi_log_err(SLAPI_LOG_CRIT, "op_shared_modify", "Unable to hash userPassword attribute for %s, " ++ "check value is utf8 string.\n", slapi_entry_get_dn_const(e)); ++ send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "Unable to hash \"userPassword\" attribute, " ++ "check value is utf8 string.\n", 0, NULL); + valuearray_free(&va); + goto free_and_return; + } +-- +2.41.0 + diff --git a/0007-CVE-2024-3657.patch b/0007-CVE-2024-3657.patch new file mode 100644 index 0000000..dba55ff --- /dev/null +++ b/0007-CVE-2024-3657.patch @@ -0,0 +1,213 @@ +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 + diff --git a/389-ds-base.spec b/389-ds-base.spec index 903fcf4..bc5e6e5 100644 --- a/389-ds-base.spec +++ b/389-ds-base.spec @@ -48,7 +48,7 @@ ExcludeArch: i686 Summary: 389 Directory Server (base) Name: 389-ds-base Version: 1.4.3.39 -Release: %{?relprefix}3%{?prerel}%{?dist} +Release: %{?relprefix}4%{?prerel}%{?dist} License: GPLv3+ and (ASL 2.0 or MIT) URL: https://www.port389.org Group: System Environment/Daemons @@ -298,6 +298,8 @@ Patch02: 0002-Issue-5647-Fix-unused-variable-warning-from-previous.patc Patch03: 0003-Issue-5407-sync_repl-crashes-if-enabled-while-dynami.patch Patch04: 0004-Issue-5547-automember-plugin-improvements.patch Patch05: 0001-Issue-3527-Support-HAProxy-and-Instance-on-the-same-.patch +Patch06: 0006-CVE-2024-2199.patch +Patch07: 0007-CVE-2024-3657.patch %description 389 Directory Server is an LDAPv3 compliant server. The base package includes @@ -919,6 +921,11 @@ exit 0 %doc README.md %changelog +* Thu Jun 06 2024 James Chapman - 1.4.3.39-4 +- Bump version to 1.4.3.39-4 +- Resolves: RHEL-34818 - redhat-ds:11/389-ds-base: Malformed userPassword may cause crash at do_modify in slapd/modify.c +- Resolves: RHEL-34824 - redhat-ds:11/389-ds-base: potential denial of service via specially crafted kerberos AS-REQ request + * Thu Mar 14 2024 Simon Pichugin - 1.4.3.39-3 - Bump version to 1.4.3.39-3 - Resolves: RHEL-19240 - RFE Add PROXY protocol support to 389-ds-base via confiuration item - similar to Postfix