forked from BigfootDev/flatbuffers
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 <ville@vesilehto.fi> * 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 <ville@vesilehto.fi> * 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 <ville@vesilehto.fi> --------- Signed-off-by: Ville Vesilehto <ville@vesilehto.fi> Co-authored-by: Derek Bailey <derekbailey@google.com>
This commit is contained in:
30
go/grpc.go
30
go/grpc.go
@@ -1,7 +1,17 @@
|
|||||||
package flatbuffers
|
package flatbuffers
|
||||||
|
|
||||||
// Codec implements gRPC-go Codec which is used to encode and decode messages.
|
import "errors"
|
||||||
var Codec = "flatbuffers"
|
|
||||||
|
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
|
// FlatbuffersCodec defines the interface gRPC uses to encode and decode messages. Note
|
||||||
// that implementations of this interface must be thread safe; a Codec's
|
// 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.
|
// Unmarshal parses the wire format into v.
|
||||||
func (FlatbuffersCodec) Unmarshal(data []byte, v interface{}) error {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user