mirror of
https://github.com/openembedded/meta-openembedded.git
synced 2026-09-27 00:30:20 +00:00
thrift: fix CVE-2026-58662
Improper Validation of Specified Quantity in Input, Out-of-bounds Read vulnerability in Apache Thrift C++ bindings. This issue affects Apache Thrift: before 0.24.0. Backport patch to fix CVE-2026-58662. Reference: [https://nvd.nist.gov/vuln/detail/cve-2026-58662] Upstream Patch: [https://github.com/apache/thrift/commit/f961cdb44249c293fcce6a840ffa1f7419fd88d0] Signed-off-by: Abhishek Bachiphale <Abhishek.Bachiphale@windriver.com> Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
From b9fe622d3e3dd2e376fbb5ccf2acfbfaf498ddb1 Mon Sep 17 00:00:00 2001
|
||||
From: Javid Khan <dxbjavid@gmail.com>
|
||||
Date: Tue, 30 Jun 2026 16:34:47 +0200
|
||||
Subject: [PATCH] fix info-header string bound check in
|
||||
|
||||
THeaderTransport::readString Client: cpp Patch: Javid Khan
|
||||
<dxbjavid@gmail.com>
|
||||
|
||||
when reading the key/value info headers of a THeader frame, readString reads
|
||||
the length varint and then bounds it against the bytes left in the header
|
||||
section. the comparison uses ptr before it is moved past the varint, so the
|
||||
remaining count is overstated by the width of the length field, and a negative
|
||||
length (a varint with the high bit set) is not rejected at all. with a header
|
||||
section sized to fill the receive buffer, either case lets a wire-supplied
|
||||
length exceed the header bytes that are actually present.
|
||||
|
||||
bound the length against the position that follows the varint, reject a
|
||||
negative length, and only advance ptr once those checks pass so the documented
|
||||
advance-on-success behaviour still holds. regression tests covering both the
|
||||
oversized and the negative length are added to ThrifttReadCheckTests.
|
||||
|
||||
This closes #3610
|
||||
|
||||
CVE: CVE-2026-58662
|
||||
Upstream-Status: Backport [https://github.com/apache/thrift/commit/f961cdb44249c293fcce6a840ffa1f7419fd88d0]
|
||||
Signed-off-by: Abhishek Bachiphale <Abhishek.Bachiphale@windriver.com>
|
||||
---
|
||||
.../src/thrift/transport/THeaderTransport.cpp | 12 +++--
|
||||
lib/cpp/test/ThrifttReadCheckTests.cpp | 52 +++++++++++++++++++
|
||||
2 files changed, 60 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/lib/cpp/src/thrift/transport/THeaderTransport.cpp b/lib/cpp/src/thrift/transport/THeaderTransport.cpp
|
||||
index 117c8ed..ba2fd5d 100644
|
||||
--- a/lib/cpp/src/thrift/transport/THeaderTransport.cpp
|
||||
+++ b/lib/cpp/src/thrift/transport/THeaderTransport.cpp
|
||||
@@ -183,13 +183,17 @@ void THeaderTransport::readString(uint8_t*& ptr,
|
||||
int32_t strLen;
|
||||
|
||||
uint32_t bytes = readVarint32(ptr, &strLen, headerBoundary);
|
||||
- if (strLen > headerBoundary - ptr) {
|
||||
+ // Bound the string against the header bytes that remain once the length varint
|
||||
+ // itself is accounted for, and reject a negative length so the size_t
|
||||
+ // conversion in assign() below stays within the buffer. ptr is only advanced
|
||||
+ // once these checks pass, keeping the "advances on success" contract above.
|
||||
+ uint8_t* strStart = ptr + bytes;
|
||||
+ if (strLen < 0 || strLen > headerBoundary - strStart) {
|
||||
throw TTransportException(TTransportException::CORRUPTED_DATA,
|
||||
"Info header length exceeds header size");
|
||||
}
|
||||
- ptr += bytes;
|
||||
- str.assign(reinterpret_cast<const char*>(ptr), strLen);
|
||||
- ptr += strLen;
|
||||
+ str.assign(reinterpret_cast<const char*>(strStart), strLen);
|
||||
+ ptr = strStart + strLen;
|
||||
}
|
||||
|
||||
void THeaderTransport::readHeaderFormat(uint16_t headerSize, uint32_t sz) {
|
||||
diff --git a/lib/cpp/test/ThrifttReadCheckTests.cpp b/lib/cpp/test/ThrifttReadCheckTests.cpp
|
||||
index 9632861..2a92160 100644
|
||||
--- a/lib/cpp/test/ThrifttReadCheckTests.cpp
|
||||
+++ b/lib/cpp/test/ThrifttReadCheckTests.cpp
|
||||
@@ -270,6 +270,58 @@ BOOST_AUTO_TEST_CASE(test_tthriftjsonprotocol_read_check_exception) {
|
||||
protocol->readMapEnd();
|
||||
}
|
||||
|
||||
+BOOST_AUTO_TEST_CASE(test_theadertransport_info_header_string_overrun) {
|
||||
+ using apache::thrift::transport::THeaderTransport;
|
||||
+ // Header-format frame whose info-header key length (4) does not fit within the
|
||||
+ // header bytes that remain once the length varint itself is accounted for. The
|
||||
+ // header section (8 bytes) exactly fills the frame, so the boundary sits at the
|
||||
+ // buffer end; the key length has to be bounded against the remaining bytes and
|
||||
+ // rejected.
|
||||
+ uint8_t frame[] = {
|
||||
+ 0x00, 0x00, 0x00, 0x12, // frame length = 18
|
||||
+ 0x0F, 0xFF, 0x00, 0x00, // header magic
|
||||
+ 0x00, 0x00, 0x00, 0x00, // seqId
|
||||
+ 0x00, 0x02, // header size field (2 -> 8 bytes)
|
||||
+ 0x02, // protocol id varint
|
||||
+ 0x00, // num transforms = 0
|
||||
+ 0x01, // info id = key/value
|
||||
+ 0x01, // one key/value pair
|
||||
+ 0x04, // key length = 4 (only 3 bytes remain)
|
||||
+ 0xAA, 0xBB, 0xCC // key bytes
|
||||
+ };
|
||||
+ std::shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer(frame, sizeof(frame)));
|
||||
+ std::shared_ptr<THeaderTransport> trans(new THeaderTransport(buffer));
|
||||
+
|
||||
+ uint8_t out[1];
|
||||
+ BOOST_CHECK_THROW(trans->read(out, sizeof(out)), TTransportException);
|
||||
+}
|
||||
+
|
||||
+BOOST_AUTO_TEST_CASE(test_theadertransport_info_header_string_negative_length) {
|
||||
+ using apache::thrift::transport::THeaderTransport;
|
||||
+ // Header-format frame whose info-header key length varint decodes to a
|
||||
+ // negative int32 (top bit set). The length has to be treated as out of range
|
||||
+ // rather than converted to a size_t, so the read is rejected instead of
|
||||
+ // reaching the string assignment. The three trailing bytes only pad the
|
||||
+ // header section out to its declared size and are never reached.
|
||||
+ uint8_t frame[] = {
|
||||
+ 0x00, 0x00, 0x00, 0x16, // frame length = 22
|
||||
+ 0x0F, 0xFF, 0x00, 0x00, // header magic
|
||||
+ 0x00, 0x00, 0x00, 0x00, // seqId
|
||||
+ 0x00, 0x03, // header size field (3 -> 12 bytes)
|
||||
+ 0x02, // protocol id varint
|
||||
+ 0x00, // num transforms = 0
|
||||
+ 0x01, // info id = key/value
|
||||
+ 0x01, // one key/value pair
|
||||
+ 0x80, 0x80, 0x80, 0x80, 0x08, // key length varint = INT32_MIN
|
||||
+ 0x00, 0x00, 0x00 // padding to fill the header section
|
||||
+ };
|
||||
+ std::shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer(frame, sizeof(frame)));
|
||||
+ std::shared_ptr<THeaderTransport> trans(new THeaderTransport(buffer));
|
||||
+
|
||||
+ uint8_t out[1];
|
||||
+ BOOST_CHECK_THROW(trans->read(out, sizeof(out)), TTransportException);
|
||||
+}
|
||||
+
|
||||
BOOST_AUTO_TEST_CASE(test_theadertransport_zlib_roundtrip) {
|
||||
using apache::thrift::transport::THeaderTransport;
|
||||
// A run of identical bytes compresses to far fewer bytes than it occupies
|
||||
@@ -17,6 +17,7 @@ SRC_URI = "https://downloads.apache.org/${BPN}/${PV}/${BP}.tar.gz \
|
||||
file://CVE-2026-58023.patch \
|
||||
file://CVE-2026-48144.patch \
|
||||
file://CVE-2026-58389.patch \
|
||||
file://CVE-2026-58662.patch \
|
||||
"
|
||||
SRC_URI[sha256sum] = "794a0e455787960d9f27ab92c38e34da27e8deeda7a5db0e59dc64a00df8a1e5"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user