This is an automated email from the ASF dual-hosted git repository.

markt-asf pushed a commit to branch 11.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/11.0.x by this push:
     new c6310d1cfd Review "Bound the multicast send paths to a sendable packet 
size"
c6310d1cfd is described below

commit c6310d1cfda41fb53fd1a083ba72dd2a0ab7d03c
Author: Mark Thomas <[email protected]>
AuthorDate: Thu Oct 22 17:42:15 2026 +0100

    Review "Bound the multicast send paths to a sendable packet size"
    
    Extend coverage to all variable length components
---
 .../tribes/membership/LocalStrings.properties      |  4 ++
 .../catalina/tribes/membership/MemberImpl.java     | 45 ++++++++++++++--------
 .../catalina/tribes/membership/TestMemberImpl.java | 42 ++++++++++++++++++++
 3 files changed, 76 insertions(+), 15 deletions(-)

diff --git a/java/org/apache/catalina/tribes/membership/LocalStrings.properties 
b/java/org/apache/catalina/tribes/membership/LocalStrings.properties
index a3422e4721..d2967a6e3f 100644
--- a/java/org/apache/catalina/tribes/membership/LocalStrings.properties
+++ b/java/org/apache/catalina/tribes/membership/LocalStrings.properties
@@ -61,7 +61,11 @@ mcastServiceImpl.waitForMembers.start=Sleeping for [{0}] 
milliseconds to establi
 memberImpl.invalid.hostLength=Invalid host length [{0}]
 memberImpl.invalid.package.begin=Invalid package, should start with:[{0}]
 memberImpl.invalid.package.end=Invalid package, should end with:[{0}]
+memberImpl.large.command=Command is too large for tribes to handle.
+memberImpl.large.domain=Domain is too large for tribes to handle.
+memberImpl.large.host=Host is too large for tribes to handle.
 memberImpl.large.payload=Payload is too large for tribes to handle.
+memberImpl.large.uniqueId=Unique ID is too large for tribes to handle.
 memberImpl.notEnough.bytes=Not enough bytes in member package.
 memberImpl.package.small=Member package too small to validate.
 
diff --git a/java/org/apache/catalina/tribes/membership/MemberImpl.java 
b/java/org/apache/catalina/tribes/membership/MemberImpl.java
index edac5f8dab..56e9319bbc 100644
--- a/java/org/apache/catalina/tribes/membership/MemberImpl.java
+++ b/java/org/apache/catalina/tribes/membership/MemberImpl.java
@@ -427,12 +427,12 @@ public class MemberImpl implements Member, 
java.io.Externalizable {
         pos += payload.length;
 
         synchronized (member) {
-            member.setHost(addr);
+            member.host = addr;
             member.setPort(XByteBuffer.toInt(portd, 0));
             member.setSecurePort(XByteBuffer.toInt(sportd, 0));
             member.setUdpPort(XByteBuffer.toInt(uportd, 0));
             member.setMemberAliveTime(XByteBuffer.toLong(alived, 0));
-            member.setUniqueId(uniqueId);
+            member.uniqueId = uniqueId;
             member.payload = payload;
             member.domain = domain;
             member.command = command;
@@ -628,7 +628,9 @@ public class MemberImpl implements Member, 
java.io.Externalizable {
      * @param host the host
      */
     public synchronized void setHost(byte[] host) {
+        checkSize(this.host.length, host != null ? host.length : 0, 
"memberImpl.large.host");
         this.host = host;
+        this.dataPkg = null;
     }
 
     /**
@@ -637,9 +639,12 @@ public class MemberImpl implements Member, 
java.io.Externalizable {
      * @throws IOException if there is an error converting the host name to an 
IP address
      */
     public void setHostname(String host) throws IOException {
-        hostname = host;
+        byte[] address = java.net.InetAddress.getByName(host).getAddress();
         synchronized (this) {
-            this.host = java.net.InetAddress.getByName(host).getAddress();
+            checkSize(this.host.length, address.length, 
"memberImpl.large.host");
+            hostname = host;
+            this.host = address;
+            this.dataPkg = null;
         }
     }
 
@@ -673,31 +678,40 @@ public class MemberImpl implements Member, 
java.io.Externalizable {
      * @param uniqueId the unique ID
      */
     public synchronized void setUniqueId(byte[] uniqueId) {
+        checkSize(this.uniqueId.length, uniqueId != null ? uniqueId.length : 
16, "memberImpl.large.uniqueId");
         this.uniqueId = uniqueId != null ? uniqueId : new byte[16];
         getData(true, true);
     }
 
     @Override
     public synchronized void setPayload(byte[] payload) {
+        checkSize(this.payload.length, payload != null ? payload.length : 0, 
"memberImpl.large.payload");
+        this.payload = payload != null ? payload : new byte[0];
+        getData(true, true);
+    }
+
+    /**
+     * Check that replacing a variable length component of this member will 
not take the member ping above the maximum
+     * size that can be sent. Must be called before the component is changed 
so that a rejected change leaves the member
+     * unmodified.
+     *
+     * @param oldLength The length of the component being replaced
+     * @param newLength The length of the replacement component
+     * @param msgKey    The key of the message for the exception thrown if the 
size is exceeded
+     */
+    private void checkSize(int oldLength, int newLength, String msgKey) {
         // longs to avoid any possibility of overflow
-        long oldPayloadLength = this.payload.length;
-        long newPayloadLength = 0;
-        if (payload != null) {
-            newPayloadLength = payload.length;
-        }
-        if (newPayloadLength > oldPayloadLength) {
+        if (newLength > oldLength) {
             // It is possible that the max packet size will be exceeded
-            if ((newPayloadLength - oldPayloadLength +
-                    getData(false, false).length) > 
McastServiceImpl.MAX_SEND_SIZE) {
-                throw new 
IllegalArgumentException(sm.getString("memberImpl.large.payload"));
+            if (((long) newLength - oldLength + getData(false, false).length) 
> McastServiceImpl.MAX_SEND_SIZE) {
+                throw new IllegalArgumentException(sm.getString(msgKey));
             }
         }
-        this.payload = payload != null ? payload : new byte[0];
-        getData(true, true);
     }
 
     @Override
     public synchronized void setCommand(byte[] command) {
+        checkSize(this.command.length, command != null ? command.length : 0, 
"memberImpl.large.command");
         this.command = command != null ? command : new byte[0];
         getData(true, true);
     }
@@ -707,6 +721,7 @@ public class MemberImpl implements Member, 
java.io.Externalizable {
      * @param domain the domain
      */
     public synchronized void setDomain(byte[] domain) {
+        checkSize(this.domain.length, domain != null ? domain.length : 0, 
"memberImpl.large.domain");
         this.domain = domain != null ? domain : new byte[0];
         getData(true, true);
     }
diff --git a/test/org/apache/catalina/tribes/membership/TestMemberImpl.java 
b/test/org/apache/catalina/tribes/membership/TestMemberImpl.java
index b13e8e9030..07c6e8f4d3 100644
--- a/test/org/apache/catalina/tribes/membership/TestMemberImpl.java
+++ b/test/org/apache/catalina/tribes/membership/TestMemberImpl.java
@@ -45,4 +45,46 @@ public class TestMemberImpl {
             // The size check must reject it
         }
     }
+
+    /*
+     * Every variable length component of the ping must be bounded in the same 
way as the payload, and
+     * a rejected change must leave the member unmodified and usable.
+     */
+    @Test
+    public void testOtherComponentsAreBoundedAtTheSendableSize() throws 
Exception {
+        MemberImpl member = new MemberImpl("localhost", 4000, 100);
+        member.setUniqueId(UUIDGenerator.randomUUID(false));
+        byte[] before = member.getData(false, false);
+        int base = before.length;
+        int tooLarge = McastServiceImpl.MAX_SEND_SIZE - base + 1;
+
+        try {
+            member.setCommand(new byte[tooLarge + member.getCommand().length]);
+            Assert.fail("An oversized command must be rejected");
+        } catch (IllegalArgumentException expected) {
+            // Expected
+        }
+        try {
+            member.setDomain(new byte[tooLarge + member.getDomain().length]);
+            Assert.fail("An oversized domain must be rejected");
+        } catch (IllegalArgumentException expected) {
+            // Expected
+        }
+        try {
+            member.setUniqueId(new byte[tooLarge + 
member.getUniqueId().length]);
+            Assert.fail("An oversized unique ID must be rejected");
+        } catch (IllegalArgumentException expected) {
+            // Expected
+        }
+        try {
+            member.setHost(new byte[tooLarge + member.getHost().length]);
+            Assert.fail("An oversized host must be rejected");
+        } catch (IllegalArgumentException expected) {
+            // Expected
+        }
+
+        // Rejected changes leave the member unmodified and usable
+        Assert.assertEquals(base, member.getData(false, true).length);
+        member.setCommand(new byte[4]);
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to