Fw: Patch submission

Karim Harouat <[email protected]> Fri, 9 Jan 2026 06:55:55 +0000
Newsgroups org.yoctoproject.lists.poky
Message-ID <PA0P264MB683409224C7BAAD3FBF9A635F682A@PA0P264MB6834.FRAP264.PROD.OUTLOOK.COM>
Hello
I'm resending the email.

________________________________
From: Karim Harouat
Sent: Thursday, January 8, 2026 8:34 PM
To: [email protected] <[email protected]>
Subject: Patch submission


Hello



Happy new year



I am suggesting a patch to apply to lighttpd which is present in 1.4.80.



Thank you





Karim Harouat
Senior R&D Engineer
[email protected]<mailto:[email protected]> | www.ekinops.com<https://www.ekinops.com/>
Phone:



This email may contain material and data that are confidential. Any review or forwarding without express permission is strictly prohibited. If you are not the intended recipient, please delete all copies.
0001-lighttpd-apply-patch-CVE-2025-8671.patch (application/octet-stream, 10.8 KB)
From f6444f80c966817783847a3e833dfb5d4dd8fe4e Mon Sep 17 00:00:00 2001
From: Karim Harouat <[email protected]>
Date: Thu, 8 Jan 2026 20:04:26 +0100
Subject: [PATCH] lighttpd: apply patch CVE-2025-8671

Fixes: CVE-2025-8671

From Glenn Strauss <[email protected]>

CVE: CVE-2025-8671

Lighttpd is prone to a denial of service (DoS) vulnerability in the HTTP/2 protocol dubbed
'MadeYouReset'

applying commit
https://git.lighttpd.net/lighttpd/lighttpd1.4/commit/8442ca4c699566cdd7369e09690926f403b54fc9

Signed-off-by: Karim Harouat <[email protected]>
---
 .../lighttpd/lighttpd/CVE-2025-8671.patch     | 181 ++++++++++++++++++
 .../lighttpd/lighttpd_1.4.74.bb               |   1 +
 2 files changed, 182 insertions(+)
 create mode 100644 meta/recipes-extended/lighttpd/lighttpd/CVE-2025-8671.patch

diff --git a/meta/recipes-extended/lighttpd/lighttpd/CVE-2025-8671.patch b/meta/recipes-extended/lighttpd/lighttpd/CVE-2025-8671.patch
new file mode 100644
index 0000000000..a304d91ff1
--- /dev/null
+++ b/meta/recipes-extended/lighttpd/lighttpd/CVE-2025-8671.patch
@@ -0,0 +1,181 @@
+From 8442ca4c699566cdd7369e09690926f403b54fc9 Mon Sep 17 00:00:00 2001
+From: Glenn Strauss <[email protected]>
+Date: Wed, 13 Aug 2025 08:52:15 -0400
+Subject: [PATCH] [h2] attempt to detect HTTP/2 MadeYouReset DoS
+
+attempt to detect HTTP/2 MadeYouReset DoS attack VU#767506 CVE-2025-8671
+
+Upstream-Status: Backport
+
+x-ref:
+  https://kb.cert.org/vuls/id/767506
+  https://www.cve.org/CVERecord?id=CVE-2025-8671
+---
+ src/h2.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
+ src/h2.h |   1 +
+ 2 files changed, 103 insertions(+), 4 deletions(-)
+
+diff --git a/src/h2.c b/src/h2.c
+index 7926a5e9..b4299453 100644
+--- a/src/h2.c
++++ b/src/h2.c
+@@ -349,6 +349,11 @@ h2_send_rst_stream_state (request_st * const r, h2con * const h2c)
+ }
+ 
+ 
++__attribute_cold__
++static void
++h2_send_goaway_e (connection * const con, const request_h2error_t e);
++
++
+ __attribute_cold__
+ static void
+ h2_send_rst_stream (request_st * const r, connection * const con, const request_h2error_t e)
+@@ -356,6 +361,97 @@ h2_send_rst_stream (request_st * const r, connection * const con, const request_
+     /*(set r->x.h2.state=H2_STATE_CLOSED)*/
+     h2_send_rst_stream_state(r, (h2con *)con->hx);
+     h2_send_rst_stream_id(r->x.h2.id, con, e);
++
++    /* attempt to detect HTTP/2 MadeYouReset DoS attack VU#767506 CVE-2025-8671
++     * heuristic to detect excessive err sent by client to cause reset by server
++     * Ignore H2_E_NO_ERROR and H2_E_INTERNAL_ERROR.
++     *   Were H2_E_INTERNAL_ERROR to be included, there might be false positives
++     *   (not attacks) in the count.  Ignoring H2_E_INTERNAL_ERROR here does not
++     *   count *response* headers too long, but that is not a client error.
++     * Ignore H2_E_REFUSED_STREAM, which is counted separately, elsewhere,
++     *   but not listed in conditional below since H2_E_REFUSED_STREAM is sent
++     *   directly via h2_send_rst_stream_id(), not h2_send_rst_stream()
++     * Include all other errors, though some are more prevalent than others:
++     *   H2_E_PROTOCOL_ERROR, H2_E_FLOW_CONTROL_ERROR, H2_E_STREAM_CLOSED,
++     *   H2_E_FRAME_SIZE_ERROR, H2_E_COMPRESSION_ERROR, ...
++     * Many such errors are sent with GOAWAY, so not as relevant to count here.
++     * If r->x.h2.state is not H2_STATE_CLOSED, include H2_E_STREAM_CLOSED here.
++     *
++     * Errors for unrecognized (not currently active) stream id are not counted
++     * here, but also do not affect potentially in-progress streams which are
++     * consuming resources in lighttpd and/or backends, e.g. if request headers
++     * are not yet complete, a backend to handle request has not been started.
++     *
++     * Similar to h2_recv_rst_stream() for HTTP/2 Rapid Reset attack,
++     * send GOAWAY with H2_E_NO_ERROR if count exceeds the policy limit since if
++     * peer is triggering server to send RST_STREAM, the peer is misbehaving,
++     * whether or not it is multiplexing requests from different clients, but a
++     * naive peer multiplexing requests from different clients could result in
++     * more reset (failed) streams of valid streams if one client could trigger
++     * too many resets sent by server on a single multiplexed connection, and
++     * server resets all streams and sends GOAWAY w/ error (not H2_E_NO_ERROR).
++     * log watchers such as fail2ban could watch for error log trace indicating
++     * detection of this attack, and could respond accordingly, across multiple
++     * servers.  In lighttpd, a client could trigger server-sent reset stream w/
++     * e.g. mismatch between received data and Content-Length, when provided.
++     */
++    if (e != H2_E_NO_ERROR && e != H2_E_INTERNAL_ERROR) {
++        /* simulate receiving TCP FIN from client to trigger imminent shutdown()
++         * on socket connection to backend, indicating request terminated.
++         * Note: mod_cgi must be configured for this to have any effect,
++         *   e.g. cgi.limits += ("tcp-fin-propagate" => "SIGTERM")
++         * Regardless of whether or not this optimization is performed,
++         * lighttpd will schedule close() on backend socket (or CGI pipe)
++         * and will close() backend socket (or kill CGI) upon next poll cycle */
++        /*r->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_TCP_FIN;*/
++        if (r->handler_module)
++            joblist_append(con);  /*(cause short poll for next poll cycle)*/
++
++        /* increment h2c->n_send_rst_stream_err and check for policy violation
++         *
++         * time step interval currently 2 secs: (log_monotonic_secs >> 1)
++         * store time bits in upper nibble of h2c->n_send_rst_stream_err
++         *   (32-second time slice: ((log_monotonic_secs >> 1) & 0xF))
++         * time_bits are only 4 bits, so repeated time_bits could cause false
++         *   positive and not decay the counter, but well-behaved peers should
++         *   not trigger *any* RST_STREAM, so tripping the policy sooner is ok.
++         *   (rather than potentially missing policy violation (false negative))
++         * decay counter (divide by 2 (>> 1)) when time step interval changes
++         *   (any time interval change; not shifting by (cur_bits - time_bits))
++         * counter is 4 bits, so max is 15 (0xF) unless bit masks are adjusted
++         *
++         * XXX: server triggered to send RST_STREAM w/ error is unexpected
++         *      A stricter implementation might send GOAWAY H2_E_NO_ERROR
++         *      upon first occurrence.
++         */
++        h2con * const h2c = (h2con *)con->hx;
++        uint8_t cur_bits = (log_monotonic_secs >> 1) & 0xF;
++        uint8_t time_bits = h2c->n_send_rst_stream_err >> 4;
++        if (cur_bits != time_bits)
++            h2c->n_send_rst_stream_err =
++              (cur_bits << 4) | ((h2c->n_send_rst_stream_err & 0xF) >> 1);
++        if (!h2c->sent_goaway && (++h2c->n_send_rst_stream_err & 0xF) > 4) {
++            log_error(NULL, __FILE__, __LINE__,
++              "h2: %s triggered too many RST_STREAM too quickly (xaddr:%s)",
++              con->request.dst_addr_buf->ptr, r->dst_addr_buf->ptr);
++            h2_send_goaway_e(con, H2_E_NO_ERROR);
++            /* h2_send_goaway_e w/ H2_E_PROTOCOL_ERROR or H2_E_ENHANCE_YOUR_CALM
++             * would cause other request streams to be reset (and would have to
++             * check h2c->send_goaway <= 0 above instead of !h2c->sent_goaway)*/
++        }
++    }
++}
++
++
++__attribute_cold__
++__attribute_noinline__
++static void
++h2_send_rst_stream_closed (request_st * const r, connection * const con)
++{
++    if (r->x.h2.state == H2_STATE_CLOSED) /*already closed; rst_stream_id only*/
++        h2_send_rst_stream_id(r->x.h2.id, con, H2_E_STREAM_CLOSED);
++    else /*(r->x.h2.state == H2_STATE_HALF_CLOSED_REMOTE)*/
++        h2_send_rst_stream(r, con, H2_E_STREAM_CLOSED);
+ }
+ 
+ 
+@@ -593,6 +689,8 @@ h2_recv_rst_stream (connection * const con, const uint8_t * const s, const uint3
+         /* XXX: ? add debug trace including error code from RST_STREAM ? */
+         r->state = CON_STATE_ERROR;
+         r->x.h2.state = H2_STATE_CLOSED;
++        if (r->handler_module)
++            joblist_append(con);  /*(cause short poll for next poll cycle)*/
+ 
+         /* attempt to detect HTTP/2 rapid reset attack (CVE-2023-44487)
+          * Send GOAWAY if 17 or more requests in recent batch of up to 32
+@@ -608,8 +706,8 @@ h2_recv_rst_stream (connection * const con, const uint8_t * const s, const uint3
+               (h2c->n_recv_rst_stream >> 4) + (h2c->n_recv_rst_stream & 0xf);
+             if (n_recv_rst_stream > 16) {
+                 log_error(NULL, __FILE__, __LINE__,
+-                  "h2: %s sent too many RST_STREAM too quickly",
+-                  con->request.dst_addr_buf->ptr);
++                  "h2: %s sent too many RST_STREAM too quickly (xaddr:%s)",
++                  con->request.dst_addr_buf->ptr, r->dst_addr_buf->ptr);
+                 h2_send_goaway_e(con, H2_E_NO_ERROR);
+             }
+         }
+@@ -1137,7 +1235,7 @@ h2_recv_data (connection * const con, const uint8_t * const s, const uint32_t le
+ 
+     if (r->x.h2.state == H2_STATE_CLOSED
+         || r->x.h2.state == H2_STATE_HALF_CLOSED_REMOTE) {
+-        h2_send_rst_stream_id(id, con, H2_E_STREAM_CLOSED);
++        h2_send_rst_stream_closed(r, con); /* H2_E_STREAM_CLOSED */
+         chunkqueue_mark_written(cq, 9+len);
+         h2_send_window_update_unit(con, h2r, len); /*(h2r->x.h2.rwin)*/
+         return 1;
+@@ -1515,7 +1613,7 @@ h2_recv_trailers_r (connection * const con, h2con * const h2c, const uint32_t id
+     }
+     if (r->x.h2.state != H2_STATE_OPEN
+         && r->x.h2.state != H2_STATE_HALF_CLOSED_LOCAL) {
+-        h2_send_rst_stream(r, con, H2_E_STREAM_CLOSED);
++        h2_send_rst_stream_closed(r, con); /* H2_E_STREAM_CLOSED */
+         return NULL;
+     }
+     /* RFC 7540 is not explicit in restricting HEADERS (trailers) following
+diff --git a/src/h2.h b/src/h2.h
+index 2112c637..53541fe5 100644
+--- a/src/h2.h
++++ b/src/h2.h
+@@ -91,6 +91,7 @@ struct h2con {
+     uint8_t n_refused_stream;
+     uint8_t n_discarded_headers;
+     uint8_t n_recv_rst_stream;
++    uint8_t n_send_rst_stream_err;
+ };
+ typedef struct h2con h2con;
+ 
diff --git a/meta/recipes-extended/lighttpd/lighttpd_1.4.74.bb b/meta/recipes-extended/lighttpd/lighttpd_1.4.74.bb
index 7460d3d716..ef6002d031 100644
--- a/meta/recipes-extended/lighttpd/lighttpd_1.4.74.bb
+++ b/meta/recipes-extended/lighttpd/lighttpd_1.4.74.bb
@@ -14,6 +14,7 @@ SRC_URI = "http://download.lighttpd.net/lighttpd/releases-1.4.x/lighttpd-${PV}.t
            file://index.html.lighttpd \
            file://lighttpd.conf \
            file://lighttpd \
+           file://CVE-2025-8671.patch \
            "
 
 SRC_URI[sha256sum] = "5c08736e83088f7e019797159f306e88ec729abe976dc98fb3bed71b9d3e53b5"