From 1e6c851dba92317440ed779dd2956e229fc728e4 Mon Sep 17 00:00:00 2001 From: Ville Vesilehto Date: Thu, 28 Aug 2025 10:31:57 +0300 Subject: [PATCH] fix(go/grpc): avoid panic on short FlatBuffers input (#8684) * fix(go/grpc): avoid panic on short FlatBuffers input The gRPC codec read the root UOffsetT without checking input size. On buffers shorter than SizeUOffsetT, GetUint32 touched data[3] and the process panics. Add a simple length check and validate the root offset stays within the buffer. Return clear errors (insufficient data / invalid root offset) instead of panicking. Signed-off-by: Ville Vesilehto * fix(go/grpc): avoid signed overflow in offset Keep the bounds check in the unsigned domain (UOffsetT) to avoid signedness pitfalls. Signed-off-by: Ville Vesilehto * chore: clarify comment regarding offset A full FlatBuffer structure would be: - uoffset_t: root table offset (4 bytes) - soffset_t: vtable offset in root table (4 bytes) - uint16_t: vtable size (2 bytes) - uint16_t: table size (2 bytes) In total 12 bytes. We are only validating the data length before trying to read the uoffset_t, not the full structure. Signed-off-by: Ville Vesilehto --------- Signed-off-by: Ville Vesilehto Co-authored-by: Derek Bailey --- go/grpc.go | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/go/grpc.go b/go/grpc.go index 15f1a510d..56d7e9f2e 100644 --- a/go/grpc.go +++ b/go/grpc.go @@ -1,7 +1,17 @@ package flatbuffers -// Codec implements gRPC-go Codec which is used to encode and decode messages. -var Codec = "flatbuffers" +import "errors" + +var ( + // Codec implements gRPC-go Codec which is used to encode and decode messages. + Codec = "flatbuffers" + + // ErrInsufficientData is returned when the data is too short to read the root UOffsetT. + ErrInsufficientData = errors.New("insufficient data") + + // ErrInvalidRootOffset is returned when the root UOffsetT is out of bounds. + ErrInvalidRootOffset = errors.New("invalid root offset") +) // FlatbuffersCodec defines the interface gRPC uses to encode and decode messages. Note // that implementations of this interface must be thread safe; a Codec's @@ -15,7 +25,21 @@ func (FlatbuffersCodec) Marshal(v interface{}) ([]byte, error) { // Unmarshal parses the wire format into v. func (FlatbuffersCodec) Unmarshal(data []byte, v interface{}) error { - v.(flatbuffersInit).Init(data, GetUOffsetT(data)) + // Need at least 4 bytes to read the root table offset (UOffsetT). + // Vtable soffset_t and metadata are read later during field access. + if len(data) < SizeUOffsetT { + return ErrInsufficientData + } + + off := GetUOffsetT(data) + + // The root UOffsetT must be within the data buffer + // Compare in the unsigned domain to avoid signedness pitfalls + if off > UOffsetT(len(data)-SizeUOffsetT) { + return ErrInvalidRootOffset + } + + v.(flatbuffersInit).Init(data, off) return nil }