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 }