Compare commits
10 Commits
c69b103bea
...
2d055830c2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d055830c2 | ||
|
|
2bf58c9d76 | ||
|
|
4cf9d9448b | ||
|
|
7997c6b5e8 | ||
|
|
96ee89be49 | ||
|
|
8de09516fe | ||
|
|
7d22acf249 | ||
|
|
c09eb42dac | ||
|
|
c6b50b4c6e | ||
|
|
575533ae5b |
166
CVE-2022-41881.patch
Normal file
166
CVE-2022-41881.patch
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
From cd91cf3c99123bd1e53fd6a1de0e3d1922f05bb2 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Norman Maurer <norman_maurer@apple.com>
|
||||||
|
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<HAProxyTLV> 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<HAProxyTLV> encapsulatedTlvs = new ArrayList<HAProxyTLV>(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
|
||||||
|
|
||||||
411
CVE-2024-29025.patch
Normal file
411
CVE-2024-29025.patch
Normal file
@ -0,0 +1,411 @@
|
|||||||
|
From: Markus Koschany <apo@debian.org>
|
||||||
|
Date: Sat, 11 May 2024 21:52:15 +0200
|
||||||
|
Subject: CVE-2024-29025
|
||||||
|
|
||||||
|
Bug-Debian: https://bugs.debian.org/1068110
|
||||||
|
Origin: https://github.com/netty/netty/commit/0d0c6ed782d13d423586ad0c71737b2c7d02058c
|
||||||
|
---
|
||||||
|
.../HttpPostMultipartRequestDecoder.java | 41 +++++++
|
||||||
|
.../multipart/HttpPostRequestDecoder.java | 70 ++++++++++++
|
||||||
|
.../HttpPostStandardRequestDecoder.java | 44 ++++++++
|
||||||
|
.../multipart/HttpPostRequestDecoderTest.java | 103 ++++++++++++++++++
|
||||||
|
4 files changed, 258 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostMultipartRequestDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostMultipartRequestDecoder.java
|
||||||
|
index 17c3e64..7cac6a0 100644
|
||||||
|
--- a/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostMultipartRequestDecoder.java
|
||||||
|
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostMultipartRequestDecoder.java
|
||||||
|
@@ -61,6 +61,16 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||||
|
*/
|
||||||
|
private final HttpRequest request;
|
||||||
|
|
||||||
|
+ /**
|
||||||
|
+ * The maximum number of fields allows by the form
|
||||||
|
+ */
|
||||||
|
+ private final int maxFields;
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * The maximum number of accumulated bytes when decoding a field
|
||||||
|
+ */
|
||||||
|
+ private final int maxBufferedBytes;
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* Default charset to use
|
||||||
|
*/
|
||||||
|
@@ -172,9 +182,34 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||||
|
* errors
|
||||||
|
*/
|
||||||
|
public HttpPostMultipartRequestDecoder(HttpDataFactory factory, HttpRequest request, Charset charset) {
|
||||||
|
+ this(factory, request, charset, HttpPostRequestDecoder.DEFAULT_MAX_FIELDS, HttpPostRequestDecoder.DEFAULT_MAX_BUFFERED_BYTES);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ *
|
||||||
|
+ * @param factory
|
||||||
|
+ * the factory used to create InterfaceHttpData
|
||||||
|
+ * @param request
|
||||||
|
+ * the request to decode
|
||||||
|
+ * @param charset
|
||||||
|
+ * the charset to use as default
|
||||||
|
+ * @param maxFields
|
||||||
|
+ * the maximum number of fields the form can have, {@code -1} to disable
|
||||||
|
+ * @param maxBufferedBytes
|
||||||
|
+ * the maximum number of bytes the decoder can buffer when decoding a field, {@code -1} to disable
|
||||||
|
+ * @throws NullPointerException
|
||||||
|
+ * for request or charset or factory
|
||||||
|
+ * @throws ErrorDataDecoderException
|
||||||
|
+ * if the default charset was wrong when decoding or other
|
||||||
|
+ * errors
|
||||||
|
+ */
|
||||||
|
+ public HttpPostMultipartRequestDecoder(HttpDataFactory factory, HttpRequest request, Charset charset,
|
||||||
|
+ int maxFields, int maxBufferedBytes) {
|
||||||
|
this.request = checkNotNull(request, "request");
|
||||||
|
this.charset = checkNotNull(charset, "charset");
|
||||||
|
this.factory = checkNotNull(factory, "factory");
|
||||||
|
+ this.maxFields = maxFields;
|
||||||
|
+ this.maxBufferedBytes = maxBufferedBytes;
|
||||||
|
// Fill default values
|
||||||
|
|
||||||
|
setMultipart(this.request.headers().get(HttpHeaderNames.CONTENT_TYPE));
|
||||||
|
@@ -333,6 +368,9 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||||
|
isLastChunk = true;
|
||||||
|
}
|
||||||
|
parseBody();
|
||||||
|
+ if (maxBufferedBytes > 0 && undecodedChunk != null && undecodedChunk.readableBytes() > maxBufferedBytes) {
|
||||||
|
+ throw new HttpPostRequestDecoder.TooLongFormFieldException();
|
||||||
|
+ }
|
||||||
|
if (undecodedChunk != null && undecodedChunk.writerIndex() > discardThreshold) {
|
||||||
|
undecodedChunk.discardReadBytes();
|
||||||
|
}
|
||||||
|
@@ -417,6 +455,9 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||||
|
if (data == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
+ if (maxFields > 0 && bodyListHttpData.size() >= maxFields) {
|
||||||
|
+ throw new HttpPostRequestDecoder.TooManyFormFieldsException();
|
||||||
|
+ }
|
||||||
|
List<InterfaceHttpData> datas = bodyMapHttpData.get(data.getName());
|
||||||
|
if (datas == null) {
|
||||||
|
datas = new ArrayList<InterfaceHttpData>(1);
|
||||||
|
diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostRequestDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostRequestDecoder.java
|
||||||
|
index 0c10626..d57b63e 100644
|
||||||
|
--- a/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostRequestDecoder.java
|
||||||
|
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostRequestDecoder.java
|
||||||
|
@@ -25,6 +25,7 @@ import io.netty.util.internal.StringUtil;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.List;
|
||||||
|
+import io.netty.util.internal.ObjectUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This decoder will decode Body and can handle POST BODY.
|
||||||
|
@@ -36,6 +37,10 @@ public class HttpPostRequestDecoder implements InterfaceHttpPostRequestDecoder {
|
||||||
|
|
||||||
|
static final int DEFAULT_DISCARD_THRESHOLD = 10 * 1024 * 1024;
|
||||||
|
|
||||||
|
+ static final int DEFAULT_MAX_FIELDS = 128;
|
||||||
|
+
|
||||||
|
+ static final int DEFAULT_MAX_BUFFERED_BYTES = 1024;
|
||||||
|
+
|
||||||
|
private final InterfaceHttpPostRequestDecoder decoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -52,6 +57,25 @@ public class HttpPostRequestDecoder implements InterfaceHttpPostRequestDecoder {
|
||||||
|
this(new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE), request, HttpConstants.DEFAULT_CHARSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ /**
|
||||||
|
+ *
|
||||||
|
+ * @param request
|
||||||
|
+ * the request to decode
|
||||||
|
+ * @param maxFields
|
||||||
|
+ * the maximum number of fields the form can have, {@code -1} to disable
|
||||||
|
+ * @param maxBufferedBytes
|
||||||
|
+ * the maximum number of bytes the decoder can buffer when decoding a field, {@code -1} to disable
|
||||||
|
+ * @throws NullPointerException
|
||||||
|
+ * for request
|
||||||
|
+ * @throws ErrorDataDecoderException
|
||||||
|
+ * if the default charset was wrong when decoding or other
|
||||||
|
+ * errors
|
||||||
|
+ */
|
||||||
|
+ public HttpPostRequestDecoder(HttpRequest request, int maxFields, int maxBufferedBytes) {
|
||||||
|
+ this(new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE), request, HttpConstants.DEFAULT_CHARSET,
|
||||||
|
+ maxFields, maxBufferedBytes);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param factory
|
||||||
|
@@ -100,6 +124,38 @@ public class HttpPostRequestDecoder implements InterfaceHttpPostRequestDecoder {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ /**
|
||||||
|
+ *
|
||||||
|
+ * @param factory
|
||||||
|
+ * the factory used to create InterfaceHttpData
|
||||||
|
+ * @param request
|
||||||
|
+ * the request to decode
|
||||||
|
+ * @param charset
|
||||||
|
+ * the charset to use as default
|
||||||
|
+ * @param maxFields
|
||||||
|
+ * the maximum number of fields the form can have, {@code -1} to disable
|
||||||
|
+ * @param maxBufferedBytes
|
||||||
|
+ * the maximum number of bytes the decoder can buffer when decoding a field, {@code -1} to disable
|
||||||
|
+ * @throws NullPointerException
|
||||||
|
+ * for request or charset or factory
|
||||||
|
+ * @throws ErrorDataDecoderException
|
||||||
|
+ * if the default charset was wrong when decoding or other
|
||||||
|
+ * errors
|
||||||
|
+ */
|
||||||
|
+ public HttpPostRequestDecoder(HttpDataFactory factory, HttpRequest request, Charset charset,
|
||||||
|
+ int maxFields, int maxBufferedBytes) {
|
||||||
|
+ ObjectUtil.checkNotNull(factory, "factory");
|
||||||
|
+ ObjectUtil.checkNotNull(request, "request");
|
||||||
|
+ ObjectUtil.checkNotNull(charset, "charset");
|
||||||
|
+
|
||||||
|
+ // Fill default values
|
||||||
|
+ if (isMultipart(request)) {
|
||||||
|
+ decoder = new HttpPostMultipartRequestDecoder(factory, request, charset, maxFields, maxBufferedBytes);
|
||||||
|
+ } else {
|
||||||
|
+ decoder = new HttpPostStandardRequestDecoder(factory, request, charset, maxFields, maxBufferedBytes);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* states follow NOTSTARTED PREAMBLE ( (HEADERDELIMITER DISPOSITION (FIELD |
|
||||||
|
* FILEUPLOAD))* (HEADERDELIMITER DISPOSITION MIXEDPREAMBLE (MIXEDDELIMITER
|
||||||
|
@@ -342,4 +398,18 @@ public class HttpPostRequestDecoder implements InterfaceHttpPostRequestDecoder {
|
||||||
|
super(msg, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Exception when the maximum number of fields for a given form is reached
|
||||||
|
+ */
|
||||||
|
+ public static final class TooManyFormFieldsException extends DecoderException {
|
||||||
|
+ private static final long serialVersionUID = 1336267941020800769L;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Exception when a field content is too long
|
||||||
|
+ */
|
||||||
|
+ public static final class TooLongFormFieldException extends DecoderException {
|
||||||
|
+ private static final long serialVersionUID = 1336267941020800769L;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostStandardRequestDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostStandardRequestDecoder.java
|
||||||
|
index ece64d8..65a9e16 100644
|
||||||
|
--- a/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostStandardRequestDecoder.java
|
||||||
|
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostStandardRequestDecoder.java
|
||||||
|
@@ -16,6 +16,7 @@
|
||||||
|
package io.netty.handler.codec.http.multipart;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
+import io.netty.handler.codec.DecoderException;
|
||||||
|
import io.netty.handler.codec.http.HttpConstants;
|
||||||
|
import io.netty.handler.codec.http.HttpContent;
|
||||||
|
import io.netty.handler.codec.http.HttpRequest;
|
||||||
|
@@ -26,6 +27,8 @@ import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.EndOfDataDec
|
||||||
|
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException;
|
||||||
|
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.MultiPartStatus;
|
||||||
|
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException;
|
||||||
|
+import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.TooManyFormFieldsException;
|
||||||
|
+import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.TooLongFormFieldException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
@@ -60,6 +63,16 @@ public class HttpPostStandardRequestDecoder implements InterfaceHttpPostRequestD
|
||||||
|
*/
|
||||||
|
private final Charset charset;
|
||||||
|
|
||||||
|
+ /**
|
||||||
|
+ * The maximum number of fields allows by the form
|
||||||
|
+ */
|
||||||
|
+ private final int maxFields;
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * The maximum number of accumulated bytes when decoding a field
|
||||||
|
+ */
|
||||||
|
+ private final int maxBufferedBytes;
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* Does the last chunk already received
|
||||||
|
*/
|
||||||
|
@@ -145,9 +158,34 @@ public class HttpPostStandardRequestDecoder implements InterfaceHttpPostRequestD
|
||||||
|
* errors
|
||||||
|
*/
|
||||||
|
public HttpPostStandardRequestDecoder(HttpDataFactory factory, HttpRequest request, Charset charset) {
|
||||||
|
+ this(factory, request, charset, HttpPostRequestDecoder.DEFAULT_MAX_FIELDS, HttpPostRequestDecoder.DEFAULT_MAX_BUFFERED_BYTES);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ *
|
||||||
|
+ * @param factory
|
||||||
|
+ * the factory used to create InterfaceHttpData
|
||||||
|
+ * @param request
|
||||||
|
+ * the request to decode
|
||||||
|
+ * @param charset
|
||||||
|
+ * the charset to use as default
|
||||||
|
+ * @param maxFields
|
||||||
|
+ * the maximum number of fields the form can have, {@code -1} to disable
|
||||||
|
+ * @param maxBufferedBytes
|
||||||
|
+ * the maximum number of bytes the decoder can buffer when decoding a field, {@code -1} to disable
|
||||||
|
+ * @throws NullPointerException
|
||||||
|
+ * for request or charset or factory
|
||||||
|
+ * @throws ErrorDataDecoderException
|
||||||
|
+ * if the default charset was wrong when decoding or other
|
||||||
|
+ * errors
|
||||||
|
+ */
|
||||||
|
+ public HttpPostStandardRequestDecoder(HttpDataFactory factory, HttpRequest request, Charset charset,
|
||||||
|
+ int maxFields, int maxBufferedBytes) {
|
||||||
|
this.request = checkNotNull(request, "request");
|
||||||
|
this.charset = checkNotNull(charset, "charset");
|
||||||
|
this.factory = checkNotNull(factory, "factory");
|
||||||
|
+ this.maxFields = maxFields;
|
||||||
|
+ this.maxBufferedBytes = maxBufferedBytes;
|
||||||
|
if (request instanceof HttpContent) {
|
||||||
|
// Offer automatically if the given request is als type of HttpContent
|
||||||
|
// See #1089
|
||||||
|
@@ -287,6 +325,9 @@ public class HttpPostStandardRequestDecoder implements InterfaceHttpPostRequestD
|
||||||
|
isLastChunk = true;
|
||||||
|
}
|
||||||
|
parseBody();
|
||||||
|
+ if (maxBufferedBytes > 0 && undecodedChunk != null && undecodedChunk.readableBytes() > maxBufferedBytes) {
|
||||||
|
+ throw new TooLongFormFieldException();
|
||||||
|
+ }
|
||||||
|
if (undecodedChunk != null && undecodedChunk.writerIndex() > discardThreshold) {
|
||||||
|
undecodedChunk.discardReadBytes();
|
||||||
|
}
|
||||||
|
@@ -367,6 +408,9 @@ public class HttpPostStandardRequestDecoder implements InterfaceHttpPostRequestD
|
||||||
|
if (data == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
+ if (maxFields > 0 && bodyListHttpData.size() >= maxFields) {
|
||||||
|
+ throw new TooManyFormFieldsException();
|
||||||
|
+ }
|
||||||
|
List<InterfaceHttpData> datas = bodyMapHttpData.get(data.getName());
|
||||||
|
if (datas == null) {
|
||||||
|
datas = new ArrayList<InterfaceHttpData>(1);
|
||||||
|
diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/multipart/HttpPostRequestDecoderTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/multipart/HttpPostRequestDecoderTest.java
|
||||||
|
index 1334107..bdc5fd7 100644
|
||||||
|
--- a/codec-http/src/test/java/io/netty/handler/codec/http/multipart/HttpPostRequestDecoderTest.java
|
||||||
|
+++ b/codec-http/src/test/java/io/netty/handler/codec/http/multipart/HttpPostRequestDecoderTest.java
|
||||||
|
@@ -19,6 +19,7 @@ import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.ByteBufAllocator;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import io.netty.buffer.UnpooledByteBufAllocator;
|
||||||
|
+import io.netty.handler.codec.DecoderException;
|
||||||
|
import io.netty.handler.codec.DecoderResult;
|
||||||
|
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
||||||
|
import io.netty.handler.codec.http.DefaultHttpContent;
|
||||||
|
@@ -491,4 +492,106 @@ public class HttpPostRequestDecoderTest {
|
||||||
|
content.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ @Test
|
||||||
|
+ public void testTooManyFormFieldsPostStandardDecoder() {
|
||||||
|
+ HttpRequest req = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "/");
|
||||||
|
+
|
||||||
|
+ HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(req, 1024, -1);
|
||||||
|
+
|
||||||
|
+ int num = 0;
|
||||||
|
+ while (true) {
|
||||||
|
+ try {
|
||||||
|
+ decoder.offer(new DefaultHttpContent(Unpooled.wrappedBuffer("foo=bar&".getBytes())));
|
||||||
|
+ } catch (DecoderException e) {
|
||||||
|
+ assertEquals(HttpPostRequestDecoder.TooManyFormFieldsException.class, e.getClass());
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ assertTrue(num++ < 1024);
|
||||||
|
+ }
|
||||||
|
+ assertEquals(1024, num);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Test
|
||||||
|
+ public void testTooManyFormFieldsPostMultipartDecoder() {
|
||||||
|
+ HttpRequest req = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "/");
|
||||||
|
+ req.headers().add("Content-Type", "multipart/form-data;boundary=be38b42a9ad2713f");
|
||||||
|
+
|
||||||
|
+ HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(req, 1024, -1);
|
||||||
|
+ decoder.offer(new DefaultHttpContent(Unpooled.wrappedBuffer("--be38b42a9ad2713f\n".getBytes())));
|
||||||
|
+
|
||||||
|
+ int num = 0;
|
||||||
|
+ while (true) {
|
||||||
|
+ try {
|
||||||
|
+ byte[] bodyBytes = ("content-disposition: form-data; name=\"title\"\n" +
|
||||||
|
+ "content-length: 10\n" +
|
||||||
|
+ "content-type: text/plain; charset=UTF-8\n" +
|
||||||
|
+ "\n" +
|
||||||
|
+ "bar-stream\n" +
|
||||||
|
+ "--be38b42a9ad2713f\n").getBytes();
|
||||||
|
+ ByteBuf content = Unpooled.wrappedBuffer(bodyBytes);
|
||||||
|
+ decoder.offer(new DefaultHttpContent(content));
|
||||||
|
+ } catch (DecoderException e) {
|
||||||
|
+ assertEquals(HttpPostRequestDecoder.TooManyFormFieldsException.class, e.getClass());
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ assertTrue(num++ < 1024);
|
||||||
|
+ }
|
||||||
|
+ assertEquals(1024, num);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Test
|
||||||
|
+ public void testTooLongFormFieldStandardDecoder() {
|
||||||
|
+ HttpRequest req = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "/");
|
||||||
|
+
|
||||||
|
+ HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(req, -1, 16 * 1024);
|
||||||
|
+
|
||||||
|
+ try {
|
||||||
|
+ decoder.offer(new DefaultHttpContent(Unpooled.wrappedBuffer(new byte[16 * 1024 + 1])));
|
||||||
|
+ fail();
|
||||||
|
+ } catch (DecoderException e) {
|
||||||
|
+ assertEquals(HttpPostRequestDecoder.TooLongFormFieldException.class, e.getClass());
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Test
|
||||||
|
+ public void testFieldGreaterThanMaxBufferedBytesStandardDecoder() {
|
||||||
|
+ HttpRequest req = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "/");
|
||||||
|
+
|
||||||
|
+ HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(req, -1, 6);
|
||||||
|
+
|
||||||
|
+ decoder.offer(new DefaultHttpContent(Unpooled.wrappedBuffer("foo=bar".getBytes())));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Test
|
||||||
|
+ public void testTooLongFormFieldMultipartDecoder() {
|
||||||
|
+ HttpRequest req = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "/");
|
||||||
|
+ req.headers().add("Content-Type", "multipart/form-data;boundary=be38b42a9ad2713f");
|
||||||
|
+
|
||||||
|
+ HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(req, -1, 16 * 1024);
|
||||||
|
+
|
||||||
|
+ try {
|
||||||
|
+ decoder.offer(new DefaultHttpContent(Unpooled.wrappedBuffer(new byte[16 * 1024 + 1])));
|
||||||
|
+ fail();
|
||||||
|
+ } catch (DecoderException e) {
|
||||||
|
+ assertEquals(HttpPostRequestDecoder.TooLongFormFieldException.class, e.getClass());
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Test
|
||||||
|
+ public void testFieldGreaterThanMaxBufferedBytesMultipartDecoder() {
|
||||||
|
+ HttpRequest req = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "/");
|
||||||
|
+ req.headers().add("Content-Type", "multipart/form-data;boundary=be38b42a9ad2713f");
|
||||||
|
+
|
||||||
|
+ byte[] bodyBytes = ("content-disposition: form-data; name=\"title\"\n" +
|
||||||
|
+ "content-length: 10\n" +
|
||||||
|
+ "content-type: text/plain; charset=UTF-8\n" +
|
||||||
|
+ "\n" +
|
||||||
|
+ "bar-stream\n" +
|
||||||
|
+ "--be38b42a9ad2713f\n").getBytes();
|
||||||
|
+
|
||||||
|
+ HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(req, -1, bodyBytes.length - 1);
|
||||||
|
+
|
||||||
|
+ decoder.offer(new DefaultHttpContent(Unpooled.wrappedBuffer(bodyBytes)));
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
--
|
||||||
|
2.47.0
|
||||||
|
|
||||||
30
fix-strip.patch
Normal file
30
fix-strip.patch
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
diff -Nur a/transport-native-epoll/pom.xml b/transport-native-epoll/pom.xml
|
||||||
|
--- a/transport-native-epoll/pom.xml 2023-03-05 15:42:40.947323733 +0800
|
||||||
|
+++ b/transport-native-epoll/pom.xml 2023-03-05 15:45:43.877975494 +0800
|
||||||
|
@@ -32,7 +32,7 @@
|
||||||
|
<unix.common.lib.dir>${project.build.directory}/unix-common-lib</unix.common.lib.dir>
|
||||||
|
<unix.common.lib.unpacked.dir>${unix.common.lib.dir}/META-INF/native/lib</unix.common.lib.unpacked.dir>
|
||||||
|
<unix.common.include.unpacked.dir>${unix.common.lib.dir}/META-INF/native/include</unix.common.include.unpacked.dir>
|
||||||
|
- <jni.compiler.args.ldflags>LDFLAGS=-L${unix.common.lib.unpacked.dir} -Wl,--no-as-needed -lrt -Wl,--whole-archive -l${unix.common.lib.name} -Wl,--no-whole-archive</jni.compiler.args.ldflags>
|
||||||
|
+ <jni.compiler.args.ldflags>LDFLAGS=-L${unix.common.lib.unpacked.dir} -Wl,--no-as-needed -lrt -Wl,--whole-archive -Wl,-s -l${unix.common.lib.name} -Wl,--no-whole-archive</jni.compiler.args.ldflags>
|
||||||
|
<skipTests>true</skipTests>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
@@ -221,7 +221,7 @@
|
||||||
|
<value>${linux.sendmmsg.support}${glibc.sendmmsg.support}</value>
|
||||||
|
<!-- If glibc and linux kernel are both not sufficient...then define the CFLAGS -->
|
||||||
|
<regex>.*IO_NETTY_SENDMSSG_NOT_FOUND.*</regex>
|
||||||
|
- <replacement>CFLAGS=-O3 -DIO_NETTY_SENDMMSG_NOT_FOUND -Werror -fno-omit-frame-pointer -Wunused-variable -I${unix.common.include.unpacked.dir}</replacement>
|
||||||
|
+ <replacement>CFLAGS=-O3 -DIO_NETTY_SENDMMSG_NOT_FOUND -Werror -fno-omit-frame-pointer -Wunused-variable -Wl,-s -I${unix.common.include.unpacked.dir}</replacement>
|
||||||
|
<failIfNoMatch>false</failIfNoMatch>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
@@ -237,7 +237,7 @@
|
||||||
|
<value>${jni.compiler.args.cflags}</value>
|
||||||
|
<!-- If glibc and linux kernel are both not sufficient...then define the CFLAGS -->
|
||||||
|
<regex>^((?!CFLAGS=).)*$</regex>
|
||||||
|
- <replacement>CFLAGS=-O3 -Werror -fno-omit-frame-pointer -Wunused-variable -I${unix.common.include.unpacked.dir}</replacement>
|
||||||
|
+ <replacement>CFLAGS=-O3 -Werror -fno-omit-frame-pointer -Wunused-variable -Wl,-s -I${unix.common.include.unpacked.dir}</replacement>
|
||||||
|
<failIfNoMatch>false</failIfNoMatch>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
Binary file not shown.
35
netty.spec
35
netty.spec
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Name: netty
|
Name: netty
|
||||||
Version: 4.1.13
|
Version: 4.1.13
|
||||||
Release: 15
|
Release: 22
|
||||||
Summary: Asynchronous event-driven network application Java framework
|
Summary: Asynchronous event-driven network application Java framework
|
||||||
License: ASL 2.0
|
License: ASL 2.0
|
||||||
URL: https://netty.io/
|
URL: https://netty.io/
|
||||||
@ -29,6 +29,10 @@ Patch0017: CVE-2021-37136.patch
|
|||||||
Patch0018: CVE-2021-37137.patch
|
Patch0018: CVE-2021-37137.patch
|
||||||
Patch0019: CVE-2021-43797-pre.patch
|
Patch0019: CVE-2021-43797-pre.patch
|
||||||
Patch0020: CVE-2021-43797.patch
|
Patch0020: CVE-2021-43797.patch
|
||||||
|
Patch0021: fix-strip.patch
|
||||||
|
# https://github.com/netty/netty/commit/cd91cf3c99123bd1e53fd6a1de0e3d1922f05bb2
|
||||||
|
Patch0022: CVE-2022-41881.patch
|
||||||
|
Patch0023: CVE-2024-29025.patch
|
||||||
|
|
||||||
BuildRequires: maven-local mvn(ant-contrib:ant-contrib)
|
BuildRequires: maven-local mvn(ant-contrib:ant-contrib)
|
||||||
BuildRequires: mvn(com.jcraft:jzlib) mvn(commons-logging:commons-logging)
|
BuildRequires: mvn(com.jcraft:jzlib) mvn(commons-logging:commons-logging)
|
||||||
@ -153,13 +157,34 @@ export CFLAGS="$RPM_OPT_FLAGS" LDFLAGS="$RPM_LD_FLAGS"
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
* Fri Apr 22 2022 wangkai <wangkai385@h-partners.com> - 4.1.13-15
|
* Tue Nov 12 2024 yaoxin <yao_xin001@hoperun.com> - 4.1.13-22
|
||||||
- Remove lz4-java dependency and fix CVE-2021-43797
|
- Fix CVE-2024-29025
|
||||||
|
|
||||||
* Wed Oct 27 2021 wangkai <wangkai385@huawei.com> - 4.1.13-14
|
* Wed Dec 13 2023 yaoxin <yao_xin001@hoperun.com> - 4.1.13-21
|
||||||
|
- Fix CVE-2022-41881
|
||||||
|
|
||||||
|
* Sun Mar 05 2023 wulei <wulei80@h-partners.com> - 4.1.13-20
|
||||||
|
- Add strip
|
||||||
|
|
||||||
|
* Wed Nov 9 2022 liyanan <liyanan32@h-partners.com> - 4.1.13-19
|
||||||
|
- Change source
|
||||||
|
|
||||||
|
* Mon Mar 07 2022 wangkai <wangkai385@huawei.com> - 4.1.13-18
|
||||||
|
- Remove lz4-java dependency
|
||||||
|
|
||||||
|
* Fri Dec 24 2021 wangkai <wangkai385@huawei.com> - 4.1.13-17
|
||||||
|
- This package depends on log4j.After the log4j vulnerability CVE-2021-45105 is fixed,the version needs to be rebuild.
|
||||||
|
|
||||||
|
* Fri Dec 17 2021 yaoxin <yaoxin30@huawei.com> - 4.1.13-16
|
||||||
|
- Fix CVE-2021-43797
|
||||||
|
|
||||||
|
* Wed Oct 27 2021 wangkai <wangkai385@huawei.com> - 4.1.13-15
|
||||||
- fix CVE-2021-37136 CVE-2021-37137
|
- fix CVE-2021-37136 CVE-2021-37137
|
||||||
|
|
||||||
* Mon Aug 16 2021 wangyue <wangyue92@qq.com> - 4.1.13-13
|
* Mon Aug 16 2021 wangyue <wangyue92@qq.com> - 4.1.13-14
|
||||||
|
- fix build error
|
||||||
|
|
||||||
|
* Sat Aug 14 2021 wangyue <wangyue92@qq.com> - 4.1.13-13
|
||||||
- fix build error
|
- fix build error
|
||||||
|
|
||||||
* Tue Apr 06 2021 wangxiao <wangxiao65@huawei.com> - 4.1.13-12
|
* Tue Apr 06 2021 wangxiao <wangxiao65@huawei.com> - 4.1.13-12
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user