[Git][java-team/netty][master] CVE-2025-55163

Bastien Roucariès (@rouca) gitlab at salsa.debian.org
Sat Nov 8 19:09:04 GMT 2025



Bastien Roucariès pushed to branch master at Debian Java Maintainers / netty


Commits:
d7548a5d by Bastien Roucariès at 2025-11-05T22:36:25+01:00
CVE-2025-55163

- - - - -


4 changed files:

- debian/changelog
- + debian/patches/CVE-2025-55163_1.patch
- + debian/patches/CVE-2025-55163_2.patch
- debian/patches/series


Changes:

=====================================
debian/changelog
=====================================
@@ -1,6 +1,12 @@
 netty (1:4.1.48-11) unstable; urgency=high
 
   * Team upload
+  * Fix CVE-2025-55163 (Closes: #1111105)
+    Netty is vulnerable to MadeYouReset DDoS.
+    This is a logical vulnerability in the HTTP/2 protocol,
+    that uses malformed HTTP/2 control frames in order to break
+    the max concurrent streams limit, which results in resource
+    exhaustion and distributed denial of service.
   * Fix CVE-2025-59419 (Closes: #1118282)
     SMTP Command Injection Vulnerability Allowing Email Forgery
     An SMTP Command Injection (CRLF Injection) vulnerability


=====================================
debian/patches/CVE-2025-55163_1.patch
=====================================
@@ -0,0 +1,149 @@
+From: Norman Maurer <norman_maurer at apple.com>
+Date: Mon, 28 Jul 2025 08:25:35 -1000
+Subject: =?utf-8?q?HTTP2=3A_Http2ConnectionHandler_should_always_use_Http2C?=
+ =?utf-8?q?onnectionEncode=E2=80=A6_=28=2315518=29?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: 8bit
+
+…r (#15516)
+
+Motivation:
+
+We sometimes directly used the Http2FrameWriter which is not correct as
+someone might have supplied a custom Http2ConnectionEncoder
+
+Modifications:
+
+Use Http2ConnectionEncoder when writing RST frames
+
+Result:
+
+Don't by-pass Http2ConnectionEncoder
+
+origin: backport, https://github.com/netty/netty/commit/be53dc3c9acd9af2e20d0c3c07cd77115a594cf1
+bug: https://github.com/netty/netty/security/advisories/GHSA-prj3-ccx8-p6x4
+bug-github-pull: https://github.com/netty/netty/pull/15516
+---
+ .../codec/http2/Http2ConnectionHandler.java        |  6 +++---
+ .../codec/http2/Http2ConnectionHandlerTest.java    | 22 +++++++++++-----------
+ 2 files changed, 14 insertions(+), 14 deletions(-)
+
+diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandler.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandler.java
+index 909ca74..0dd73cb 100644
+--- a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandler.java
++++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandler.java
+@@ -706,7 +706,7 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
+                 try {
+                     stream = encoder.connection().remote().createStream(streamId, true);
+                 } catch (Http2Exception e) {
+-                    resetUnknownStream(ctx, streamId, http2Ex.error().code(), ctx.newPromise());
++                    encoder().writeRstStream(ctx, streamId, http2Ex.error().code(), ctx.newPromise());
+                     return;
+                 }
+             }
+@@ -723,10 +723,10 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
+ 
+         if (stream == null) {
+             if (!outbound || connection().local().mayHaveCreatedStream(streamId)) {
+-                resetUnknownStream(ctx, streamId, http2Ex.error().code(), ctx.newPromise());
++                encoder().writeRstStream(ctx, streamId, http2Ex.error().code(), ctx.newPromise());
+             }
+         } else {
+-            resetStream(ctx, stream, http2Ex.error().code(), ctx.newPromise());
++            encoder().writeRstStream(ctx, streamId, http2Ex.error().code(), ctx.newPromise());
+         }
+     }
+ 
+diff --git a/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2ConnectionHandlerTest.java b/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2ConnectionHandlerTest.java
+index 0143edc..90b0ef6 100644
+--- a/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2ConnectionHandlerTest.java
++++ b/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2ConnectionHandlerTest.java
+@@ -403,7 +403,7 @@ public class Http2ConnectionHandlerTest {
+         when(connection.isServer()).thenReturn(true);
+         when(stream.isHeadersSent()).thenReturn(false);
+         when(remote.lastStreamCreated()).thenReturn(STREAM_ID);
+-        when(frameWriter.writeRstStream(eq(ctx), eq(STREAM_ID),
++        when(encoder.writeRstStream(eq(ctx), eq(STREAM_ID),
+                 eq(PROTOCOL_ERROR.code()), eq(promise))).thenReturn(future);
+ 
+         handler.exceptionCaught(ctx, e);
+@@ -413,7 +413,7 @@ public class Http2ConnectionHandlerTest {
+                 captor.capture(), eq(padding), eq(true), eq(promise));
+         Http2Headers headers = captor.getValue();
+         assertEquals(HttpResponseStatus.REQUEST_HEADER_FIELDS_TOO_LARGE.codeAsText(), headers.status());
+-        verify(frameWriter).writeRstStream(ctx, STREAM_ID, PROTOCOL_ERROR.code(), promise);
++        verify(encoder).writeRstStream(ctx, STREAM_ID, PROTOCOL_ERROR.code(), promise);
+     }
+ 
+     @Test
+@@ -427,14 +427,14 @@ public class Http2ConnectionHandlerTest {
+         when(connection.isServer()).thenReturn(true);
+         when(stream.isHeadersSent()).thenReturn(false);
+         when(remote.lastStreamCreated()).thenReturn(STREAM_ID);
+-        when(frameWriter.writeRstStream(eq(ctx), eq(STREAM_ID),
++        when(encoder.writeRstStream(eq(ctx), eq(STREAM_ID),
+             eq(PROTOCOL_ERROR.code()), eq(promise))).thenReturn(future);
+ 
+         handler.exceptionCaught(ctx, e);
+ 
+         verify(encoder, never()).writeHeaders(eq(ctx), eq(STREAM_ID),
+             any(Http2Headers.class), eq(padding), eq(true), eq(promise));
+-        verify(frameWriter).writeRstStream(ctx, STREAM_ID, PROTOCOL_ERROR.code(), promise);
++        verify(encoder).writeRstStream(ctx, STREAM_ID, PROTOCOL_ERROR.code(), promise);
+     }
+ 
+     @Test
+@@ -448,14 +448,14 @@ public class Http2ConnectionHandlerTest {
+         when(connection.isServer()).thenReturn(false);
+         when(stream.isHeadersSent()).thenReturn(false);
+         when(remote.lastStreamCreated()).thenReturn(STREAM_ID);
+-        when(frameWriter.writeRstStream(eq(ctx), eq(STREAM_ID),
++        when(encoder.writeRstStream(eq(ctx), eq(STREAM_ID),
+                 eq(PROTOCOL_ERROR.code()), eq(promise))).thenReturn(future);
+ 
+         handler.exceptionCaught(ctx, e);
+ 
+         verify(encoder, never()).writeHeaders(eq(ctx), eq(STREAM_ID),
+                 any(Http2Headers.class), eq(padding), eq(true), eq(promise));
+-        verify(frameWriter).writeRstStream(ctx, STREAM_ID, PROTOCOL_ERROR.code(), promise);
++        verify(encoder).writeRstStream(ctx, STREAM_ID, PROTOCOL_ERROR.code(), promise);
+     }
+ 
+     @Test
+@@ -484,14 +484,14 @@ public class Http2ConnectionHandlerTest {
+         when(connection.isServer()).thenReturn(true);
+         when(stream.isHeadersSent()).thenReturn(true);
+         when(remote.lastStreamCreated()).thenReturn(STREAM_ID);
+-        when(frameWriter.writeRstStream(eq(ctx), eq(STREAM_ID),
++        when(encoder.writeRstStream(eq(ctx), eq(STREAM_ID),
+             eq(PROTOCOL_ERROR.code()), eq(promise))).thenReturn(future);
+         handler.exceptionCaught(ctx, e);
+ 
+         verify(encoder, never()).writeHeaders(eq(ctx), eq(STREAM_ID),
+             any(Http2Headers.class), eq(padding), eq(true), eq(promise));
+ 
+-        verify(frameWriter).writeRstStream(ctx, STREAM_ID, PROTOCOL_ERROR.code(), promise);
++        verify(encoder).writeRstStream(ctx, STREAM_ID, PROTOCOL_ERROR.code(), promise);
+     }
+ 
+     @Test
+@@ -508,15 +508,15 @@ public class Http2ConnectionHandlerTest {
+         when(connection.isServer()).thenReturn(true);
+         when(stream.isHeadersSent()).thenReturn(false);
+         when(remote.lastStreamCreated()).thenReturn(STREAM_ID);
+-        when(frameWriter.writeRstStream(eq(ctx), eq(STREAM_ID),
+-            eq(Http2Error.PROTOCOL_ERROR.code()), eq(promise))).thenReturn(future);
++        when(encoder.writeRstStream(eq(ctx), eq(STREAM_ID),
++            eq(PROTOCOL_ERROR.code()), eq(promise))).thenReturn(future);
+         handler.exceptionCaught(ctx, e);
+ 
+         verify(remote).createStream(STREAM_ID, true);
+         verify(encoder).writeHeaders(eq(ctx), eq(STREAM_ID),
+             any(Http2Headers.class), eq(padding), eq(true), eq(promise));
+ 
+-        verify(frameWriter).writeRstStream(ctx, STREAM_ID, PROTOCOL_ERROR.code(), promise);
++        verify(encoder).writeRstStream(ctx, STREAM_ID, PROTOCOL_ERROR.code(), promise);
+     }
+ 
+     @Test


=====================================
debian/patches/CVE-2025-55163_2.patch
=====================================
@@ -0,0 +1,401 @@
+From: Norman Maurer <norman_maurer at apple.com>
+Date: Wed, 13 Aug 2025 14:14:00 +0200
+Subject: [PATCH] Merge commit from fork
+
+* Enforce the maximum number of RST frames that can be sent in window of time
+
+Motivation:
+
+A remote peer might be able to trigger an instance to generate and send RST frames by sending invalid frames on an existing stream. This can cause high resource usage and so might be abused by a remote peer.
+
+Modifications:
+
+Limit the number of RSTs that we allow to be generated and so send in a specific time window. If this limit is reached a GO_AWAY frame is send and the connection be closed.
+
+Result:
+
+Fix high resource usage that can be caused by a remote peer by trigger RST frames
+
+* Adjust testing
+
+* Address comments
+
+origin: backport, https://github.com/netty/netty/commit/009bd17b38a39fb1eecf9d22ea8ae8108afaac59
+bug: https://github.com/netty/netty/security/advisories/GHSA-prj3-ccx8-p6x4
+---
+ .../AbstractHttp2ConnectionHandlerBuilder.java     |  56 +++++-
+ .../codec/http2/Http2ConnectionHandlerBuilder.java |   8 +
+ .../codec/http2/Http2FrameCodecBuilder.java        |   6 +
+ .../codec/http2/Http2MultiplexCodecBuilder.java    |   6 +
+ .../http2/Http2MaxRstFrameLimitEncoderTest.java    | 213 +++++++++++++++++++++
+ 5 files changed, 282 insertions(+), 7 deletions(-)
+ create mode 100644 codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MaxRstFrameLimitEncoderTest.java
+
+diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/AbstractHttp2ConnectionHandlerBuilder.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/AbstractHttp2ConnectionHandlerBuilder.java
+index a904310..157739d 100644
+--- a/codec-http2/src/main/java/io/netty/handler/codec/http2/AbstractHttp2ConnectionHandlerBuilder.java
++++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/AbstractHttp2ConnectionHandlerBuilder.java
+@@ -109,9 +109,10 @@ public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2Conne
+     private boolean autoAckPingFrame = true;
+     private int maxQueuedControlFrames = Http2CodecUtil.DEFAULT_MAX_QUEUED_CONTROL_FRAMES;
+     private int maxConsecutiveEmptyFrames = 2;
+-    private int maxRstFramesPerWindow = 200;
+-    private int secondsPerWindow = 30;
+-
++    private Integer maxDecodedRstFramesPerWindow;
++    private int maxDecodedRstFramesSecondsPerWindow = 30;
++    private Integer maxEncodedRstFramesPerWindow;
++    private int maxEncodedRstFramesSecondsPerWindow = 30;
+     /**
+      * Sets the {@link Http2Settings} to use for the initial connection settings exchange.
+      */
+@@ -444,9 +445,24 @@ public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2Conne
+      */
+     protected B decoderEnforceMaxRstFramesPerWindow(int maxRstFramesPerWindow, int secondsPerWindow) {
+         enforceNonCodecConstraints("decoderEnforceMaxRstFramesPerWindow");
+-        this.maxRstFramesPerWindow = checkPositiveOrZero(
++        this.maxDecodedRstFramesPerWindow = checkPositiveOrZero(
++                maxRstFramesPerWindow, "maxRstFramesPerWindow");
++        this.maxDecodedRstFramesSecondsPerWindow = checkPositiveOrZero(secondsPerWindow, "secondsPerWindow");
++        return self();
++    }
++
++    /**
++     * Sets the maximum number RST frames that are allowed per window before
++     * the connection is closed. This allows to protect against the remote peer that will trigger us to generate a flood
++     * of RST frames and so use up a lot of CPU.
++     *
++     * {@code 0} for any of the parameters means no protection should be applied.
++     */
++    protected B encoderEnforceMaxRstFramesPerWindow(int maxRstFramesPerWindow, int secondsPerWindow) {
++        enforceNonCodecConstraints("decoderEnforceMaxRstFramesPerWindow");
++        this.maxEncodedRstFramesPerWindow = checkPositiveOrZero(
+                 maxRstFramesPerWindow, "maxRstFramesPerWindow");
+-        this.secondsPerWindow = checkPositiveOrZero(secondsPerWindow, "secondsPerWindow");
++        this.maxEncodedRstFramesSecondsPerWindow = checkPositiveOrZero(secondsPerWindow, "secondsPerWindow");
+         return self();
+     }
+ 
+@@ -541,6 +557,21 @@ public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2Conne
+         if (maxQueuedControlFrames != 0) {
+             encoder = new Http2ControlFrameLimitEncoder(encoder, maxQueuedControlFrames);
+         }
++        final int maxEncodedRstFrames;
++        if (maxEncodedRstFramesPerWindow == null) {
++            // Only enable by default on the server.
++            if (isServer()) {
++                maxEncodedRstFrames = DEFAULT_MAX_RST_FRAMES_PER_CONNECTION_FOR_SERVER;
++            } else {
++                maxEncodedRstFrames = 0;
++            }
++        } else {
++            maxEncodedRstFrames = maxEncodedRstFramesPerWindow;
++        }
++        if (maxEncodedRstFrames > 0 && maxEncodedRstFramesSecondsPerWindow > 0) {
++            encoder = new Http2MaxRstFrameLimitEncoder(
++                    encoder, maxEncodedRstFrames, maxEncodedRstFramesSecondsPerWindow);
++        }
+         if (encoderEnforceMaxConcurrentStreams) {
+             if (connection.isServer()) {
+                 encoder.close();
+@@ -562,8 +593,19 @@ public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2Conne
+         if (maxConsecutiveEmptyDataFrames > 0) {
+             decoder = new Http2EmptyDataFrameConnectionDecoder(decoder, maxConsecutiveEmptyDataFrames);
+         }
+-        if (maxRstFramesPerWindow > 0 && secondsPerWindow > 0) {
+-            decoder = new Http2MaxRstFrameDecoder(decoder, maxRstFramesPerWindow, secondsPerWindow);
++        final int maxDecodedRstFrames;
++        if (maxDecodedRstFramesPerWindow == null) {
++            // Only enable by default on the server.
++            if (isServer()) {
++                maxDecodedRstFrames = DEFAULT_MAX_RST_FRAMES_PER_CONNECTION_FOR_SERVER;
++            } else {
++                maxDecodedRstFrames = 0;
++            }
++        } else {
++            maxDecodedRstFrames = maxDecodedRstFramesPerWindow;
++        }
++        if (maxDecodedRstFrames > 0 && maxDecodedRstFramesSecondsPerWindow > 0) {
++            decoder = new Http2MaxRstFrameDecoder(decoder, maxDecodedRstFrames, maxDecodedRstFramesSecondsPerWindow);
+         }
+         final T handler;
+         try {
+diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandlerBuilder.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandlerBuilder.java
+index c6d1ce7..1d2ac71 100644
+--- a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandlerBuilder.java
++++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandlerBuilder.java
+@@ -19,6 +19,8 @@ package io.netty.handler.codec.http2;
+ import io.netty.handler.codec.http2.Http2HeadersEncoder.SensitivityDetector;
+ import io.netty.util.internal.UnstableApi;
+ 
++import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
++
+ /**
+  * Builder which builds {@link Http2ConnectionHandler} objects.
+  */
+@@ -98,6 +100,12 @@ public final class Http2ConnectionHandlerBuilder
+         return super.decoupleCloseAndGoAway(decoupleCloseAndGoAway);
+     }
+ 
++    @Override
++    public Http2ConnectionHandlerBuilder encoderEnforceMaxRstFramesPerWindow(
++            int maxRstFramesPerWindow, int secondsPerWindow) {
++        return super.encoderEnforceMaxRstFramesPerWindow(maxRstFramesPerWindow, secondsPerWindow);
++    }
++
+     @Override
+     public Http2ConnectionHandler build() {
+         return super.build();
+diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2FrameCodecBuilder.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2FrameCodecBuilder.java
+index 241c9c5..b73413f 100644
+--- a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2FrameCodecBuilder.java
++++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2FrameCodecBuilder.java
+@@ -183,6 +183,12 @@ public class Http2FrameCodecBuilder extends
+         return super.decoderEnforceMaxRstFramesPerWindow(maxConsecutiveEmptyFrames, secondsPerWindow);
+     }
+ 
++    @Override
++    public Http2FrameCodecBuilder encoderEnforceMaxRstFramesPerWindow(
++            int maxRstFramesPerWindow, int secondsPerWindow) {
++        return super.encoderEnforceMaxRstFramesPerWindow(maxRstFramesPerWindow, secondsPerWindow);
++    }
++
+     /**
+      * Build a {@link Http2FrameCodec} object.
+      */
+diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MultiplexCodecBuilder.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MultiplexCodecBuilder.java
+index a3c0bed..34fa5e8 100644
+--- a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MultiplexCodecBuilder.java
++++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MultiplexCodecBuilder.java
+@@ -212,6 +212,12 @@ public class Http2MultiplexCodecBuilder
+         return super.decoderEnforceMaxRstFramesPerWindow(maxConsecutiveEmptyFrames, secondsPerWindow);
+     }
+ 
++    @Override
++    public Http2MultiplexCodecBuilder encoderEnforceMaxRstFramesPerWindow(
++            int maxRstFramesPerWindow, int secondsPerWindow) {
++        return super.encoderEnforceMaxRstFramesPerWindow(maxRstFramesPerWindow, secondsPerWindow);
++    }
++
+     @Override
+     public Http2MultiplexCodec build() {
+         Http2FrameWriter frameWriter = this.frameWriter;
+diff --git a/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MaxRstFrameLimitEncoderTest.java b/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MaxRstFrameLimitEncoderTest.java
+new file mode 100644
+index 0000000..24c40fe
+--- /dev/null
++++ b/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MaxRstFrameLimitEncoderTest.java
+@@ -0,0 +1,213 @@
++/*
++ * Copyright 2019 The Netty Project
++ *
++ * The Netty Project licenses this file to you under the Apache License, version 2.0 (the
++ * "License"); you may not use this file except in compliance with the License. You may obtain a
++ * copy of the License at:
++ *
++ * https://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software distributed under the License
++ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
++ * or implied. See the License for the specific language governing permissions and limitations under
++ * the License.
++ */
++
++package io.netty.handler.codec.http2;
++
++import io.netty.buffer.ByteBuf;
++import io.netty.buffer.UnpooledByteBufAllocator;
++import io.netty.channel.Channel;
++import io.netty.channel.ChannelConfig;
++import io.netty.channel.ChannelFuture;
++import io.netty.channel.ChannelHandlerContext;
++import io.netty.channel.ChannelMetadata;
++import io.netty.channel.ChannelPromise;
++import io.netty.channel.DefaultChannelPromise;
++import io.netty.channel.DefaultMessageSizeEstimator;
++import io.netty.util.ReferenceCountUtil;
++import io.netty.util.concurrent.EventExecutor;
++import io.netty.util.concurrent.ImmediateEventExecutor;
++import org.junit.jupiter.api.AfterEach;
++import org.junit.jupiter.api.BeforeEach;
++import org.junit.jupiter.api.Test;
++import org.junit.jupiter.params.ParameterizedTest;
++import org.junit.jupiter.params.provider.EnumSource;
++import org.junit.jupiter.params.provider.ValueSource;
++import org.mockito.Mock;
++import org.mockito.MockitoAnnotations;
++import org.mockito.invocation.InvocationOnMock;
++import org.mockito.stubbing.Answer;
++
++import java.util.ArrayDeque;
++import java.util.Queue;
++
++import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_MAX_FRAME_SIZE;
++import static io.netty.handler.codec.http2.Http2Error.CANCEL;
++import static io.netty.handler.codec.http2.Http2Error.ENHANCE_YOUR_CALM;
++import static io.netty.handler.codec.http2.Http2Error.NO_ERROR;
++import static org.junit.jupiter.api.Assertions.assertTrue;
++import static org.mockito.Mockito.any;
++import static org.mockito.Mockito.anyInt;
++import static org.mockito.Mockito.anyLong;
++import static org.mockito.Mockito.atLeast;
++import static org.mockito.Mockito.doAnswer;
++import static org.mockito.Mockito.eq;
++import static org.mockito.Mockito.mock;
++import static org.mockito.Mockito.times;
++import static org.mockito.Mockito.verify;
++import static org.mockito.Mockito.when;
++
++/**
++ * Tests for {@link Http2MaxRstFrameLimitEncoder}.
++ */
++public class Http2MaxRstFrameLimitEncoderTest {
++
++    private Http2MaxRstFrameLimitEncoder encoder;
++
++    @Mock
++    private Http2FrameWriter writer;
++
++    @Mock
++    private ChannelHandlerContext ctx;
++
++    @Mock
++    private Channel channel;
++
++    @Mock
++    private Channel.Unsafe unsafe;
++
++    @Mock
++    private ChannelConfig config;
++
++    @Mock
++    private EventExecutor executor;
++
++    private final Queue<ChannelPromise> goAwayPromises = new ArrayDeque<ChannelPromise>();
++
++    /**
++     * Init fields and do mocking.
++     */
++    @BeforeEach
++    public void setup() throws Exception {
++        MockitoAnnotations.initMocks(this);
++        Http2FrameWriter.Configuration configuration = mock(Http2FrameWriter.Configuration.class);
++        Http2FrameSizePolicy frameSizePolicy = mock(Http2FrameSizePolicy.class);
++        when(writer.configuration()).thenReturn(configuration);
++        when(configuration.frameSizePolicy()).thenReturn(frameSizePolicy);
++        when(frameSizePolicy.maxFrameSize()).thenReturn(DEFAULT_MAX_FRAME_SIZE);
++
++        when(writer.writeRstStream(eq(ctx), anyInt(), anyLong(), any(ChannelPromise.class)))
++                .thenAnswer(new Answer<ChannelFuture>() {
++                    @Override
++                    public ChannelFuture answer(InvocationOnMock invocationOnMock) {
++                        return handlePromise(invocationOnMock, 3);
++                    }
++                });
++        when(writer.writeGoAway(any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ByteBuf.class),
++                any(ChannelPromise.class))).thenAnswer(new Answer<ChannelFuture>() {
++            @Override
++            public ChannelFuture answer(InvocationOnMock invocationOnMock) {
++                ReferenceCountUtil.release(invocationOnMock.getArgument(3));
++                ChannelPromise promise = invocationOnMock.getArgument(4);
++                goAwayPromises.offer(promise);
++                return promise;
++            }
++        });
++        Http2Connection connection = new DefaultHttp2Connection(false);
++        connection.remote().flowController(new DefaultHttp2RemoteFlowController(connection));
++        connection.local().flowController(new DefaultHttp2LocalFlowController(connection).frameWriter(writer));
++
++        DefaultHttp2ConnectionEncoder defaultEncoder =
++                new DefaultHttp2ConnectionEncoder(connection, writer);
++        encoder = new Http2MaxRstFrameLimitEncoder(defaultEncoder, 2, 1);
++        DefaultHttp2ConnectionDecoder decoder =
++                new DefaultHttp2ConnectionDecoder(connection, encoder, mock(Http2FrameReader.class));
++        Http2ConnectionHandler handler = new Http2ConnectionHandlerBuilder()
++                .frameListener(mock(Http2FrameListener.class))
++                .codec(decoder, encoder).build();
++
++        // Set LifeCycleManager on encoder and decoder
++        when(ctx.channel()).thenReturn(channel);
++        when(ctx.alloc()).thenReturn(UnpooledByteBufAllocator.DEFAULT);
++        when(channel.alloc()).thenReturn(UnpooledByteBufAllocator.DEFAULT);
++        when(executor.inEventLoop()).thenReturn(true);
++        doAnswer(new Answer<ChannelPromise>() {
++            @Override
++            public ChannelPromise answer(InvocationOnMock invocation) throws Throwable {
++                return newPromise();
++            }
++        }).when(ctx).newPromise();
++        when(ctx.executor()).thenReturn(executor);
++        when(channel.isActive()).thenReturn(false);
++        when(channel.config()).thenReturn(config);
++        when(channel.isWritable()).thenReturn(true);
++        when(channel.bytesBeforeUnwritable()).thenReturn(Long.MAX_VALUE);
++        when(config.getWriteBufferHighWaterMark()).thenReturn(Integer.MAX_VALUE);
++        when(config.getMessageSizeEstimator()).thenReturn(DefaultMessageSizeEstimator.DEFAULT);
++        ChannelMetadata metadata = new ChannelMetadata(false, 16);
++        when(channel.metadata()).thenReturn(metadata);
++        when(channel.unsafe()).thenReturn(unsafe);
++        handler.handlerAdded(ctx);
++    }
++
++    private ChannelPromise handlePromise(InvocationOnMock invocationOnMock, int promiseIdx) {
++        ChannelPromise promise = invocationOnMock.getArgument(promiseIdx);
++        return promise.setSuccess();
++    }
++
++    @AfterEach
++    public void teardown() {
++        // Close and release any buffered frames.
++        encoder.close();
++
++        // Notify all goAway ChannelPromise instances now as these will also release the retained ByteBuf for the
++        // debugData.
++        for (;;) {
++            ChannelPromise promise = goAwayPromises.poll();
++            if (promise == null) {
++                break;
++            }
++            promise.setSuccess();
++        }
++    }
++
++    @ParameterizedTest
++    @EnumSource(Http2Error.class)
++    public void testLimitRst(Http2Error error) {
++        assertTrue(encoder.writeRstStream(ctx, 1, error.code(), newPromise()).isSuccess());
++        assertTrue(encoder.writeRstStream(ctx, 1, error.code(), newPromise()).isSuccess());
++        verifyFlushAndClose(0, false);
++        assertTrue(encoder.writeRstStream(ctx, 1, error.code(), newPromise()).isSuccess());
++        if (error == CANCEL || error == NO_ERROR) {
++            // CANCEL and NO_ERROR are ignored as these will not be caused by a stream error.
++            verifyFlushAndClose(0, false);
++        } else {
++            verifyFlushAndClose(1, true);
++        }
++    }
++
++    @ParameterizedTest
++    @EnumSource(Http2Error.class)
++    public void testLimitRstReset(Http2Error error) throws Exception {
++        assertTrue(encoder.writeRstStream(ctx, 1, error.code(), newPromise()).isSuccess());
++        assertTrue(encoder.writeRstStream(ctx, 1, error.code(), newPromise()).isSuccess());
++        verifyFlushAndClose(0, false);
++        Thread.sleep(1000);
++        assertTrue(encoder.writeRstStream(ctx, 1, error.code(), newPromise()).isSuccess());
++        verifyFlushAndClose(0, false);
++    }
++
++    private void verifyFlushAndClose(int invocations, boolean failed) {
++        verify(ctx, atLeast(invocations)).flush();
++        verify(ctx, times(invocations)).close();
++        if (failed) {
++            verify(writer, times(1)).writeGoAway(eq(ctx), eq(Integer.MAX_VALUE), eq(ENHANCE_YOUR_CALM.code()),
++                    any(ByteBuf.class), any(ChannelPromise.class));
++        }
++    }
++
++    private ChannelPromise newPromise() {
++        return new DefaultChannelPromise(channel, ImmediateEventExecutor.INSTANCE);
++    }
++}


=====================================
debian/patches/series
=====================================
@@ -26,3 +26,5 @@ CVE-2023-44487.patch
 22-java-21.patch
 CVE-2024-29025.patch
 CVE-2025-59419
+CVE-2025-55163_1.patch
+CVE-2025-55163_2.patch



View it on GitLab: https://salsa.debian.org/java-team/netty/-/commit/d7548a5d02c4e2bdf1b46399e415bfe1d54deac2

-- 
View it on GitLab: https://salsa.debian.org/java-team/netty/-/commit/d7548a5d02c4e2bdf1b46399e415bfe1d54deac2
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20251108/3b47f71d/attachment.htm>


More information about the pkg-java-commits mailing list