| Message ID | 20260901090727.1384945-1-Abhishek.Bachiphale@windriver.com |
|---|---|
| State | New |
| Headers | show |
| Series | [meta-oe,wrynose] thrift: fix CVE-2026-58662 | expand |
Anuj, It seems like you missed this one. It still applies to wrynose HEAD for me and seems like a good backport. ../Randy On 2026-09-01 05:07, Abhishek Bachiphale via lists.openembedded.org wrote: > 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> > --- > .../thrift/thrift/CVE-2026-58662.patch | 120 ++++++++++++++++++ > .../thrift/thrift_0.22.0.bb | 1 + > 2 files changed, 121 insertions(+) > create mode 100644 meta-oe/recipes-connectivity/thrift/thrift/CVE-2026-58662.patch > > diff --git a/meta-oe/recipes-connectivity/thrift/thrift/CVE-2026-58662.patch b/meta-oe/recipes-connectivity/thrift/thrift/CVE-2026-58662.patch > new file mode 100644 > index 0000000000..03eaccb17a > --- /dev/null > +++ b/meta-oe/recipes-connectivity/thrift/thrift/CVE-2026-58662.patch > @@ -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 > diff --git a/meta-oe/recipes-connectivity/thrift/thrift_0.22.0.bb b/meta-oe/recipes-connectivity/thrift/thrift_0.22.0.bb > index 0128de8519..949ffc3e70 100644 > --- a/meta-oe/recipes-connectivity/thrift/thrift_0.22.0.bb > +++ b/meta-oe/recipes-connectivity/thrift/thrift_0.22.0.bb > @@ -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" > > > -=-=-=-=-=-=-=-=-=-=-=- > Links: You receive all messages sent to this group. > View/Reply Online (#129627):https://lists.openembedded.org/g/openembedded-devel/message/129627 > Mute This Topic:https://lists.openembedded.org/mt/121028875/3616765 > Group Owner:openembedded-devel+owner@lists.openembedded.org > Unsubscribe:https://lists.openembedded.org/g/openembedded-devel/unsub [randy.macleod@windriver.com] > -=-=-=-=-=-=-=-=-=-=-=- >
On 2026-09-02 16:54, Randy MacLeod wrote: > Anuj, > > It seems like you missed this one. > It still applies to wrynose HEAD for me and seems like a good backport. > > ../Randy Oops that was just sent yesterday. Sorry for the noise Anuj.
diff --git a/meta-oe/recipes-connectivity/thrift/thrift/CVE-2026-58662.patch b/meta-oe/recipes-connectivity/thrift/thrift/CVE-2026-58662.patch new file mode 100644 index 0000000000..03eaccb17a --- /dev/null +++ b/meta-oe/recipes-connectivity/thrift/thrift/CVE-2026-58662.patch @@ -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 diff --git a/meta-oe/recipes-connectivity/thrift/thrift_0.22.0.bb b/meta-oe/recipes-connectivity/thrift/thrift_0.22.0.bb index 0128de8519..949ffc3e70 100644 --- a/meta-oe/recipes-connectivity/thrift/thrift_0.22.0.bb +++ b/meta-oe/recipes-connectivity/thrift/thrift_0.22.0.bb @@ -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"
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> --- .../thrift/thrift/CVE-2026-58662.patch | 120 ++++++++++++++++++ .../thrift/thrift_0.22.0.bb | 1 + 2 files changed, 121 insertions(+) create mode 100644 meta-oe/recipes-connectivity/thrift/thrift/CVE-2026-58662.patch