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

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