diff --git a/CVE-2022-41881.patch b/CVE-2022-41881.patch new file mode 100644 index 0000000000000000000000000000000000000000..cf50717dd40b9f509b49182dd077ad3218b65597 --- /dev/null +++ b/CVE-2022-41881.patch @@ -0,0 +1,166 @@ +From cd91cf3c99123bd1e53fd6a1de0e3d1922f05bb2 Mon Sep 17 00:00:00 2001 +From: Norman Maurer +Date: Mon, 12 Dec 2022 14:04:31 +0100 +Subject: [PATCH] Merge pull request from GHSA-fx2c-96vj-985v + +Motivation: + +A StackOverflowError can be raised when parsing a malformed crafted message due to an +infinite recursion. We should bail out early + +Modifications: + +- Add a limit to the maximum nesting of TLV. +- Add unit test + +Result: + +Not possible anymore to trigger a StackOverflowError with a special crafted packet + +--- + .../handler/codec/haproxy/HAProxyMessage.java | 16 +++-- + .../haproxy/HAProxyMessageDecoderTest.java | 65 +++++++++++++++++++ + 2 files changed, 76 insertions(+), 5 deletions(-) + +diff --git a/codec-haproxy/src/main/java/io/netty/handler/codec/haproxy/HAProxyMessage.java b/codec-haproxy/src/main/java/io/netty/handler/codec/haproxy/HAProxyMessage.java +index b40bf42..3f30c4a 100644 +--- a/codec-haproxy/src/main/java/io/netty/handler/codec/haproxy/HAProxyMessage.java ++++ b/codec-haproxy/src/main/java/io/netty/handler/codec/haproxy/HAProxyMessage.java +@@ -30,6 +30,9 @@ import java.util.List; + */ + public final class HAProxyMessage { + ++ // Let's pick some conservative limit here. ++ private static final int MAX_NESTING_LEVEL = 128; ++ + /** + * Version 1 proxy protocol message for 'UNKNOWN' proxied protocols. Per spec, when the proxied protocol is + * 'UNKNOWN' we must discard all other header values. +@@ -238,7 +241,7 @@ public final class HAProxyMessage { + } + + private static List readTlvs(final ByteBuf header) { +- HAProxyTLV haProxyTLV = readNextTLV(header); ++ HAProxyTLV haProxyTLV = readNextTLV(header, 0); + if (haProxyTLV == null) { + return Collections.emptyList(); + } +@@ -250,12 +253,15 @@ public final class HAProxyMessage { + if (haProxyTLV instanceof HAProxySSLTLV) { + haProxyTLVs.addAll(((HAProxySSLTLV) haProxyTLV).encapsulatedTLVs()); + } +- } while ((haProxyTLV = readNextTLV(header)) != null); ++ } while ((haProxyTLV = readNextTLV(header, 0)) != null); + return haProxyTLVs; + } + +- private static HAProxyTLV readNextTLV(final ByteBuf header) { +- ++ private static HAProxyTLV readNextTLV(final ByteBuf header, int nestingLevel) { ++ if (nestingLevel > MAX_NESTING_LEVEL) { ++ throw new HAProxyProtocolException( ++ "Maximum TLV nesting level reached: " + nestingLevel + " (expected: < " + MAX_NESTING_LEVEL + ')'); ++ } + // We need at least 4 bytes for a TLV + if (header.readableBytes() < 4) { + return null; +@@ -276,7 +282,7 @@ public final class HAProxyMessage { + + final List encapsulatedTlvs = new ArrayList(4); + do { +- final HAProxyTLV haProxyTLV = readNextTLV(byteBuf); ++ final HAProxyTLV haProxyTLV = readNextTLV(byteBuf, nestingLevel + 1); + if (haProxyTLV == null) { + break; + } +diff --git a/codec-haproxy/src/test/java/io/netty/handler/codec/haproxy/HAProxyMessageDecoderTest.java b/codec-haproxy/src/test/java/io/netty/handler/codec/haproxy/HAProxyMessageDecoderTest.java +index 2d4039d..8d27e4a 100644 +--- a/codec-haproxy/src/test/java/io/netty/handler/codec/haproxy/HAProxyMessageDecoderTest.java ++++ b/codec-haproxy/src/test/java/io/netty/handler/codec/haproxy/HAProxyMessageDecoderTest.java +@@ -16,6 +16,7 @@ + package io.netty.handler.codec.haproxy; + + import io.netty.buffer.ByteBuf; ++import io.netty.buffer.Unpooled; + import io.netty.channel.ChannelFuture; + import io.netty.channel.embedded.EmbeddedChannel; + import io.netty.handler.codec.ProtocolDetectionResult; +@@ -26,6 +27,9 @@ import io.netty.util.CharsetUtil; + import org.junit.Before; + import org.junit.Test; + ++import java.io.ByteArrayOutputStream; ++import java.nio.ByteBuffer; ++import java.nio.ByteOrder; + import java.util.List; + + import static io.netty.buffer.Unpooled.*; +@@ -1013,4 +1017,65 @@ public class HAProxyMessageDecoderTest { + assertNull(result.detectedProtocol()); + incompleteHeader.release(); + } ++ ++ @Test ++ public void testNestedTLV() throws Exception { ++ ByteArrayOutputStream headerWriter = new ByteArrayOutputStream(); ++ //src_ip = "AAAA", dst_ip = "BBBB", src_port = "CC", dst_port = "DD" ++ headerWriter.write(new byte[] {'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'C', 'D', 'D'}); ++ //write TLVs ++ int countOfTLVs = 8100; ++ ByteBuffer tlvLengthBuf = ByteBuffer.allocate(2); ++ tlvLengthBuf.order(ByteOrder.BIG_ENDIAN); ++ short totalLength = (short) (countOfTLVs * (1 + 2 + 1 + 4)); ++ for (int i = 0; i < countOfTLVs; i++) { ++ //write PP2_TYPE_SSL TLV ++ headerWriter.write(0x20); //PP2_TYPE_SSL ++ //notice that the TLV length cannot be bigger than 0xffff ++ totalLength -= 1 + 2; //exclude type and length themselves ++ tlvLengthBuf.clear(); ++ tlvLengthBuf.putShort(totalLength); ++ //add to the header ++ headerWriter.write(tlvLengthBuf.array()); ++ //write client field ++ headerWriter.write(1); ++ //write verify field ++ headerWriter.write(new byte[] {'V', 'V', 'V', 'V'}); ++ //subtract the client and verify fields ++ totalLength -= 1 + 4; ++ } ++ byte[] header = headerWriter.toByteArray(); ++ ByteBuffer numsWrite = ByteBuffer.allocate(2); ++ numsWrite.order(ByteOrder.BIG_ENDIAN); ++ numsWrite.putShort((short) header.length); ++ ++ final ByteBuf data = Unpooled.buffer(); ++ data.writeBytes(new byte[] { ++ (byte) 0x0D, ++ (byte) 0x0A, ++ (byte) 0x0D, ++ (byte) 0x0A, ++ (byte) 0x00, ++ (byte) 0x0D, ++ (byte) 0x0A, ++ (byte) 0x51, ++ (byte) 0x55, ++ (byte) 0x49, ++ (byte) 0x54, ++ (byte) 0x0A ++ }); ++ //verCmd = 32 ++ byte versionCmd = 0x20 | 1; //V2 | ProxyCmd ++ data.writeByte(versionCmd); ++ data.writeByte(17); //TPAF_TCP4_BYTE ++ data.writeBytes(numsWrite.array()); ++ data.writeBytes(header); ++ ++ assertThrows(HAProxyProtocolException.class, new Executable() { ++ @Override ++ public void execute() { ++ ch.writeInbound(data); ++ } ++ }); ++ } + } +-- +2.30.0 + diff --git a/netty.spec b/netty.spec index 5c163e4856b083f7e559dded9ed5214b2f9e4189..ba7a950111b96da9a40c8865c6080408b425f976 100644 --- a/netty.spec +++ b/netty.spec @@ -2,7 +2,7 @@ Name: netty Version: 4.1.13 -Release: 20 +Release: 21 Summary: Asynchronous event-driven network application Java framework License: ASL 2.0 URL: https://netty.io/ @@ -30,6 +30,8 @@ Patch0018: CVE-2021-37137.patch Patch0019: CVE-2021-43797-pre.patch Patch0020: CVE-2021-43797.patch Patch0021: fix-strip.patch +# https://github.com/netty/netty/commit/cd91cf3c99123bd1e53fd6a1de0e3d1922f05bb2 +Patch0022: CVE-2022-41881.patch BuildRequires: maven-local mvn(ant-contrib:ant-contrib) BuildRequires: mvn(com.jcraft:jzlib) mvn(commons-logging:commons-logging) @@ -154,6 +156,9 @@ export CFLAGS="$RPM_OPT_FLAGS" LDFLAGS="$RPM_LD_FLAGS" %changelog +* Wed Dec 13 2023 yaoxin - 4.1.13-21 +- Fix CVE-2022-41881 + * Sun Mar 05 2023 wulei - 4.1.13-20 - Add strip