|
|
b2bc38 |
From d000349089eb15b3476ec302f4279f118336290e Mon Sep 17 00:00:00 2001
|
|
|
b03d2c |
From: Mark Reynolds <mreynolds@redhat.com>
|
|
|
b03d2c |
Date: Thu, 16 Dec 2021 16:13:08 -0500
|
|
|
b2bc38 |
Subject: [PATCH 1/2] CVE-2021-4091 (BZ#2030367) double-free of the virtual
|
|
|
b03d2c |
attribute context in persistent search
|
|
|
b03d2c |
|
|
|
b03d2c |
description:
|
|
|
b03d2c |
A search is processed by a worker using a private pblock.
|
|
|
b03d2c |
If the search is persistent, the worker spawn a thread
|
|
|
b03d2c |
and kind of duplicate its private pblock so that the spawn
|
|
|
b03d2c |
thread continue to process the persistent search.
|
|
|
b03d2c |
Then worker ends the initial search, reinit (free) its private pblock,
|
|
|
b03d2c |
and returns monitoring the wait_queue.
|
|
|
b03d2c |
When the persistent search completes, it frees the duplicated
|
|
|
b03d2c |
pblock.
|
|
|
b03d2c |
The problem is that private pblock and duplicated pblock
|
|
|
b03d2c |
are referring to a same structure (pb_vattr_context).
|
|
|
b03d2c |
That lead to a double free
|
|
|
b03d2c |
|
|
|
b03d2c |
Fix:
|
|
|
b03d2c |
When cloning the pblock (slapi_pblock_clone) make sure
|
|
|
b03d2c |
to transfert the references inside the original (private)
|
|
|
b03d2c |
pblock to the target (cloned) one
|
|
|
b03d2c |
That includes pb_vattr_context pointer.
|
|
|
b03d2c |
|
|
|
b03d2c |
Reviewed by: Mark Reynolds, James Chapman, Pierre Rogier (Thanks !)
|
|
|
b03d2c |
---
|
|
|
b03d2c |
ldap/servers/slapd/connection.c | 8 +++++---
|
|
|
b03d2c |
ldap/servers/slapd/pblock.c | 14 ++++++++++++--
|
|
|
b03d2c |
2 files changed, 17 insertions(+), 5 deletions(-)
|
|
|
b03d2c |
|
|
|
b03d2c |
diff --git a/ldap/servers/slapd/connection.c b/ldap/servers/slapd/connection.c
|
|
|
b03d2c |
index e0c1a52d2..fc7ed9c4a 100644
|
|
|
b03d2c |
--- a/ldap/servers/slapd/connection.c
|
|
|
b03d2c |
+++ b/ldap/servers/slapd/connection.c
|
|
|
b03d2c |
@@ -1823,9 +1823,11 @@ connection_threadmain()
|
|
|
b03d2c |
pthread_mutex_unlock(&(conn->c_mutex));
|
|
|
b03d2c |
}
|
|
|
b03d2c |
/* ps_add makes a shallow copy of the pb - so we
|
|
|
b03d2c |
- * can't free it or init it here - just set operation to NULL.
|
|
|
b03d2c |
- * ps_send_results will call connection_remove_operation_ext to free it
|
|
|
b03d2c |
- */
|
|
|
b03d2c |
+ * can't free it or init it here - just set operation to NULL.
|
|
|
b03d2c |
+ * ps_send_results will call connection_remove_operation_ext to free it
|
|
|
b03d2c |
+ * The connection_thread private pblock ('pb') has be cloned and should only
|
|
|
b03d2c |
+ * be reinit (slapi_pblock_init)
|
|
|
b03d2c |
+ */
|
|
|
b03d2c |
slapi_pblock_set(pb, SLAPI_OPERATION, NULL);
|
|
|
b03d2c |
slapi_pblock_init(pb);
|
|
|
b03d2c |
} else {
|
|
|
b03d2c |
diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c
|
|
|
b03d2c |
index a64986aeb..c78d1250f 100644
|
|
|
b03d2c |
--- a/ldap/servers/slapd/pblock.c
|
|
|
b03d2c |
+++ b/ldap/servers/slapd/pblock.c
|
|
|
b03d2c |
@@ -292,6 +292,12 @@ _pblock_assert_pb_deprecated(Slapi_PBlock *pblock)
|
|
|
b03d2c |
}
|
|
|
b03d2c |
}
|
|
|
b03d2c |
|
|
|
b03d2c |
+/* It clones the pblock
|
|
|
b03d2c |
+ * the content of the source pblock is transfered
|
|
|
b03d2c |
+ * to the target pblock (returned)
|
|
|
b03d2c |
+ * The source pblock should not be used for any operation
|
|
|
b03d2c |
+ * it needs to be reinit (slapi_pblock_init)
|
|
|
b03d2c |
+ */
|
|
|
b03d2c |
Slapi_PBlock *
|
|
|
b03d2c |
slapi_pblock_clone(Slapi_PBlock *pb)
|
|
|
b03d2c |
{
|
|
|
b03d2c |
@@ -312,28 +318,32 @@ slapi_pblock_clone(Slapi_PBlock *pb)
|
|
|
b03d2c |
if (pb->pb_task != NULL) {
|
|
|
b03d2c |
_pblock_assert_pb_task(new_pb);
|
|
|
b03d2c |
*(new_pb->pb_task) = *(pb->pb_task);
|
|
|
b03d2c |
+ memset(pb->pb_task, 0, sizeof(slapi_pblock_task));
|
|
|
b03d2c |
}
|
|
|
b03d2c |
if (pb->pb_mr != NULL) {
|
|
|
b03d2c |
_pblock_assert_pb_mr(new_pb);
|
|
|
b03d2c |
*(new_pb->pb_mr) = *(pb->pb_mr);
|
|
|
b03d2c |
+ memset(pb->pb_mr, 0, sizeof(slapi_pblock_matching_rule));
|
|
|
b03d2c |
}
|
|
|
b03d2c |
if (pb->pb_misc != NULL) {
|
|
|
b03d2c |
_pblock_assert_pb_misc(new_pb);
|
|
|
b03d2c |
*(new_pb->pb_misc) = *(pb->pb_misc);
|
|
|
b03d2c |
+ memset(pb->pb_misc, 0, sizeof(slapi_pblock_misc));
|
|
|
b03d2c |
}
|
|
|
b03d2c |
if (pb->pb_intop != NULL) {
|
|
|
b03d2c |
_pblock_assert_pb_intop(new_pb);
|
|
|
b03d2c |
*(new_pb->pb_intop) = *(pb->pb_intop);
|
|
|
b03d2c |
- /* set pwdpolicy to NULL so this clone allocates its own policy */
|
|
|
b03d2c |
- new_pb->pb_intop->pwdpolicy = NULL;
|
|
|
b03d2c |
+ memset(pb->pb_intop, 0, sizeof(slapi_pblock_intop));
|
|
|
b03d2c |
}
|
|
|
b03d2c |
if (pb->pb_intplugin != NULL) {
|
|
|
b03d2c |
_pblock_assert_pb_intplugin(new_pb);
|
|
|
b03d2c |
*(new_pb->pb_intplugin) = *(pb->pb_intplugin);
|
|
|
b03d2c |
+ memset(pb->pb_intplugin, 0,sizeof(slapi_pblock_intplugin));
|
|
|
b03d2c |
}
|
|
|
b03d2c |
if (pb->pb_deprecated != NULL) {
|
|
|
b03d2c |
_pblock_assert_pb_deprecated(new_pb);
|
|
|
b03d2c |
*(new_pb->pb_deprecated) = *(pb->pb_deprecated);
|
|
|
b03d2c |
+ memset(pb->pb_deprecated, 0, sizeof(slapi_pblock_deprecated));
|
|
|
b03d2c |
}
|
|
|
b03d2c |
#ifdef PBLOCK_ANALYTICS
|
|
|
b03d2c |
new_pb->analytics = NULL;
|
|
|
b03d2c |
--
|
|
|
b03d2c |
2.31.1
|
|
|
b03d2c |
|