Package: netty / 1:4.1.48-7+deb12u1

CVE-2023-44487.patch Patch series | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
From: Markus Koschany <apo@debian.org>
Date: Sun, 5 Nov 2023 22:29:58 +0100
Subject: CVE-2023-44487

Bug-Debian: https://bugs.debian.org/1054234
Origin: https://github.com/netty/netty/commit/58f75f665aa81a8cbcf6ffa74820042a285c5e61
---
 .../AbstractHttp2ConnectionHandlerBuilder.java     | 24 ++++++++-
 .../codec/http2/Http2FrameCodecBuilder.java        |  6 +++
 .../codec/http2/Http2MaxRstFrameDecoder.java       | 58 ++++++++++++++++++++++
 .../codec/http2/Http2MaxRstFrameListener.java      | 58 ++++++++++++++++++++++
 .../codec/http2/Http2MultiplexCodecBuilder.java    |  6 +++
 5 files changed, 150 insertions(+), 2 deletions(-)
 create mode 100644 codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MaxRstFrameDecoder.java
 create mode 100644 codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MaxRstFrameListener.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 f262b11..a904310 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,6 +109,8 @@ 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;
 
     /**
      * Sets the {@link Http2Settings} to use for the initial connection settings exchange.
@@ -410,7 +412,7 @@ public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2Conne
 
     /**
      * Returns the maximum number of consecutive empty DATA frames (without end_of_stream flag) that are allowed before
-     * the connection is closed. This allows to protected against the remote peer flooding us with such frames and
+     * the connection is closed. This allows to protect against the remote peer flooding us with such frames and
      * so use up a lot of CPU. There is no valid use-case for empty DATA frames without end_of_stream flag.
      *
      * {@code 0} means no protection is in place.
@@ -421,7 +423,7 @@ public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2Conne
 
     /**
      * Sets the maximum number of consecutive empty DATA frames (without end_of_stream flag) that are allowed before
-     * the connection is closed. This allows to protected against the remote peer flooding us with such frames and
+     * the connection is closed. This allows to protect against the remote peer flooding us with such frames and
      * so use up a lot of CPU. There is no valid use-case for empty DATA frames without end_of_stream flag.
      *
      * {@code 0} means no protection should be applied.
@@ -433,6 +435,21 @@ public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2Conne
         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 flooding us with such frames and
+     * so use up a lot of CPU.
+     *
+     * {@code 0} for any of the parameters means no protection should be applied.
+     */
+    protected B decoderEnforceMaxRstFramesPerWindow(int maxRstFramesPerWindow, int secondsPerWindow) {
+        enforceNonCodecConstraints("decoderEnforceMaxRstFramesPerWindow");
+        this.maxRstFramesPerWindow = checkPositiveOrZero(
+                maxRstFramesPerWindow, "maxRstFramesPerWindow");
+        this.secondsPerWindow = checkPositiveOrZero(secondsPerWindow, "secondsPerWindow");
+        return self();
+    }
+
     /**
      * Determine if settings frame should automatically be acknowledged and applied.
      * @return this.
@@ -545,6 +562,9 @@ 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 T handler;
         try {
             // Call the abstract build method
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 fad31b2..241c9c5 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
@@ -177,6 +177,12 @@ public class Http2FrameCodecBuilder extends
         return super.decoderEnforceMaxConsecutiveEmptyDataFrames(maxConsecutiveEmptyFrames);
     }
 
+    @Override
+    public Http2FrameCodecBuilder decoderEnforceMaxRstFramesPerWindow(
+            int maxConsecutiveEmptyFrames, int secondsPerWindow) {
+        return super.decoderEnforceMaxRstFramesPerWindow(maxConsecutiveEmptyFrames, secondsPerWindow);
+    }
+
     /**
      * Build a {@link Http2FrameCodec} object.
      */
diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MaxRstFrameDecoder.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MaxRstFrameDecoder.java
new file mode 100644
index 0000000..6ac6660
--- /dev/null
+++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MaxRstFrameDecoder.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2023 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 static io.netty.util.internal.ObjectUtil.checkPositive;
+
+
+/**
+ * Enforce a limit on the maximum number of RST frames that are allowed per a window
+ * before the connection will be closed with a GO_AWAY frame.
+ */
+final class Http2MaxRstFrameDecoder extends DecoratingHttp2ConnectionDecoder {
+    private final int maxRstFramesPerWindow;
+    private final int secondsPerWindow;
+
+    Http2MaxRstFrameDecoder(Http2ConnectionDecoder delegate, int maxRstFramesPerWindow, int secondsPerWindow) {
+        super(delegate);
+        this.maxRstFramesPerWindow = checkPositive(maxRstFramesPerWindow, "maxRstFramesPerWindow");
+        this.secondsPerWindow = checkPositive(secondsPerWindow, "secondsPerWindow");
+    }
+
+    @Override
+    public void frameListener(Http2FrameListener listener) {
+        if (listener != null) {
+            super.frameListener(new Http2MaxRstFrameListener(listener, maxRstFramesPerWindow, secondsPerWindow));
+        } else {
+            super.frameListener(null);
+        }
+    }
+
+    @Override
+    public Http2FrameListener frameListener() {
+        Http2FrameListener frameListener = frameListener0();
+        // Unwrap the original Http2FrameListener as we add this decoder under the hood.
+        if (frameListener instanceof Http2MaxRstFrameListener) {
+            return ((Http2MaxRstFrameListener) frameListener).listener;
+        }
+        return frameListener;
+    }
+
+    // Package-private for testing
+    Http2FrameListener frameListener0() {
+        return super.frameListener();
+    }
+}
diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MaxRstFrameListener.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MaxRstFrameListener.java
new file mode 100644
index 0000000..4603686
--- /dev/null
+++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MaxRstFrameListener.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2023 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.channel.ChannelHandlerContext;
+import io.netty.util.internal.logging.InternalLogger;
+import io.netty.util.internal.logging.InternalLoggerFactory;
+
+import java.util.concurrent.TimeUnit;
+
+
+final class Http2MaxRstFrameListener extends Http2FrameListenerDecorator {
+    private static final InternalLogger logger = InternalLoggerFactory.getInstance(Http2MaxRstFrameListener.class);
+
+    private final long nanosPerWindow;
+    private final int maxRstFramesPerWindow;
+    private long lastRstFrameNano = System.nanoTime();
+    private int receivedRstInWindow;
+
+    Http2MaxRstFrameListener(Http2FrameListener listener, int maxRstFramesPerWindow, int secondsPerWindow) {
+        super(listener);
+        this.maxRstFramesPerWindow = maxRstFramesPerWindow;
+        this.nanosPerWindow = TimeUnit.SECONDS.toNanos(secondsPerWindow);
+    }
+
+    @Override
+    public void onRstStreamRead(ChannelHandlerContext ctx, int streamId, long errorCode) throws Http2Exception {
+        long currentNano = System.nanoTime();
+        if (currentNano - lastRstFrameNano >= nanosPerWindow) {
+            lastRstFrameNano = currentNano;
+            receivedRstInWindow = 1;
+        } else {
+            receivedRstInWindow++;
+            if (receivedRstInWindow > maxRstFramesPerWindow) {
+                Http2Exception exception = Http2Exception.connectionError(Http2Error.ENHANCE_YOUR_CALM,
+                        "Maximum number of RST frames reached");
+                logger.debug("{} Maximum number {} of RST frames reached within {} seconds, " +
+                                "closing connection with {} error", ctx.channel(), maxRstFramesPerWindow,
+                        TimeUnit.NANOSECONDS.toSeconds(nanosPerWindow), exception.error(), exception);
+                throw exception;
+            }
+        }
+        super.onRstStreamRead(ctx, streamId, errorCode);
+    }
+}
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 5d0829e..a3c0bed 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
@@ -206,6 +206,12 @@ public class Http2MultiplexCodecBuilder
         return super.decoderEnforceMaxConsecutiveEmptyDataFrames(maxConsecutiveEmptyFrames);
     }
 
+    @Override
+    public Http2MultiplexCodecBuilder decoderEnforceMaxRstFramesPerWindow(
+            int maxConsecutiveEmptyFrames, int secondsPerWindow) {
+        return super.decoderEnforceMaxRstFramesPerWindow(maxConsecutiveEmptyFrames, secondsPerWindow);
+    }
+
     @Override
     public Http2MultiplexCodec build() {
         Http2FrameWriter frameWriter = this.frameWriter;