This is an automated email from the ASF dual-hosted git repository. jbonofre pushed a commit to branch activemq-5.18.x in repository https://gitbox.apache.org/repos/asf/activemq.git
commit 705cf299f9ce2c8f489114359792ef5e5c6c48b1 Author: Christopher L. Shannon <[email protected]> AuthorDate: Fri Nov 21 14:33:27 2025 -0500 AMQ-9810 - Add additional validation for MQTT control packets Validate that the remaining length field is the correct number of bytes --- .../apache/activemq/transport/mqtt/MQTTCodec.java | 6 ++++ .../activemq/transport/mqtt/MQTTCodecTest.java | 33 ++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/activemq-mqtt/src/main/java/org/apache/activemq/transport/mqtt/MQTTCodec.java b/activemq-mqtt/src/main/java/org/apache/activemq/transport/mqtt/MQTTCodec.java index 12c9981db2..06efe49910 100644 --- a/activemq-mqtt/src/main/java/org/apache/activemq/transport/mqtt/MQTTCodec.java +++ b/activemq-mqtt/src/main/java/org/apache/activemq/transport/mqtt/MQTTCodec.java @@ -25,6 +25,8 @@ import org.fusesource.mqtt.codec.MQTTFrame; public class MQTTCodec { + private static final int MAX_MULTIPLIER = (int) Math.pow(2, 21); + private final MQTTFrameSink frameSink; private final MQTTWireFormat wireFormat; @@ -159,6 +161,10 @@ public class MQTTCodec { int i = 0; while (i++ < readSize) { digit = data.readByte(); + // MQTT protocol limits Remaining Length to 4 bytes + if (multiplier == MAX_MULTIPLIER && (digit & 128) != 0) { + throw new IOException("Remaining length exceeds 4 bytes"); + } length += (digit & 0x7F) * multiplier; multiplier <<= 7; if ((digit & 0x80) == 0) { diff --git a/activemq-mqtt/src/test/java/org/apache/activemq/transport/mqtt/MQTTCodecTest.java b/activemq-mqtt/src/test/java/org/apache/activemq/transport/mqtt/MQTTCodecTest.java index 49722d8eec..b14fba8c58 100644 --- a/activemq-mqtt/src/test/java/org/apache/activemq/transport/mqtt/MQTTCodecTest.java +++ b/activemq-mqtt/src/test/java/org/apache/activemq/transport/mqtt/MQTTCodecTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.io.IOException; import java.net.ProtocolException; import java.util.ArrayList; import java.util.List; @@ -314,4 +315,36 @@ public class MQTTCodecTest { LOG.info("Total time to process: {}", TimeUnit.MILLISECONDS.toSeconds(duration)); } + + + @Test + public void testParseInvalidRemainingLengthField() throws Exception { + try { + // The maximum bytes in the remaining length field is 4 + // The most significant bit is used to indicate that there are following bytes in the representation. + // If the most significant digit is a 1 in byte 4 that is an error and invalid length field + final Buffer buffer = new Buffer(new byte[]{CONNECT.TYPE, (byte) 0x81, (byte) 0x81, + (byte) 0x81, (byte) 0x81}); + final DataByteArrayInputStream input = new DataByteArrayInputStream(buffer); + codec.parse(input, buffer.length()); + fail("Parsing should have failed invalid remaining length field"); + } catch (IOException e) { + // expected + } + } + + @Test + public void testPartialReadInvalidRemainingLengthField() throws Exception { + // Test Invalid remaining field checking still works with partial reads + Buffer buffer = new Buffer(new byte[]{CONNECT.TYPE, (byte) 0x81, (byte) 0x81}); + codec.parse(new DataByteArrayInputStream(buffer), buffer.length()); + try { + buffer = new Buffer(new byte[]{(byte) 0x81, (byte) 0x81}); + codec.parse(new DataByteArrayInputStream(buffer), buffer.length()); + fail("Parsing should have failed invalid remaining length field"); + } catch (IOException e) { + // expected + } + } + } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected] For further information, visit: https://activemq.apache.org/contact
