Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
321 changes: 321 additions & 0 deletions SPECS/fluent-bit/CVE-2026-58055.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,321 @@
From ab28105c4a0197da24f8bfc414bc116055249e1e Mon Sep 17 00:00:00 2001
From: Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
Date: Fri, 22 May 2026 21:26:44 +0900
Subject: [PATCH] nghttpx: Tighten up CONNECT and HTTP Upgrade handling

Upstream Patch reference: https://github.com/nghttp2/nghttp2/commit/ab28105c4a0197da24f8bfc414bc116055249e1e.patch
---
lib/nghttp2/src/shrpx_downstream.cc | 3 +-
lib/nghttp2/src/shrpx_downstream.h | 4 ++
lib/nghttp2/src/shrpx_http2_upstream.cc | 11 +++
lib/nghttp2/src/shrpx_http3_upstream.cc | 11 +++
.../src/shrpx_http_downstream_connection.cc | 70 ++++++++++++++++---
.../src/shrpx_http_downstream_connection.h | 5 ++
lib/nghttp2/src/shrpx_https_upstream.cc | 35 ++++++++--
7 files changed, 123 insertions(+), 16 deletions(-)

diff --git a/lib/nghttp2/src/shrpx_downstream.cc b/lib/nghttp2/src/shrpx_downstream.cc
index 9ea52b4..b52fa26 100644
--- a/lib/nghttp2/src/shrpx_downstream.cc
+++ b/lib/nghttp2/src/shrpx_downstream.cc
@@ -1114,7 +1114,8 @@ bool Downstream::can_detach_downstream_connection() const {
// 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() {
diff --git a/lib/nghttp2/src/shrpx_downstream.h b/lib/nghttp2/src/shrpx_downstream.h
index 146cae5..d3619f9 100644
--- a/lib/nghttp2/src/shrpx_downstream.h
+++ b/lib/nghttp2/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 {
diff --git a/lib/nghttp2/src/shrpx_http2_upstream.cc b/lib/nghttp2/src/shrpx_http2_upstream.cc
index c9f8a8c..f6e221a 100644
--- a/lib/nghttp2/src/shrpx_http2_upstream.cc
+++ b/lib/nghttp2/src/shrpx_http2_upstream.cc
@@ -359,6 +359,17 @@ int Http2Upstream::on_request_headers(Downstream *downstream,
return 0;
}

+ if (method_token == HTTP_CONNECT && content_length) {
+ if (LOG_ENABLED(INFO)) {
+ ULOG(INFO, this) << "content-length are not allowed in CONNECT request";
+ }
+
+ if (error_reply(downstream, 400) != 0) {
+ return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
+ }
+ return 0;
+ }
+
auto faddr = handler_->get_upstream_addr();

// For HTTP/2 proxy, we require :authority.
diff --git a/lib/nghttp2/src/shrpx_http3_upstream.cc b/lib/nghttp2/src/shrpx_http3_upstream.cc
index 46800de..c7ed311 100644
--- a/lib/nghttp2/src/shrpx_http3_upstream.cc
+++ b/lib/nghttp2/src/shrpx_http3_upstream.cc
@@ -2263,6 +2263,17 @@ int Http3Upstream::http_end_request_headers(Downstream *downstream, int fin) {
return 0;
}

+ if (method_token == HTTP_CONNECT && content_length) {
+ if (LOG_ENABLED(INFO)) {
+ ULOG(INFO, this) << "content-length are not allowed in CONNECT request";
+ }
+
+ if (error_reply(downstream, 400) != 0) {
+ return -1;
+ }
+ return 0;
+ }
+
auto faddr = handler_->get_upstream_addr();

auto config = get_config();
diff --git a/lib/nghttp2/src/shrpx_http_downstream_connection.cc b/lib/nghttp2/src/shrpx_http_downstream_connection.cc
index bdb4294..57bc4a9 100644
--- a/lib/nghttp2/src/shrpx_http_downstream_connection.cc
+++ b/lib/nghttp2/src/shrpx_http_downstream_connection.cc
@@ -727,6 +727,34 @@ int HttpDownstreamConnection::push_request_headers() {
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();

@@ -756,7 +784,7 @@ int HttpDownstreamConnection::process_blocked_request_buf() {

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);
@@ -788,7 +816,7 @@ int HttpDownstreamConnection::push_upload_data_chunk(const uint8_t *data,
}

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();
@@ -989,6 +1017,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.
@@ -1010,7 +1043,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);
}

@@ -1025,13 +1058,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()) {
@@ -1205,7 +1247,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();
@@ -1226,8 +1271,11 @@ int HttpDownstreamConnection::write_first() {
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
diff --git a/lib/nghttp2/src/shrpx_http_downstream_connection.h b/lib/nghttp2/src/shrpx_http_downstream_connection.h
index a453f0d..e9e1b1d 100644
--- a/lib/nghttp2/src/shrpx_http_downstream_connection.h
+++ b/lib/nghttp2/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
diff --git a/lib/nghttp2/src/shrpx_https_upstream.cc b/lib/nghttp2/src/shrpx_https_upstream.cc
index 49d2088..e6382d8 100644
--- a/lib/nghttp2/src/shrpx_https_upstream.cc
+++ b/lib/nghttp2/src/shrpx_https_upstream.cc
@@ -419,6 +419,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);
}
@@ -562,6 +573,16 @@ int htp_bodycb(llhttp_t *htp, const char *data, size_t len) {
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) {
@@ -595,6 +616,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) {
@@ -635,7 +657,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());

@@ -710,9 +733,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 &&
--
2.43.0

6 changes: 5 additions & 1 deletion SPECS/fluent-bit/fluent-bit.spec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Summary: Fast and Lightweight Log processor and forwarder for Linux, BSD and OSX
Name: fluent-bit
Version: 3.1.10
Release: 6%{?dist}
Release: 7%{?dist}
License: Apache-2.0
Vendor: Microsoft Corporation
Distribution: Azure Linux
Expand All @@ -21,6 +21,7 @@ Patch10: CVE-2025-12969.patch
Patch11: CVE-2025-62408.patch
Patch12: CVE-2025-63657.patch
Patch13: CVE-2025-63652.patch
Patch14: CVE-2026-58055.patch
BuildRequires: bison
BuildRequires: cmake
BuildRequires: cyrus-sasl-devel
Expand Down Expand Up @@ -95,6 +96,9 @@ Development files for %{name}
%{_libdir}/fluent-bit/*.so

%changelog
* Wed Jul 01 2026 Azure Linux Security Servicing Account <azurelinux-security@microsoft.com> - 3.1.10-7
- Patch for CVE-2026-58055

* Thu Apr 23 2026 Azure Linux Security Servicing Account <azurelinux-security@microsoft.com> - 3.1.10-6
- Patch for CVE-2025-63652

Expand Down
Loading