From 40e752922e6160356399cd07169ec1f76dd7db99 Mon Sep 17 00:00:00 2001 From: Pierre Rogier Date: Thu, 27 Feb 2025 16:36:48 +0100 Subject: [PATCH] Security fix for CVE-2025-2487 Description: A denial of service vulnerability was found in the 389 Directory Server. The 389 Directory Server may crash (Null Pointer Exception) after some failed rename subtree operations (i.e. MODDN) issued by a user having enough privileges to do so. References: - https://access.redhat.com/security/cve/CVE-2025-2487 - https://bugzilla.redhat.com/show_bug.cgi?id=2353071 --- ldap/servers/slapd/back-ldbm/findentry.c | 36 +++++++++++++++++----- ldap/servers/slapd/back-ldbm/ldbm_add.c | 2 ++ ldap/servers/slapd/back-ldbm/ldbm_modify.c | 6 ++++ ldap/servers/slapd/back-ldbm/ldbm_modrdn.c | 13 ++++++-- 4 files changed, 48 insertions(+), 9 deletions(-) diff --git a/ldap/servers/slapd/back-ldbm/findentry.c b/ldap/servers/slapd/back-ldbm/findentry.c index 7bb56ef2c4..907b4367a1 100644 --- a/ldap/servers/slapd/back-ldbm/findentry.c +++ b/ldap/servers/slapd/back-ldbm/findentry.c @@ -99,6 +99,7 @@ find_entry_internal_dn( int isroot = 0; int op_type; int reverted_entry = 0; + int return_err = LDAP_SUCCESS; /* get the managedsait ldap message control */ slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait); @@ -121,6 +122,7 @@ find_entry_internal_dn( if (rc) { /* if check_entry_for_referral returns non-zero, result is sent. */ *rc = FE_RC_SENT_RESULT; } + slapi_set_ldap_result(pb, LDAP_REFERRAL, NULL, NULL, 0, NULL); return (NULL); } } @@ -153,7 +155,12 @@ find_entry_internal_dn( slapi_log_err(SLAPI_LOG_ERR, "find_entry_internal_dn", "Retry count exceeded (%s)\n", slapi_sdn_get_dn(sdn)); } if (reverted_entry) { + CACHE_RETURN(&inst->inst_cache, &e); + slapi_set_ldap_result(pb, LDAP_BUSY, NULL, NULL, 0, NULL); slapi_send_ldap_result(pb, LDAP_BUSY, NULL, "target entry busy because of a canceled operation", 0, NULL); + if (rc) { + *rc = FE_RC_SENT_RESULT; /* Result is sent */ + } return (NULL); } /* @@ -179,6 +186,7 @@ find_entry_internal_dn( if (rc) { /* if check_entry_for_referral returns non-zero, result is sent. */ *rc = FE_RC_SENT_RESULT; } + slapi_set_ldap_result(pb, LDAP_REFERRAL, NULL, NULL, 0, NULL); return (NULL); } /* else fall through to no such object */ @@ -189,7 +197,7 @@ find_entry_internal_dn( if (me && !isroot) { /* If not root, you may not want to reveal it. */ int acl_type = -1; - int return_err = LDAP_NO_SUCH_OBJECT; + return_err = LDAP_NO_SUCH_OBJECT; err = LDAP_SUCCESS; switch (op_type) { case SLAPI_OPERATION_ADD: @@ -230,18 +238,22 @@ find_entry_internal_dn( * do not return the "matched" DN. * Plus, the bind case returns LDAP_INAPPROPRIATE_AUTH. */ + slapi_set_ldap_result(pb, return_err, NULL, NULL, 0, NULL); slapi_send_ldap_result(pb, return_err, NULL, NULL, 0, NULL); } else { + slapi_set_ldap_result(pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL); slapi_send_ldap_result(pb, LDAP_NO_SUCH_OBJECT, (char *)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL); } } else { + slapi_set_ldap_result(pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL); slapi_send_ldap_result(pb, LDAP_NO_SUCH_OBJECT, (char *)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL); } } else { - slapi_send_ldap_result(pb, (LDAP_INVALID_DN_SYNTAX == err) ? LDAP_INVALID_DN_SYNTAX : LDAP_OPERATIONS_ERROR, - (char *)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL); + return_err = (LDAP_INVALID_DN_SYNTAX == err) ? LDAP_INVALID_DN_SYNTAX : LDAP_OPERATIONS_ERROR; + slapi_set_ldap_result(pb, return_err, NULL, NULL, 0, NULL); + slapi_send_ldap_result(pb, return_err, (char *)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL); } if (rc) { *rc = FE_RC_SENT_RESULT; @@ -265,13 +277,15 @@ find_entry_internal_uniqueid( backend *be, const char *uniqueid, int lock, - back_txn *txn) + back_txn *txn, + int *rc) { ldbm_instance *inst = (ldbm_instance *)be->be_instance_info; struct backentry *e; int err; size_t tries = 0; int reverted_entry = 0; + int return_err = 0; while ((tries < LDBM_CACHE_RETRY_COUNT) && (e = uniqueid2entry(be, uniqueid, txn, &err)) != NULL) { @@ -307,12 +321,20 @@ find_entry_internal_uniqueid( } if (reverted_entry) { + slapi_set_ldap_result(pb, LDAP_BUSY, NULL, NULL, 0, NULL); slapi_send_ldap_result(pb, LDAP_BUSY, NULL, "target entry busy because of a canceled operation", 0, NULL); + if (rc) { + *rc = FE_RC_SENT_RESULT; /* Result is sent */ + } return (NULL); } else { /* entry not found */ - slapi_send_ldap_result(pb, (0 == err || DBI_RC_NOTFOUND == err) ? LDAP_NO_SUCH_OBJECT : LDAP_OPERATIONS_ERROR, NULL /* matched */, NULL, - 0, NULL); + return_err = (0 == err || DBI_RC_NOTFOUND == err) ? LDAP_NO_SUCH_OBJECT : LDAP_OPERATIONS_ERROR; + slapi_set_ldap_result(pb, return_err, NULL, NULL, 0, NULL); + slapi_send_ldap_result(pb, return_err, NULL /* matched */, NULL, 0, NULL); + if (rc) { + *rc = FE_RC_SENT_RESULT; /* Result is sent */ + } } slapi_log_err(SLAPI_LOG_TRACE, "find_entry_internal_uniqueid", "<= not found; uniqueid = (%s)\n", @@ -334,7 +356,7 @@ find_entry_internal( if (addr->uniqueid != NULL) { slapi_log_err(SLAPI_LOG_TRACE, "find_entry_internal", "=> (uniqueid=%s) lock %d\n", addr->uniqueid, lock); - return (find_entry_internal_uniqueid(pb, be, addr->uniqueid, lock, txn)); + return (find_entry_internal_uniqueid(pb, be, addr->uniqueid, lock, txn, rc)); } else { struct backentry *entry = NULL; diff --git a/ldap/servers/slapd/back-ldbm/ldbm_add.c b/ldap/servers/slapd/back-ldbm/ldbm_add.c index 067e19f0c6..39f49f8230 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_add.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_add.c @@ -435,6 +435,8 @@ ldbm_back_add(Slapi_PBlock *pb) slapi_log_err(SLAPI_LOG_BACKLDBM, "ldbm_back_add", "find_entry2modify_only returned NULL parententry pdn: %s, uniqueid: %s\n", slapi_sdn_get_dn(&parentsdn), addr.uniqueid ? addr.uniqueid : "none"); + slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code); + goto error_return; } modify_init(&parent_modify_c, parententry); } diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c index 29df2ce75d..24c62a9524 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c @@ -177,6 +177,12 @@ modify_update_all(backend *be, Slapi_PBlock *pb, modify_context *mc, back_txn *t slapi_pblock_get(pb, SLAPI_OPERATION, &operation); is_ruv = operation_is_flag_set(operation, OP_FLAG_REPL_RUV); } + if (NULL == mc->new_entry) { + /* test entry to avoid crashing in id2entry_add_ext */ + slapi_log_err(SLAPI_LOG_BACKLDBM, "modify_update_all", + "No entry in modify_context ==> operation is aborted.\n"); + return -1; + } /* * Update the ID to Entry index. * Note that id2entry_add replaces the entry, so the Entry ID stays the same. diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c index a024ca02ef..32542e110c 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c @@ -485,8 +485,8 @@ ldbm_back_modrdn(Slapi_PBlock *pb) slapi_pblock_get(pb, SLAPI_TARGET_ADDRESS, &old_addr); e = find_entry2modify(pb, be, old_addr, &txn, &result_sent); if (e == NULL) { - ldap_result_code = -1; - goto error_return; /* error result sent by find_entry2modify() */ + slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code); + goto error_return; /* error result set and sent by find_entry2modify() */ } if (slapi_entry_flag_is_set(e->ep_entry, SLAPI_ENTRY_FLAG_TOMBSTONE) && !is_resurect_operation) { @@ -518,6 +518,11 @@ ldbm_back_modrdn(Slapi_PBlock *pb) oldparent_addr.uniqueid = NULL; } parententry = find_entry2modify_only(pb, be, &oldparent_addr, &txn, &result_sent); + if (parententry == NULL) { + slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code); + goto error_return; /* error result set and sent by find_entry2modify() */ + } + modify_init(&parent_modify_context, parententry); /* Fetch and lock the new parent of the entry that is moving */ @@ -528,6 +533,10 @@ ldbm_back_modrdn(Slapi_PBlock *pb) } newparententry = find_entry2modify_only(pb, be, newsuperior_addr, &txn, &result_sent); slapi_ch_free_string(&newsuperior_addr->uniqueid); + if (newparententry == NULL) { + slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code); + goto error_return; /* error result set and sent by find_entry2modify() */ + } modify_init(&newparent_modify_context, newparententry); }