java-topology/defects/tomcat/patch/tomcat-0001.patch

69 lines
3.3 KiB
Diff

# UNDF: UNDF-2026-000000315
From 0000001 Mon Sep 17 00:00:00 2001
Subject: [PATCH] CWE-407: tomcat-0001 — fix O(n²) ArrayList.contains() in
ReplicationValve.registerReplicationSession()
ReplicationValve accumulates cross-context DeltaSession objects per request in
a ThreadLocal<ArrayList<DeltaSession>>. Each call to registerReplicationSession()
called sessions.contains(session) — O(n) scan — before adding. With many
portlet fragments sharing sessions this degrades to O(n²).
Fix: replace ArrayList with LinkedHashSet in the ThreadLocal initialiser and
all three call sites that set/iterate it (lines 297, 394, 422). Set.add() is
idempotent so the contains() guard is removed entirely.
CWE: CWE-407 (Inefficient Algorithmic Complexity)
Severity: MEDIUM
---
.../apache/catalina/ha/tcp/ReplicationValve.java | 20 +++++++++-----------
1 file changed, 9 insertions(+), 11 deletions(-)
diff --git a/java/org/apache/catalina/ha/tcp/ReplicationValve.java b/java/org/apache/catalina/ha/tcp/ReplicationValve.java
index aaaaaaa..bbbbbbb 100644
--- a/java/org/apache/catalina/ha/tcp/ReplicationValve.java
+++ b/java/org/apache/catalina/ha/tcp/ReplicationValve.java
@@ -17,7 +17,8 @@ package org.apache.catalina.ha.tcp;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.regex.Pattern;
@@ -77,7 +78,7 @@ public class ReplicationValve extends ValveBase implements ClusterValve {
* Register all cross context sessions inside endAccess. Use a list with
* contains check, that the Portlet API can include a lot of fragments from
* same or different applications with session changes.
- * ThreadLocal<ArrayList<DeltaSession>>
+ * ThreadLocal<LinkedHashSet<DeltaSession>>
*/
- protected final ThreadLocal<ArrayList<DeltaSession>> crossContextSessions = new ThreadLocal<>();
+ protected final ThreadLocal<LinkedHashSet<DeltaSession>> crossContextSessions = new ThreadLocal<>();
@@ -262,13 +263,10 @@ public class ReplicationValve extends ValveBase implements ClusterValve {
*/
public void registerReplicationSession(DeltaSession session) {
- List<DeltaSession> sessions = crossContextSessions.get();
+ LinkedHashSet<DeltaSession> sessions = crossContextSessions.get();
if (sessions != null) {
- if (!sessions.contains(session)) {
- if (log.isTraceEnabled()) {
- log.trace(sm.getString("ReplicationValve.crossContext.registerSession",
- session.getIdInternal(),
- session.getManager().getContext().getName()));
- }
- sessions.add(session);
+ if (log.isTraceEnabled() && sessions.add(session)) {
+ log.trace(sm.getString("ReplicationValve.crossContext.registerSession",
+ session.getIdInternal(),
+ session.getManager().getContext().getName()));
+ } else {
+ sessions.add(session); // O(1) — Set deduplicates automatically
}
}
}
@@ -293,7 +291,7 @@ public class ReplicationValve extends ValveBase implements ClusterValve {
if (isCrossContext) {
- crossContextSessions.set(new ArrayList<>());
+ crossContextSessions.set(new LinkedHashSet<>());
}