Skip to content

Commit 9503cd1

Browse files
Fix out-of-bounds panics in buffered frame metadata parsing
Add bounds checks in trySeekMetadataLen, trySliceMetadata, and trySliceData so malformed frames with a bogus metadata length return nil instead of panicking on the slice expression.
1 parent 2a2c1cf commit 9503cd1

1 file changed

Lines changed: 41 additions & 4 deletions

File tree

core/framing/buffered.go

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import (
1212
uberatomic "go.uber.org/atomic"
1313
)
1414

15+
const metadataLengthFieldSize = 3 // Size of u24 metadata length field in bytes
16+
1517
// bufferedFrame is basic frame implementation.
1618
type bufferedFrame struct {
1719
innerPtr unsafe.Pointer
@@ -114,15 +116,22 @@ func (f *bufferedFrame) WriteTo(w io.Writer) (n int64, err error) {
114116
}
115117

116118
func (f *bufferedFrame) trySeekMetadataLen(offset int) (n int, hasMetadata bool) {
119+
// Validate offset before accessing frame to avoid panic on released frames
120+
if offset < 0 {
121+
return -1, false
122+
}
117123
raw := f.Body()
124+
if raw == nil || offset >= len(raw) {
125+
return -1, false
126+
}
118127
if offset > 0 {
119128
raw = raw[offset:]
120129
}
121130
hasMetadata = f.HasFlag(core.FlagMetadata)
122131
if !hasMetadata {
123132
return
124133
}
125-
if len(raw) < 3 {
134+
if len(raw) < metadataLengthFieldSize {
126135
n = -1
127136
} else {
128137
n = u24.NewUint24Bytes(raw).AsInt()
@@ -135,18 +144,46 @@ func (f *bufferedFrame) trySliceMetadata(offset int) ([]byte, bool) {
135144
if !ok || n < 0 {
136145
return nil, false
137146
}
138-
return f.Body()[offset+3 : offset+3+n], true
147+
body := f.Body()
148+
if body == nil {
149+
return nil, false
150+
}
151+
// Overflow-safe bounds check
152+
metadataOffset := offset + metadataLengthFieldSize
153+
if metadataOffset > len(body) {
154+
return nil, false
155+
}
156+
if n > len(body)-metadataOffset {
157+
return nil, false
158+
}
159+
return body[metadataOffset : metadataOffset+n], true
139160
}
140161

141162
func (f *bufferedFrame) trySliceData(offset int) []byte {
163+
body := f.Body()
164+
if body == nil {
165+
return nil
166+
}
142167
n, ok := f.trySeekMetadataLen(offset)
143168
if !ok {
144-
return f.Body()[offset:]
169+
if offset < 0 || offset > len(body) {
170+
return nil
171+
}
172+
return body[offset:]
145173
}
146174
if n < 0 {
147175
return nil
148176
}
149-
return f.Body()[offset+n+3:]
177+
// Overflow-safe bounds check
178+
metadataOffset := offset + metadataLengthFieldSize
179+
if metadataOffset > len(body) {
180+
return nil
181+
}
182+
if n > len(body)-metadataOffset {
183+
return nil
184+
}
185+
dataOffset := metadataOffset + n
186+
return body[dataOffset:]
150187
}
151188

152189
func (f *bufferedFrame) bodyLen() int {

0 commit comments

Comments
 (0)