[Git][java-team/jetty9][bookworm] Import Debian changes 9.4.50-4+deb12u2

Markus Koschany (@apo) gitlab at salsa.debian.org
Sun Oct 29 23:34:37 GMT 2023



Markus Koschany pushed to branch bookworm at Debian Java Maintainers / jetty9


Commits:
2e267962 by Markus Koschany at 2023-10-30T00:34:14+01:00
Import Debian changes 9.4.50-4+deb12u2

jetty9 (9.4.50-4+deb12u2) bookworm-security; urgency=high
.
  * Team upload.
  * Fix CVE-2023-36478 and CVE-2023-44487:
    Two remotely exploitable security vulnerabilities were discovered in Jetty
    9, a Java based web server and servlet engine. The HTTP/2 protocol
    implementation did not sufficiently verify if HPACK header values exceed
    their size limit. Furthermore the HTTP/2 protocol allowed a denial of
    service (server resource consumption) because request cancellation can
    reset many streams quickly. This problem is also known as Rapid Reset
    Attack.

- - - - -


4 changed files:

- debian/changelog
- + debian/patches/CVE-2023-36478.patch
- + debian/patches/CVE-2023-44487.patch
- debian/patches/series


Changes:

=====================================
debian/changelog
=====================================
@@ -1,3 +1,17 @@
+jetty9 (9.4.50-4+deb12u2) bookworm-security; urgency=high
+
+  * Team upload.
+  * Fix CVE-2023-36478 and CVE-2023-44487:
+    Two remotely exploitable security vulnerabilities were discovered in Jetty
+    9, a Java based web server and servlet engine. The HTTP/2 protocol
+    implementation did not sufficiently verify if HPACK header values exceed
+    their size limit. Furthermore the HTTP/2 protocol allowed a denial of
+    service (server resource consumption) because request cancellation can
+    reset many streams quickly. This problem is also known as Rapid Reset
+    Attack.
+
+ -- Markus Koschany <apo at debian.org>  Sun, 29 Oct 2023 16:12:42 +0100
+
 jetty9 (9.4.50-4+deb12u1) bookworm-security; urgency=high
 
   * Team upload.


=====================================
debian/patches/CVE-2023-36478.patch
=====================================
The diff for this file was not included because it is too large.

=====================================
debian/patches/CVE-2023-44487.patch
=====================================
@@ -0,0 +1,622 @@
+From: Markus Koschany <apo at debian.org>
+Date: Thu, 26 Oct 2023 20:25:08 +0200
+Subject: CVE-2023-44487
+
+Origin: https://github.com/jetty/jetty.project/commit/2a512c2461282fa790a4c89b8ab5b7df15445b66
+---
+ .../jetty/http2/parser/ContinuationBodyParser.java | 36 +++++++++++----
+ .../jetty/http2/parser/HeaderBlockFragments.java   | 33 +++++++++----
+ .../jetty/http2/parser/HeadersBodyParser.java      | 37 +++++++++++----
+ .../org/eclipse/jetty/http2/parser/Parser.java     |  2 +-
+ .../jetty/http2/parser/PushPromiseBodyParser.java  | 13 ++++--
+ .../jetty/http2/parser/ResetBodyParser.java        |  8 ++--
+ .../jetty/http2/parser/SettingsBodyParser.java     | 29 ++++++++----
+ .../jetty/http2/parser/UnknownBodyParser.java      |  1 -
+ .../jetty/http2/frames/ContinuationParseTest.java  | 54 ++++++++++++++++++++++
+ .../eclipse/jetty/http2/frames/FrameFloodTest.java | 31 +++++++++++--
+ .../http2/frames/SettingsGenerateParseTest.java    | 16 +++----
+ .../AbstractHTTP2ServerConnectionFactory.java      |  2 +-
+ 12 files changed, 204 insertions(+), 58 deletions(-)
+
+diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java
+index 04d26d1..8f32800 100644
+--- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java
++++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java
+@@ -80,16 +80,28 @@ public class ContinuationBodyParser extends BodyParser
+                     int remaining = buffer.remaining();
+                     if (remaining < length)
+                     {
+-                        headerBlockFragments.storeFragment(buffer, remaining, false);
++                        ContinuationFrame frame = new ContinuationFrame(getStreamId(), false);
++                        if (!rateControlOnEvent(frame))
++                            return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_continuation_frame_rate");
++
++                        if (!headerBlockFragments.storeFragment(buffer, remaining, false))
++                            return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_continuation_stream");
++
+                         length -= remaining;
+                         break;
+                     }
+                     else
+                     {
+-                        boolean last = hasFlag(Flags.END_HEADERS);
+-                        headerBlockFragments.storeFragment(buffer, length, last);
++                        boolean endHeaders = hasFlag(Flags.END_HEADERS);
++                        ContinuationFrame frame = new ContinuationFrame(getStreamId(), endHeaders);
++                        if (!rateControlOnEvent(frame))
++                            return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_continuation_frame_rate");
++
++                        if (!headerBlockFragments.storeFragment(buffer, length, endHeaders))
++                            return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_continuation_stream");
++
+                         reset();
+-                        if (last)
++                        if (endHeaders)
+                             return onHeaders(buffer);
+                         return true;
+                     }
+@@ -107,17 +119,21 @@ public class ContinuationBodyParser extends BodyParser
+     {
+         ByteBuffer headerBlock = headerBlockFragments.complete();
+         MetaData metaData = headerBlockParser.parse(headerBlock, headerBlock.remaining());
+-        if (metaData == null)
+-            return true;
++        HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, headerBlockFragments.getPriorityFrame(), headerBlockFragments.isEndStream());
++        headerBlockFragments.reset();
++
+         if (metaData == HeaderBlockParser.SESSION_FAILURE)
+             return false;
+-        HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, headerBlockFragments.getPriorityFrame(), headerBlockFragments.isEndStream());
+-        if (metaData == HeaderBlockParser.STREAM_FAILURE)
++
++        if (metaData != HeaderBlockParser.STREAM_FAILURE)
++        {
++            notifyHeaders(frame);
++        }
++        else
+         {
+             if (!rateControlOnEvent(frame))
+-                return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_continuation_frame_rate");
++                return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_headers_frame_rate");
+         }
+-        notifyHeaders(frame);
+         return true;
+     }
+ 
+diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockFragments.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockFragments.java
+index be63ba4..3c69d2d 100644
+--- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockFragments.java
++++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockFragments.java
+@@ -24,22 +24,40 @@ import org.eclipse.jetty.http2.frames.PriorityFrame;
+ 
+ public class HeaderBlockFragments
+ {
++    private final int maxCapacity;
+     private PriorityFrame priorityFrame;
+-    private boolean endStream;
+     private int streamId;
++    private boolean endStream;
+     private ByteBuffer storage;
+ 
+-    public void storeFragment(ByteBuffer fragment, int length, boolean last)
++    public HeaderBlockFragments(int maxCapacity)
++    {
++        this.maxCapacity = maxCapacity;
++    }
++
++    void reset()
++    {
++        priorityFrame = null;
++        streamId = 0;
++        endStream = false;
++        storage = null;
++    }
++
++    public boolean storeFragment(ByteBuffer fragment, int length, boolean last)
+     {
+         if (storage == null)
+         {
+-            int space = last ? length : length * 2;
+-            storage = ByteBuffer.allocate(space);
++            if (length > maxCapacity)
++                return false;
++            int capacity = last ? length : length * 2;
++            storage = ByteBuffer.allocate(capacity);
+         }
+ 
+         // Grow the storage if necessary.
+         if (storage.remaining() < length)
+         {
++            if (storage.position() + length > maxCapacity)
++                return false;
+             int space = last ? length : length * 2;
+             int capacity = storage.position() + space;
+             ByteBuffer newStorage = ByteBuffer.allocate(capacity);
+@@ -53,6 +71,7 @@ public class HeaderBlockFragments
+         fragment.limit(fragment.position() + length);
+         storage.put(fragment);
+         fragment.limit(limit);
++        return true;
+     }
+ 
+     public PriorityFrame getPriorityFrame()
+@@ -77,10 +96,8 @@ public class HeaderBlockFragments
+ 
+     public ByteBuffer complete()
+     {
+-        ByteBuffer result = storage;
+-        storage = null;
+-        result.flip();
+-        return result;
++        storage.flip();
++        return storage;
+     }
+ 
+     public int getStreamId()
+diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java
+index b38a286..e222420 100644
+--- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java
++++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java
+@@ -76,8 +76,15 @@ public class HeadersBodyParser extends BodyParser
+         }
+         else
+         {
+-            headerBlockFragments.setStreamId(getStreamId());
+-            headerBlockFragments.setEndStream(isEndStream());
++            if (headerBlockFragments.getStreamId() != 0)
++            {
++                connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_headers_frame");
++            }
++            else
++            {
++                headerBlockFragments.setStreamId(getStreamId());
++                headerBlockFragments.setEndStream(isEndStream());
++            }
+         }
+     }
+ 
+@@ -172,6 +179,18 @@ public class HeadersBodyParser extends BodyParser
+                     break;
+                 }
+                 case HEADERS:
++                {
++                    if (!hasFlag(Flags.END_HEADERS))
++                    {
++                        headerBlockFragments.setStreamId(getStreamId());
++                        headerBlockFragments.setEndStream(isEndStream());
++                        if (hasFlag(Flags.PRIORITY))
++                            headerBlockFragments.setPriorityFrame(new PriorityFrame(getStreamId(), parentStreamId, weight, exclusive));
++                    }
++                    state = State.HEADER_BLOCK;
++                    break;
++                }
++                case HEADER_BLOCK:
+                 {
+                     if (hasFlag(Flags.END_HEADERS))
+                     {
+@@ -192,7 +211,7 @@ public class HeadersBodyParser extends BodyParser
+                             {
+                                 HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, null, isEndStream());
+                                 if (!rateControlOnEvent(frame))
+-                                    connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_headers_frame_rate");
++                                    return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_headers_frame_rate");
+                             }
+                         }
+                     }
+@@ -201,16 +220,14 @@ public class HeadersBodyParser extends BodyParser
+                         int remaining = buffer.remaining();
+                         if (remaining < length)
+                         {
+-                            headerBlockFragments.storeFragment(buffer, remaining, false);
++                            if (!headerBlockFragments.storeFragment(buffer, remaining, false))
++                                return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_headers_frame");
+                             length -= remaining;
+                         }
+                         else
+                         {
+-                            headerBlockFragments.setStreamId(getStreamId());
+-                            headerBlockFragments.setEndStream(isEndStream());
+-                            if (hasFlag(Flags.PRIORITY))
+-                                headerBlockFragments.setPriorityFrame(new PriorityFrame(getStreamId(), parentStreamId, weight, exclusive));
+-                            headerBlockFragments.storeFragment(buffer, length, false);
++                            if (!headerBlockFragments.storeFragment(buffer, length, false))
++                                return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_headers_frame");
+                             state = State.PADDING;
+                             loop = paddingLength == 0;
+                         }
+@@ -254,6 +271,6 @@ public class HeadersBodyParser extends BodyParser
+ 
+     private enum State
+     {
+-        PREPARE, PADDING_LENGTH, EXCLUSIVE, PARENT_STREAM_ID, PARENT_STREAM_ID_BYTES, WEIGHT, HEADERS, PADDING
++        PREPARE, PADDING_LENGTH, EXCLUSIVE, PARENT_STREAM_ID, PARENT_STREAM_ID_BYTES, WEIGHT, HEADERS, HEADER_BLOCK, PADDING
+     }
+ }
+diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java
+index 8044e71..5e2dfd0 100644
+--- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java
++++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java
+@@ -78,7 +78,7 @@ public class Parser
+         Listener listener = wrapper.apply(this.listener);
+         unknownBodyParser = new UnknownBodyParser(headerParser, listener);
+         HeaderBlockParser headerBlockParser = new HeaderBlockParser(headerParser, byteBufferPool, hpackDecoder, unknownBodyParser);
+-        HeaderBlockFragments headerBlockFragments = new HeaderBlockFragments();
++        HeaderBlockFragments headerBlockFragments = new HeaderBlockFragments(hpackDecoder.getMaxHeaderListSize());
+         bodyParsers[FrameType.DATA.getType()] = new DataBodyParser(headerParser, listener);
+         bodyParsers[FrameType.HEADERS.getType()] = new HeadersBodyParser(headerParser, listener, headerBlockParser, headerBlockFragments);
+         bodyParsers[FrameType.PRIORITY.getType()] = new PriorityBodyParser(headerParser, listener);
+diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java
+index c09405d..f02107d 100644
+--- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java
++++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java
+@@ -23,6 +23,7 @@ import java.nio.ByteBuffer;
+ import org.eclipse.jetty.http.MetaData;
+ import org.eclipse.jetty.http2.ErrorCode;
+ import org.eclipse.jetty.http2.Flags;
++import org.eclipse.jetty.http2.frames.HeadersFrame;
+ import org.eclipse.jetty.http2.frames.PushPromiseFrame;
+ 
+ public class PushPromiseBodyParser extends BodyParser
+@@ -70,13 +71,9 @@ public class PushPromiseBodyParser extends BodyParser
+                     length = getBodyLength();
+ 
+                     if (isPadding())
+-                    {
+                         state = State.PADDING_LENGTH;
+-                    }
+                     else
+-                    {
+                         state = State.STREAM_ID;
+-                    }
+                     break;
+                 }
+                 case PADDING_LENGTH:
+@@ -132,7 +129,15 @@ public class PushPromiseBodyParser extends BodyParser
+                         state = State.PADDING;
+                         loop = paddingLength == 0;
+                         if (metaData != HeaderBlockParser.STREAM_FAILURE)
++                        {
+                             onPushPromise(streamId, metaData);
++                        }
++                        else
++                        {
++                            HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, null, isEndStream());
++                            if (!rateControlOnEvent(frame))
++                                return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_headers_frame_rate");
++                        }
+                     }
+                     break;
+                 }
+diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java
+index bcc80f1..19b072a 100644
+--- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java
++++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java
+@@ -63,7 +63,7 @@ public class ResetBodyParser extends BodyParser
+                 {
+                     if (buffer.remaining() >= 4)
+                     {
+-                        return onReset(buffer.getInt());
++                        return onReset(buffer, buffer.getInt());
+                     }
+                     else
+                     {
+@@ -78,7 +78,7 @@ public class ResetBodyParser extends BodyParser
+                     --cursor;
+                     error += currByte << (8 * cursor);
+                     if (cursor == 0)
+-                        return onReset(error);
++                        return onReset(buffer, error);
+                     break;
+                 }
+                 default:
+@@ -90,9 +90,11 @@ public class ResetBodyParser extends BodyParser
+         return false;
+     }
+ 
+-    private boolean onReset(int error)
++    private boolean onReset(ByteBuffer buffer, int error)
+     {
+         ResetFrame frame = new ResetFrame(getStreamId(), error);
++        if (!rateControlOnEvent(frame))
++            return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_rst_stream_frame_rate");
+         reset();
+         notifyReset(frame);
+         return true;
+diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java
+index 5ee0252..fe9eaf0 100644
+--- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java
++++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java
+@@ -73,12 +73,22 @@ public class SettingsBodyParser extends BodyParser
+     @Override
+     protected void emptyBody(ByteBuffer buffer)
+     {
++        if (!validateFrame(buffer, getStreamId(), 0))
++            return;
+         boolean isReply = hasFlag(Flags.ACK);
+         SettingsFrame frame = new SettingsFrame(Collections.emptyMap(), isReply);
+-        if (!isReply && !rateControlOnEvent(frame))
+-            connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_settings_frame_rate");
+-        else
+-            onSettings(frame);
++        onSettings(buffer, frame);
++    }
++
++    private boolean validateFrame(ByteBuffer buffer, int streamId, int bodyLength)
++    {
++        // SPEC: wrong streamId is treated as connection error.
++        if (streamId != 0)
++            return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_settings_frame");
++        // SPEC: reply with body is treated as connection error.
++        if (hasFlag(Flags.ACK) && bodyLength > 0)
++            return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_settings_frame");
++        return true;
+     }
+ 
+     @Override
+@@ -95,9 +105,8 @@ public class SettingsBodyParser extends BodyParser
+             {
+                 case PREPARE:
+                 {
+-                    // SPEC: wrong streamId is treated as connection error.
+-                    if (streamId != 0)
+-                        return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_settings_frame");
++                    if (!validateFrame(buffer, streamId, bodyLength))
++                        return false;
+                     length = bodyLength;
+                     settings = new HashMap<>();
+                     state = State.SETTING_ID;
+@@ -211,11 +220,13 @@ public class SettingsBodyParser extends BodyParser
+             return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_settings_max_frame_size");
+ 
+         SettingsFrame frame = new SettingsFrame(settings, hasFlag(Flags.ACK));
+-        return onSettings(frame);
++        return onSettings(buffer, frame);
+     }
+ 
+-    private boolean onSettings(SettingsFrame frame)
++    private boolean onSettings(ByteBuffer buffer, SettingsFrame frame)
+     {
++        if (!rateControlOnEvent(frame))
++            return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_settings_frame_rate");
+         reset();
+         notifySettings(frame);
+         return true;
+diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/UnknownBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/UnknownBodyParser.java
+index 86a8628..23ca493 100644
+--- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/UnknownBodyParser.java
++++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/UnknownBodyParser.java
+@@ -40,7 +40,6 @@ public class UnknownBodyParser extends BodyParser
+         boolean parsed = cursor == 0;
+         if (parsed && !rateControlOnEvent(new UnknownFrame(getFrameType())))
+             return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_unknown_frame_rate");
+-
+         return parsed;
+     }
+ 
+diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ContinuationParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ContinuationParseTest.java
+index 9fb1bbf..54a7cde 100644
+--- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ContinuationParseTest.java
++++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ContinuationParseTest.java
+@@ -22,6 +22,8 @@ import java.nio.ByteBuffer;
+ import java.util.ArrayList;
+ import java.util.List;
+ import java.util.function.UnaryOperator;
++import java.util.concurrent.atomic.AtomicBoolean;
++import java.util.stream.IntStream;
+ 
+ import org.eclipse.jetty.http.HostPortHttpField;
+ import org.eclipse.jetty.http.HttpField;
+@@ -38,6 +40,8 @@ import org.eclipse.jetty.io.ByteBufferPool;
+ import org.eclipse.jetty.io.MappedByteBufferPool;
+ import org.junit.jupiter.api.Test;
+ 
++import static org.hamcrest.MatcherAssert.assertThat;
++import static org.hamcrest.Matchers.greaterThan;
+ import static org.junit.jupiter.api.Assertions.assertEquals;
+ import static org.junit.jupiter.api.Assertions.assertNull;
+ import static org.junit.jupiter.api.Assertions.assertTrue;
+@@ -160,4 +164,54 @@ public class ContinuationParseTest
+             assertNull(priority);
+         }
+     }
++
++    @Test
++    public void testLargeHeadersBlock() throws Exception
++    {
++        // Use a ByteBufferPool with a small factor, so that the accumulation buffer is not too large.
++        ByteBufferPool byteBufferPool = new MappedByteBufferPool(128);
++        // A small max headers size, used for both accumulation and decoding.
++        int maxHeadersSize = 512;
++        Parser parser = new Parser(byteBufferPool, maxHeadersSize);
++        // Specify headers block size to generate CONTINUATION frames.
++        int maxHeadersBlockFragment = 128;
++        HeadersGenerator generator = new HeadersGenerator(new HeaderGenerator(), new HpackEncoder(), maxHeadersBlockFragment);
++
++        int streamId = 13;
++        HttpFields fields = new HttpFields();
++        fields.put("Accept", "text/html");
++        // Large header that generates a large headers block.
++        StringBuilder large = new StringBuilder();
++        IntStream.range(0, 256).forEach(i -> large.append("Jetty"));
++        fields.put("User-Agent", large.toString());
++
++        MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP.asString(), new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields, -1);
++
++        ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
++        generator.generateHeaders(lease, streamId, metaData, null, true);
++        List<ByteBuffer> byteBuffers = lease.getByteBuffers();
++        assertThat(byteBuffers.stream().mapToInt(ByteBuffer::remaining).sum(), greaterThan(maxHeadersSize));
++
++        AtomicBoolean failed = new AtomicBoolean();
++        parser.init(new Parser.Listener.Adapter()
++        {
++            @Override
++            public void onConnectionFailure(int error, String reason)
++            {
++                failed.set(true);
++            }
++        });
++        // Set a large max headers size for decoding, to ensure
++        // the failure is due to accumulation, not decoding.
++        parser.getHpackDecoder().setMaxHeaderListSize(10 * maxHeadersSize);
++
++        for (ByteBuffer byteBuffer : byteBuffers)
++        {
++            parser.parse(byteBuffer);
++            if (failed.get())
++                break;
++        }
++
++        assertTrue(failed.get());
++    }
+ }
+diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/FrameFloodTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/FrameFloodTest.java
+index f9ee47f..2a1b187 100644
+--- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/FrameFloodTest.java
++++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/FrameFloodTest.java
+@@ -95,21 +95,29 @@ public class FrameFloodTest
+     }
+ 
+     @Test
+-    public void testSettingsFrameFlood()
++    public void testEmptySettingsFrameFlood()
+     {
+         byte[] payload = new byte[0];
+         testFrameFlood(null, frameFrom(payload.length, FrameType.SETTINGS.getType(), 0, 0, payload));
+     }
+ 
++    @Test
++    public void testSettingsFrameFlood()
++    {
++        // | Key0 | Key1 | Value0 | Value1 | Value2 | Value3 |
++        byte[] payload = new byte[]{0, 8, 0, 0, 0, 1};
++        testFrameFlood(null, frameFrom(payload.length, FrameType.SETTINGS.getType(), 0, 0, payload));
++    }
++
+     @Test
+     public void testPingFrameFlood()
+     {
+         byte[] payload = {0, 0, 0, 0, 0, 0, 0, 0};
+         testFrameFlood(null, frameFrom(payload.length, FrameType.PING.getType(), 0, 0, payload));
+     }
+-    
++
+     @Test
+-    public void testContinuationFrameFlood()
++    public void testEmptyContinuationFrameFlood()
+     {
+         int streamId = 13;
+         byte[] headersPayload = new byte[0];
+@@ -118,6 +126,23 @@ public class FrameFloodTest
+         testFrameFlood(headersBytes, frameFrom(continuationPayload.length, FrameType.CONTINUATION.getType(), 0, streamId, continuationPayload));
+     }
+ 
++    @Test
++    public void testContinuationFrameFlood()
++    {
++        int streamId = 13;
++        byte[] headersPayload = new byte[0];
++        byte[] headersBytes = frameFrom(headersPayload.length, FrameType.HEADERS.getType(), 0, streamId, headersPayload);
++        byte[] continuationPayload = new byte[1];
++        testFrameFlood(headersBytes, frameFrom(continuationPayload.length, FrameType.CONTINUATION.getType(), 0, streamId, continuationPayload));
++    }
++
++    @Test
++    public void testResetStreamFrameFlood()
++    {
++        byte[] payload = {0, 0, 0, 0};
++        testFrameFlood(null, frameFrom(payload.length, FrameType.RST_STREAM.getType(), 0, 13, payload));
++    }
++
+     @Test
+     public void testUnknownFrameFlood()
+     {
+diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java
+index 83ab018..4cc6a45 100644
+--- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java
++++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java
+@@ -36,6 +36,7 @@ import org.eclipse.jetty.io.MappedByteBufferPool;
+ import org.junit.jupiter.api.Test;
+ 
+ import static org.junit.jupiter.api.Assertions.assertEquals;
++import static org.junit.jupiter.api.Assertions.assertFalse;
+ import static org.junit.jupiter.api.Assertions.assertTrue;
+ 
+ public class SettingsGenerateParseTest
+@@ -45,8 +46,7 @@ public class SettingsGenerateParseTest
+     @Test
+     public void testGenerateParseNoSettings()
+     {
+-
+-        List<SettingsFrame> frames = testGenerateParse(Collections.<Integer, Integer>emptyMap());
++        List<SettingsFrame> frames = testGenerateParse(Collections.<Integer, Integer>emptyMap(), true);
+         assertEquals(1, frames.size());
+         SettingsFrame frame = frames.get(0);
+         assertEquals(0, frame.getSettings().size());
+@@ -63,7 +63,7 @@ public class SettingsGenerateParseTest
+         int key2 = 19;
+         Integer value2 = 23;
+         settings1.put(key2, value2);
+-        List<SettingsFrame> frames = testGenerateParse(settings1);
++        List<SettingsFrame> frames = testGenerateParse(settings1, false);
+         assertEquals(1, frames.size());
+         SettingsFrame frame = frames.get(0);
+         Map<Integer, Integer> settings2 = frame.getSettings();
+@@ -72,7 +72,7 @@ public class SettingsGenerateParseTest
+         assertEquals(value2, settings2.get(key2));
+     }
+ 
+-    private List<SettingsFrame> testGenerateParse(Map<Integer, Integer> settings)
++    private List<SettingsFrame> testGenerateParse(Map<Integer, Integer> settings, boolean reply)
+     {
+         SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator());
+ 
+@@ -91,7 +91,7 @@ public class SettingsGenerateParseTest
+         for (int i = 0; i < 2; ++i)
+         {
+             ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+-            generator.generateSettings(lease, settings, true);
++            generator.generateSettings(lease, settings, reply);
+ 
+             frames.clear();
+             for (ByteBuffer buffer : lease.getByteBuffers())
+@@ -125,7 +125,7 @@ public class SettingsGenerateParseTest
+         Map<Integer, Integer> settings1 = new HashMap<>();
+         settings1.put(13, 17);
+         ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+-        generator.generateSettings(lease, settings1, true);
++        generator.generateSettings(lease, settings1, false);
+         // Modify the length of the frame to make it invalid
+         ByteBuffer bytes = lease.getByteBuffers().get(0);
+         bytes.putShort(1, (short)(bytes.getShort(1) - 1));
+@@ -166,7 +166,7 @@ public class SettingsGenerateParseTest
+         for (int i = 0; i < 2; ++i)
+         {
+             ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+-            generator.generateSettings(lease, settings1, true);
++            generator.generateSettings(lease, settings1, false);
+ 
+             frames.clear();
+             for (ByteBuffer buffer : lease.getByteBuffers())
+@@ -182,7 +182,7 @@ public class SettingsGenerateParseTest
+             Map<Integer, Integer> settings2 = frame.getSettings();
+             assertEquals(1, settings2.size());
+             assertEquals(value, settings2.get(key));
+-            assertTrue(frame.isReply());
++            assertFalse(frame.isReply());
+         }
+     }
+ 
+diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java
+index 9d6306e..554ecfd 100644
+--- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java
++++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java
+@@ -60,7 +60,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
+     private int maxHeaderBlockFragment = 0;
+     private int maxFrameLength = Frame.DEFAULT_MAX_LENGTH;
+     private int maxSettingsKeys = SettingsFrame.DEFAULT_MAX_KEYS;
+-    private RateControl.Factory rateControlFactory = new WindowRateControl.Factory(50);
++    private RateControl.Factory rateControlFactory = new WindowRateControl.Factory(128);
+     private FlowControlStrategy.Factory flowControlStrategyFactory = () -> new BufferingFlowControlStrategy(0.5F);
+     private long streamIdleTimeout;
+ 


=====================================
debian/patches/series
=====================================
@@ -11,3 +11,5 @@ CVE-2023-26049.patch
 CVE-2023-40167.patch
 CVE-2023-41900.patch
 CVE-2023-36479.patch
+CVE-2023-44487.patch
+CVE-2023-36478.patch



View it on GitLab: https://salsa.debian.org/java-team/jetty9/-/commit/2e267962b83db143c831e713f44927a680f1e1fb

-- 
View it on GitLab: https://salsa.debian.org/java-team/jetty9/-/commit/2e267962b83db143c831e713f44927a680f1e1fb
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/20231029/7ec7dc5b/attachment.htm>


More information about the pkg-java-commits mailing list