Blame SOURCES/0013-CVE-2021-4091-BZ-2030367-double-free-of-the-virtual-.patch

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