From e96dc1eae5f6bd4d4669e4327a6b038b543fe21d Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Fri, 29 Aug 2025 13:59:15 +0000
Subject: [PATCH] [#545] Fix deadlock in StaticGroup.updateMembers by reducing writeLock scope

---
 opendj-server-legacy/src/main/java/org/opends/server/extensions/StaticGroup.java |   65 +++++++++++++++++++-------------
 1 files changed, 39 insertions(+), 26 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/extensions/StaticGroup.java b/opendj-server-legacy/src/main/java/org/opends/server/extensions/StaticGroup.java
index 4690eec..58a6f6e 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/extensions/StaticGroup.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/extensions/StaticGroup.java
@@ -549,44 +549,58 @@
     Reject.ifNull(nestedGroups);
 
     reloadIfNeeded();
-    lock.writeLock().lock();
-    try
+    for (Modification mod : modifications)
     {
-      for (Modification mod : modifications)
+      Attribute attribute = mod.getAttribute();
+      if (attribute.getAttributeDescription().getAttributeType().equals(memberAttributeType))
       {
-        Attribute attribute = mod.getAttribute();
-        if (attribute.getAttributeDescription().getAttributeType().equals(memberAttributeType))
+        switch (mod.getModificationType().asEnum())
         {
-          switch (mod.getModificationType().asEnum())
-          {
-            case ADD:
-              for (ByteString v : attribute)
-              {
-                DN member = DN.valueOf(v);
+          case ADD:
+            for (ByteString v : attribute)
+            {
+              DN member = DN.valueOf(v);
+              lock.writeLock().lock();
+              try {
                 memberDNs.add(new CompactDn(member));
                 if (DirectoryServer.getGroupManager().getGroupInstance(member) != null)
                 {
                   nestedGroups.add(member);
                 }
+              } finally {
+                lock.writeLock().unlock();
               }
-              break;
-            case DELETE:
-              if (attribute.isEmpty())
-              {
+            }
+            break;
+          case DELETE:
+            if (attribute.isEmpty())
+            {
+              lock.writeLock().lock();
+              try {
                 memberDNs.clear();
                 nestedGroups.clear();
+              } finally {
+                lock.writeLock().unlock();
               }
-              else
+            }
+            else
+            {
+              for (ByteString v : attribute)
               {
-                for (ByteString v : attribute)
-                {
-                  DN member = DN.valueOf(v);
+                DN member = DN.valueOf(v);
+                lock.writeLock().lock();
+                try {
                   memberDNs.remove(new CompactDn(member));
                   nestedGroups.remove(member);
+                } finally {
+                  lock.writeLock().unlock();
                 }
               }
-              break;
-            case REPLACE:
+            }
+            break;
+          case REPLACE:
+            lock.writeLock().lock();
+            try {
               memberDNs.clear();
               nestedGroups.clear();
               for (ByteString v : attribute)
@@ -598,14 +612,13 @@
                   nestedGroups.add(member);
                 }
               }
-              break;
-          }
+            } finally {
+              lock.writeLock().unlock();
+            }
+            break;
         }
       }
     }
-    finally {
-      lock.writeLock().unlock();
-    }
   }
 
   @Override

--
Gitblit v1.10.0