From c43eac4cf9714d48579e874ba3ddd22a0e87f30c Mon Sep 17 00:00:00 2001 From: zwst061106-bot Date: Fri, 19 Jun 2026 18:56:14 +0300 Subject: [PATCH 1/2] Fix integer overflow in FlatBufferBuilder This commit addresses an integer overflow vulnerability in FlatBufferBuilder. Previously, the multiplication of len * elemsize was performed without validation, which could lead to heap out-of-bounds writes. I have introduced __builtin_mul_overflow checks in CreateUninitializedVector and StartVectorOfStructs to ensure memory allocation safety. --- include/flatbuffers/flatbuffer_builder.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/include/flatbuffers/flatbuffer_builder.h b/include/flatbuffers/flatbuffer_builder.h index 636d3776ba..22334e676d 100644 --- a/include/flatbuffers/flatbuffer_builder.h +++ b/include/flatbuffers/flatbuffer_builder.h @@ -1197,7 +1197,12 @@ class FlatBufferBuilderImpl { size_t alignment, uint8_t** buf) { NotNested(); StartVector(len, elemsize, alignment); - buf_.make_space(len * elemsize); + size_t total_size = 0; + if (__builtin_mul_overflow(len, elemsize, &total_size)) { + FLATBUFFERS_ASSERT(false && "Integer overflow"); + return 0; + } + buf_.make_space(total_size); const uoffset_t vec_start = GetSizeRelative32BitRegion(); auto vec_end = EndVector(len); *buf = buf_.data_at(vec_start); @@ -1422,7 +1427,12 @@ class FlatBufferBuilderImpl { template class OffsetT = Offset> T* StartVectorOfStructs(size_t vector_size) { StartVector(vector_size, sizeof(T), AlignOf()); - return reinterpret_cast(buf_.make_space(vector_size * sizeof(T))); + size_t total_size = 0; + if (__builtin_mul_overflow(vector_size, sizeof(T), &total_size)) { + FLATBUFFERS_ASSERT(false && "Integer overflow"); + return nullptr; + } + return reinterpret_cast(buf_.make_space(total_size)); } // End the vector of structures in the flatbuffers. From b2aa619d92c09309359d30e225f4113c3f2d3dac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D8=B2=D9=8A=D8=A7=D8=AF=D9=88=D8=A7=D8=A6=D9=84?= Date: Fri, 19 Jun 2026 20:17:31 +0300 Subject: [PATCH 2/2] Apply comprehensive integer overflow protections --- include/flatbuffers/flatbuffer_builder.h | 46 ++++++++++++++++-------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/include/flatbuffers/flatbuffer_builder.h b/include/flatbuffers/flatbuffer_builder.h index 22334e676d..8135db34ef 100644 --- a/include/flatbuffers/flatbuffer_builder.h +++ b/include/flatbuffers/flatbuffer_builder.h @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -692,6 +692,10 @@ class FlatBufferBuilderImpl { void StartVector(size_t len, size_t elemsize, size_t alignment) { NotNested(); nested = true; + if (len > 0 && elemsize > (static_cast(-1) / len)) { + FLATBUFFERS_ASSERT(false && "Integer overflow"); + return; + } // Align to the Length type of the vector (either 32-bit or 64-bit), so // that the length of the buffer can be added without padding. PreAlign(len * elemsize); @@ -713,6 +717,10 @@ class FlatBufferBuilderImpl { const size_t alignment) { if (len == 0) return; FLATBUFFERS_ASSERT(VerifyAlignmentRequirements(alignment)); + if (len > 0 && elemsize > (static_cast(-1) / len)) { + FLATBUFFERS_ASSERT(false && "Integer overflow"); + return; + } PreAlign(len * elemsize, alignment); } @@ -733,6 +741,10 @@ class FlatBufferBuilderImpl { // Similar to ForceVectorAlignment but for String fields. void ForceStringAlignment(size_t len, size_t alignment) { if (len == 0) return; + if (len == static_cast(-1)) { + FLATBUFFERS_ASSERT(false && "Integer overflow in ForceStringAlignment"); + return; + } FLATBUFFERS_ASSERT(VerifyAlignmentRequirements(alignment)); PreAlign((len + 1) * sizeof(char), alignment); } @@ -906,6 +918,10 @@ class FlatBufferBuilderImpl { auto distance = std::distance(begin, end); FLATBUFFERS_ASSERT(distance >= 0); auto size = static_cast(distance); + if (size > 0 && sizeof(Offset) > (static_cast(-1) / size)) { + FLATBUFFERS_ASSERT(false && "Integer overflow"); + return 0; + } auto scratch_buffer_usage = size * sizeof(Offset); // If there is not enough space to store the offsets, there definitely won't // be enough space to store all the strings. So ensuring space for the @@ -1196,12 +1212,12 @@ class FlatBufferBuilderImpl { uoffset_t CreateUninitializedVector(size_t len, size_t elemsize, size_t alignment, uint8_t** buf) { NotNested(); - StartVector(len, elemsize, alignment); - size_t total_size = 0; - if (__builtin_mul_overflow(len, elemsize, &total_size)) { - FLATBUFFERS_ASSERT(false && "Integer overflow"); - return 0; + if (len > 0 && elemsize > (static_cast(-1) / len)) { + FLATBUFFERS_ASSERT(false && "Integer overflow"); + return 0; } + size_t total_size = len * elemsize; + StartVector(len, elemsize, alignment); buf_.make_space(total_size); const uoffset_t vec_start = GetSizeRelative32BitRegion(); auto vec_end = EndVector(len); @@ -1347,10 +1363,10 @@ class FlatBufferBuilderImpl { // // [ Complete FlatBuffer ] // [32-bit region][64-bit region] - // ^ ^ - // | Tail of the buffer. - // | - // Tail of the 32-bit region of the buffer. + // ^ ^ + // | Tail of the buffer. + // | + // Tail of the 32-bit region of the buffer. // // This keeps track of the size of the 64-bit region so that the tail of the // 32-bit region can be calculated as `GetSize() - length_of_64_bit_region_`. @@ -1426,12 +1442,12 @@ class FlatBufferBuilderImpl { // Must be completed with EndVectorOfStructs(). template class OffsetT = Offset> T* StartVectorOfStructs(size_t vector_size) { - StartVector(vector_size, sizeof(T), AlignOf()); - size_t total_size = 0; - if (__builtin_mul_overflow(vector_size, sizeof(T), &total_size)) { - FLATBUFFERS_ASSERT(false && "Integer overflow"); - return nullptr; + if (vector_size > 0 && sizeof(T) > (static_cast(-1) / vector_size)) { + FLATBUFFERS_ASSERT(false && "Integer overflow"); + return nullptr; } + size_t total_size = vector_size * sizeof(T); + StartVector(vector_size, sizeof(T), AlignOf()); return reinterpret_cast(buf_.make_space(total_size)); }