You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2026/10/15 19:45:20 UTC
(tomcat) 17/25: Fix ArrayIndexOutOfBoundsException in IPv6Utils.canonize()
This is an automated email from the ASF dual-hosted git repository.
rmaucher pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 813ce52918b82b070e0e21c5c65a12a6253dd444
Author: opencode <re...@apache.org>
AuthorDate: Thu Oct 15 13:19:04 2026 +0200
Fix ArrayIndexOutOfBoundsException in IPv6Utils.canonize()
Inputs that pass the mayBeIPv6Address() heuristic but contain more than
8 colon-separated groups (e.g. "1:2:3:4:5:6:7:8:9" or forms with more
than two consecutive colons), or groups with more than 4 significant
characters (e.g. "12345::"), indexed the fixed-size group store out of
bounds and threw an undocumented ArrayIndexOutOfBoundsException. With
the non-default access log attribute ipv6Canonical="true", such values
(e.g. from a client-supplied Host header via the %v element) caused
loss of the access log record plus a warning per request. canonize()
now returns such malformed inputs unchanged, consistent with how
non-IPv6 input is already passed through. Add tests for the
pass-through behaviour and for the valid 8-colon forms
("1:2:3:4:5:6:7::") whose canonicalization must be preserved.
---
java/org/apache/tomcat/util/net/IPv6Utils.java | 20 ++++++++++++++
test/org/apache/tomcat/util/net/TestIPv6Utils.java | 31 ++++++++++++++++++++++
2 files changed, 51 insertions(+)
diff --git a/java/org/apache/tomcat/util/net/IPv6Utils.java b/java/org/apache/tomcat/util/net/IPv6Utils.java
index 8e82d1320c..4b4cb50142 100644
--- a/java/org/apache/tomcat/util/net/IPv6Utils.java
+++ b/java/org/apache/tomcat/util/net/IPv6Utils.java
@@ -90,6 +90,20 @@ public class IPv6Utils {
ipv6AddressLength = ipv6Address.lastIndexOf('%');
}
+ // A valid IPv6 address contains at most 8 colons: 7 separate 8 explicit groups, and 8 are only reached
+ // when "::" compresses a single zero group next to 7 explicit groups (RFC 4291 allows "::" to stand for
+ // one or more zero groups). Inputs with more colons than that are not valid IPv6 addresses but the
+ // mayBeIPv6Address() heuristic above does not exclude them. Return such inputs unchanged.
+ int colonCount = 0;
+ for (int i = 0; i < ipv6AddressLength; i++) {
+ if (ipv6Address.charAt(i) == ':') {
+ colonCount++;
+ }
+ }
+ if (colonCount > MAX_NUMBER_OF_GROUPS) {
+ return ipv6Address;
+ }
+
StringBuilder result = new StringBuilder();
char[][] groups = new char[MAX_NUMBER_OF_GROUPS][MAX_GROUP_LENGTH];
int groupCounter = 0;
@@ -151,6 +165,12 @@ public class IPv6Utils {
c = (char) (c + 32);
}
if (c != ':') {
+ if (groupCounter >= MAX_NUMBER_OF_GROUPS || charInGroupCounter >= MAX_GROUP_LENGTH) {
+ // A ninth group with content, or a group with more than 4 significant characters. Neither is a
+ // valid IPv6 address but the mayBeIPv6Address() heuristic above does not exclude them. Return
+ // the input unchanged.
+ return ipv6Address;
+ }
groups[groupCounter][charInGroupCounter] = c;
if (!(groupStart && c == '0')) {
++charInGroupCounter;
diff --git a/test/org/apache/tomcat/util/net/TestIPv6Utils.java b/test/org/apache/tomcat/util/net/TestIPv6Utils.java
index 5d667ed67b..fd909bb9c8 100644
--- a/test/org/apache/tomcat/util/net/TestIPv6Utils.java
+++ b/test/org/apache/tomcat/util/net/TestIPv6Utils.java
@@ -114,6 +114,12 @@ public class TestIPv6Utils {
// Already ends with "::"
Assert.assertEquals("2001:db8::", IPv6Utils.canonize("2001:db8::"));
+ // "::" at the start or end standing for a single zero group next to 7 explicit groups (8 colons)
+ Assert.assertEquals("1:2:3:4:5:6:7:0", IPv6Utils.canonize("1:2:3:4:5:6:7::"));
+ Assert.assertEquals("0:2:3:4:5:6:7:8", IPv6Utils.canonize("::2:3:4:5:6:7:8"));
+ Assert.assertEquals("::", IPv6Utils.canonize("0:0:0:0:0:0:0::"));
+ Assert.assertEquals("1:2:3:4:5:6:7:0%eth0", IPv6Utils.canonize("1:2:3:4:5:6:7::%eth0"));
+
// IPv4 inside IPv6
Assert.assertEquals("::ffff:192.0.2.1", IPv6Utils.canonize("::ffff:192.0.2.1"));
Assert.assertEquals("::ffff:192.0.2.1", IPv6Utils.canonize("0:0:0:0:0:ffff:192.0.2.1"));
@@ -141,4 +147,29 @@ public class TestIPv6Utils {
Assert.assertEquals("www.apache.org", IPv6Utils.canonize("www.apache.org"));
Assert.assertEquals("ipv6.google.com", IPv6Utils.canonize("ipv6.google.com"));
}
+
+ @Test
+ public void testCanonizeTooManyGroups() {
+ // Strings with more than 8 groups pass the mayBeIPv6Address() heuristic but are not valid IPv6
+ // addresses. They used to trigger an ArrayIndexOutOfBoundsException. The input is now returned
+ // unchanged.
+ Assert.assertEquals("1:2:3:4:5:6:7:8:9", IPv6Utils.canonize("1:2:3:4:5:6:7:8:9"));
+ Assert.assertEquals("1:2:3:4:5:6:7::8:9", IPv6Utils.canonize("1:2:3:4:5:6:7::8:9"));
+ Assert.assertEquals("1:2:3:4:5:6:7:8:9:10", IPv6Utils.canonize("1:2:3:4:5:6:7:8:9:10"));
+ Assert.assertEquals("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
+ IPv6Utils.canonize("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"));
+ Assert.assertEquals("1:2:3:4:5:6:7:8:9%1", IPv6Utils.canonize("1:2:3:4:5:6:7:8:9%1"));
+ // Additional empty groups created by more than two consecutive colons
+ Assert.assertEquals("1:2:3:4:5:6:7:8:::", IPv6Utils.canonize("1:2:3:4:5:6:7:8:::"));
+ Assert.assertEquals("::::a:::::", IPv6Utils.canonize("::::a:::::"));
+ }
+
+ @Test
+ public void testCanonizeGroupTooLong() {
+ // A group with more than 4 significant hex digits passes the mayBeIPv6Address() heuristic but is
+ // not valid IPv6. It used to trigger an ArrayIndexOutOfBoundsException. The input is now returned
+ // unchanged.
+ Assert.assertEquals("12345:0:0:0:0:0:0:0", IPv6Utils.canonize("12345:0:0:0:0:0:0:0"));
+ Assert.assertEquals("12345::", IPv6Utils.canonize("12345::"));
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org