Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: [email protected], [email protected]
Control: affects -1 + src:nghttp2
User: [email protected]
Usertags: pu

(for 13.8)

Fixes a low severity security issue in nghttp2, all tests in debusine
are fine. debdiff below.

Cheers,
        Moritz

diff -Nru nghttp2-1.64.0/debian/changelog nghttp2-1.64.0/debian/changelog
--- nghttp2-1.64.0/debian/changelog     2026-04-15 17:04:15.000000000 +0200
+++ nghttp2-1.64.0/debian/changelog     2026-09-03 23:11:23.000000000 +0200
@@ -1,3 +1,9 @@
+nghttp2 (1.64.0-1.1+deb13u2) trixie; urgency=medium
+
+  * CVE-2026-58055 (Closes: #1140917)
+
+ -- Moritz Mühlenhoff <[email protected]>  Thu, 03 Sep 2026 23:11:23 +0200
+
 nghttp2 (1.64.0-1.1+deb13u1) trixie-security; urgency=medium
 
   * Non-maintainer upload by the Security Team.
diff -Nru nghttp2-1.64.0/debian/patches/CVE-2026-58055.patch 
nghttp2-1.64.0/debian/patches/CVE-2026-58055.patch
--- nghttp2-1.64.0/debian/patches/CVE-2026-58055.patch  1970-01-01 
01:00:00.000000000 +0100
+++ nghttp2-1.64.0/debian/patches/CVE-2026-58055.patch  2026-09-03 
23:11:20.000000000 +0200
@@ -0,0 +1,287 @@
+From ab28105c4a0197da24f8bfc414bc116055249e1e Mon Sep 17 00:00:00 2001
+From: Tatsuhiro Tsujikawa <[email protected]>
+Date: Fri, 22 May 2026 21:26:44 +0900
+Subject: [PATCH] nghttpx: Tighten up CONNECT and HTTP Upgrade handling
+
+--- nghttp2-1.64.0.orig/src/shrpx_downstream.cc
++++ nghttp2-1.64.0/src/shrpx_downstream.cc
+@@ -1146,7 +1146,8 @@ bool Downstream::can_detach_downstream_c
+   // state, especially for HTTP/1.1
+   return dconn_ && response_state_ == DownstreamState::MSG_COMPLETE &&
+          request_state_ == DownstreamState::MSG_COMPLETE && !upgraded_ &&
+-         !resp_.connection_close && request_buf_.rleft() == 0;
++         !resp_.connection_close && blocked_request_buf_.rleft() == 0 &&
++         request_buf_.rleft() == 0;
+ }
+ 
+ DefaultMemchunks Downstream::pop_response_buf() {
+--- nghttp2-1.64.0.orig/src/shrpx_downstream.h
++++ nghttp2-1.64.0/src/shrpx_downstream.h
+@@ -231,6 +231,10 @@ struct Request {
+   // orig_authority and orig_path have the authority and path which
+   // are used for the first backend selection.
+   bool forwarded_once;
++  // true if HTTP/1 request message has been completed.  This field is
++  // added because Downstream::get_request_state() might be altered
++  // from DownstreamState::MSG_COMPLETE.
++  bool http1_msg_complete;
+ };
+ 
+ struct Response {
+--- nghttp2-1.64.0.orig/src/shrpx_http2_upstream.cc
++++ nghttp2-1.64.0/src/shrpx_http2_upstream.cc
+@@ -359,6 +359,14 @@ int Http2Upstream::on_request_headers(Do
+     return 0;
+   }
+ 
++  if (method_token == HTTP_CONNECT && content_length) {
++    if (LOG_ENABLED(INFO)) {
++      ULOG(INFO, this) << "content-length are not allowed in CONNECT request";
++    }
++
++    return error_reply(downstream, 400);
++  }
++
+   auto faddr = handler_->get_upstream_addr();
+ 
+   // For HTTP/2 proxy, we require :authority.
+--- nghttp2-1.64.0.orig/src/shrpx_http3_upstream.cc
++++ nghttp2-1.64.0/src/shrpx_http3_upstream.cc
+@@ -2282,6 +2282,14 @@ int Http3Upstream::http_end_request_head
+     return 0;
+   }
+ 
++  if (method_token == HTTP_CONNECT && content_length) {
++    if (LOG_ENABLED(INFO)) {
++      ULOG(INFO, this) << "content-length are not allowed in CONNECT request";
++    }
++
++    return error_reply(downstream, 400);
++  }
++
+   auto faddr = handler_->get_upstream_addr();
+ 
+   auto config = get_config();
+--- nghttp2-1.64.0.orig/src/shrpx_http_downstream_connection.cc
++++ nghttp2-1.64.0/src/shrpx_http_downstream_connection.cc
+@@ -735,6 +735,34 @@ int HttpDownstreamConnection::push_reque
+   return 0;
+ }
+ 
++bool HttpDownstreamConnection::should_block_request_body() const {
++  const auto &req = downstream_->request();
++
++  return !downstream_->get_request_header_sent() ||
++         (req.upgrade_request && !downstream_->get_upgraded());
++}
++
++bool HttpDownstreamConnection::should_unblock_request_body_before_response()
++  const {
++  const auto &req = downstream_->request();
++
++  return !req.upgrade_request;
++}
++
++void HttpDownstreamConnection::process_blocked_request_buf_on_response() {
++  if (blocked_request_buf_processed_) {
++    return;
++  }
++
++  process_blocked_request_buf();
++
++  auto buf = downstream_->get_blocked_request_buf();
++  buf->reset();
++  blocked_request_buf_processed_ = true;
++
++  signal_write();
++}
++
+ int HttpDownstreamConnection::process_blocked_request_buf() {
+   auto src = downstream_->get_blocked_request_buf();
+ 
+@@ -764,7 +792,7 @@ int HttpDownstreamConnection::process_bl
+ 
+ int HttpDownstreamConnection::push_upload_data_chunk(const uint8_t *data,
+                                                      size_t datalen) {
+-  if (!downstream_->get_request_header_sent()) {
++  if (should_block_request_body()) {
+     auto output = downstream_->get_blocked_request_buf();
+     auto &req = downstream_->request();
+     output->append(data, datalen);
+@@ -796,7 +824,7 @@ int HttpDownstreamConnection::push_uploa
+ }
+ 
+ int HttpDownstreamConnection::end_upload_data() {
+-  if (!downstream_->get_request_header_sent()) {
++  if (should_block_request_body()) {
+     downstream_->set_blocked_request_data_eof(true);
+     if (request_header_written_) {
+       signal_write();
+@@ -997,6 +1025,11 @@ int htp_hdrs_completecb(llhttp_t *htp) {
+   // upgrade succeeded, 101 response is treated as final in nghttpx.
+   downstream->check_upgrade_fulfilled_http1();
+ 
++  if (req.method == HTTP_CONNECT && resp.http_status / 100 == 2 &&
++      !downstream->get_upgraded()) {
++    resp.http_status = 502;
++  }
++
+   if (downstream->get_non_final_response()) {
+     // Reset content-length because we reuse same Downstream for the
+     // next response.
+@@ -1018,7 +1051,7 @@ int htp_hdrs_completecb(llhttp_t *htp) {
+   downstream->set_response_state(DownstreamState::HEADER_COMPLETE);
+   downstream->inspect_http1_response();
+ 
+-  if (htp->flags & F_CHUNKED) {
++  if (!downstream->get_upgraded() && (htp->flags & F_CHUNKED)) {
+     downstream->set_chunked_response(true);
+   }
+ 
+@@ -1033,13 +1066,22 @@ int htp_hdrs_completecb(llhttp_t *htp) {
+     resp.connection_close = true;
+     // transfer-encoding not applied to upgraded connection
+     downstream->set_chunked_response(false);
+-  } else if (http2::legacy_http1(req.http_major, req.http_minor)) {
+-    if (resp.fs.content_length == -1) {
++
++    static_cast<HttpDownstreamConnection *>(dconn)
++      ->process_blocked_request_buf_on_response();
++  } else {
++    if (req.upgrade_request) {
+       resp.connection_close = true;
+     }
+-    downstream->set_chunked_response(false);
+-  } else if (!downstream->expect_response_body()) {
+-    downstream->set_chunked_response(false);
++
++    if (http2::legacy_http1(req.http_major, req.http_minor)) {
++      if (resp.fs.content_length == -1) {
++        resp.connection_close = true;
++      }
++      downstream->set_chunked_response(false);
++    } else if (!downstream->expect_response_body()) {
++      downstream->set_chunked_response(false);
++    }
+   }
+ 
+   if (loggingconf.access.write_early && downstream->accesslog_ready()) {
+@@ -1213,7 +1255,10 @@ int htp_msg_completecb(llhttp_t *htp) {
+ int HttpDownstreamConnection::write_first() {
+   int rv;
+ 
+-  process_blocked_request_buf();
++  auto should_unblock_req_body = 
should_unblock_request_body_before_response();
++  if (should_unblock_req_body) {
++    process_blocked_request_buf();
++  }
+ 
+   if (conn_.tls.ssl) {
+     rv = write_tls();
+@@ -1234,8 +1279,11 @@ int HttpDownstreamConnection::write_firs
+   first_write_done_ = true;
+   downstream_->set_request_header_sent(true);
+ 
+-  auto buf = downstream_->get_blocked_request_buf();
+-  buf->reset();
++  if (should_unblock_req_body) {
++    auto buf = downstream_->get_blocked_request_buf();
++    buf->reset();
++    blocked_request_buf_processed_ = true;
++  }
+ 
+   // upstream->resume_read() might be called in
+   // write_tls()/write_clear(), but before blocked_request_buf_ is
+--- nghttp2-1.64.0.orig/src/shrpx_http_downstream_connection.h
++++ nghttp2-1.64.0/src/shrpx_http_downstream_connection.h
+@@ -91,6 +91,9 @@ public:
+   int noop();
+ 
+   int process_blocked_request_buf();
++  void process_blocked_request_buf_on_response();
++  bool should_unblock_request_body_before_response() const;
++  bool should_block_request_body() const;
+ 
+ private:
+   Connection conn_;
+@@ -117,6 +120,8 @@ private:
+   bool reusable_;
+   // true if request header is written to request buffer.
+   bool request_header_written_;
++  // true if blocked request buffer has been processed.
++  bool blocked_request_buf_processed_;
+ };
+ 
+ } // namespace shrpx
+--- nghttp2-1.64.0.orig/src/shrpx_https_upstream.cc
++++ nghttp2-1.64.0/src/shrpx_https_upstream.cc
+@@ -416,6 +416,17 @@ int htp_hdrs_completecb(llhttp_t *htp) {
+ 
+   downstream->inspect_http1_request();
+ 
++  if ((req.upgrade_request || llhttp_get_upgrade(htp)) &&
++      (req.fs.header(http2::HD_TRANSFER_ENCODING) ||
++       req.fs.header(http2::HD_CONTENT_LENGTH))) {
++    if (LOG_ENABLED(INFO)) {
++      ULOG(INFO, upstream) << "transfer-encoding and content-length are not "
++                             "allowed in CONNECT or upgrade request";
++    }
++
++    return -1;
++  }
++
+   if (htp->flags & F_CHUNKED) {
+     downstream->set_chunked_request(true);
+   }
+@@ -559,6 +570,16 @@ int htp_bodycb(llhttp_t *htp, const char
+   int rv;
+   auto upstream = static_cast<HttpsUpstream *>(htp->data);
+   auto downstream = upstream->get_downstream();
++  const auto &req = downstream->request();
++
++  if (req.upgrade_request || llhttp_get_upgrade(htp)) {
++    if (LOG_ENABLED(INFO)) {
++      ULOG(INFO, upstream) << "Request body for Upgrade request is not 
allowed";
++    }
++
++    return HPE_USER;
++  }
++
+   rv = downstream->push_upload_data_chunk(
+     reinterpret_cast<const uint8_t *>(data), len);
+   if (rv != 0) {
+@@ -592,6 +613,7 @@ int htp_msg_completecb(llhttp_t *htp) {
+   }
+ 
+   downstream->set_request_state(DownstreamState::MSG_COMPLETE);
++  req.http1_msg_complete = true;
+   rv = downstream->end_upload_data();
+   if (rv != 0) {
+     if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
+@@ -632,7 +654,8 @@ int HttpsUpstream::on_read() {
+ 
+   // downstream can be nullptr here, because it is initialized in the
+   // callback chain called by llhttp_execute()
+-  if (downstream && downstream->get_upgraded()) {
++  if (downstream && downstream->request().http1_msg_complete &&
++      downstream->get_upgraded()) {
+     auto rv = downstream->push_upload_data_chunk(rb->pos(), rb->rleft());
+ 
+     if (rv != 0) {
+@@ -706,9 +729,13 @@ int HttpsUpstream::on_read() {
+ 
+   if (htperr != HPE_OK) {
+     if (LOG_ENABLED(INFO)) {
+-      ULOG(INFO, this) << "HTTP parse failure: "
+-                       << "(" << llhttp_errno_name(htperr) << ") "
+-                       << llhttp_get_error_reason(&htp_);
++      if (htperr == HPE_USER) {
++        ULOG(INFO, this) << "HTTP callback error";
++      } else {
++        ULOG(INFO, this) << "HTTP parse failure: "
++                         << "(" << llhttp_errno_name(htperr) << ") "
++                         << llhttp_get_error_reason(&htp_);
++      }
+     }
+ 
+     if (downstream &&
diff -Nru nghttp2-1.64.0/debian/patches/series 
nghttp2-1.64.0/debian/patches/series
--- nghttp2-1.64.0/debian/patches/series        2026-04-15 17:04:15.000000000 
+0200
+++ nghttp2-1.64.0/debian/patches/series        2026-09-03 23:11:08.000000000 
+0200
@@ -3,3 +3,4 @@
 lp-2104171-avoid-rubydomain-namespace.patch
 CVE-2026-27135.patch
 CVE-2026-27135-test.patch
+CVE-2026-58055.patch

Reply via email to