Skip to content

Commit 5976b66

Browse files
committed
spdy: enforce 24-bit frame length limits
SPDY control and data frame headers carry a 24-bit Length field, so frame payloads must be limited to 2^24-1 bytes. Tighten the write-side bounds checks accordingly. SETTINGS still encodes its entry count as a 32-bit field, but the total payload must fit within the 24-bit frame length. Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
1 parent cf0ec5d commit 5976b66

1 file changed

Lines changed: 48 additions & 11 deletions

File tree

spdy/write.go

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package spdy
77
import (
88
"encoding/binary"
99
"io"
10+
"math"
1011
"net/http"
1112
"strings"
1213
)
@@ -47,13 +48,21 @@ func (frame *RstStreamFrame) write(f *Framer) (err error) {
4748
func (frame *SettingsFrame) write(f *Framer) (err error) {
4849
frame.CFHeader.version = Version
4950
frame.CFHeader.frameType = TypeSettings
50-
frame.CFHeader.length = uint32(len(frame.FlagIdValues)*8 + 4)
51+
payloadLen := len(frame.FlagIdValues)*8 + 4
52+
if payloadLen > MaxDataLength {
53+
return &Error{InvalidControlFrame, 0}
54+
}
55+
frame.CFHeader.length = uint32(payloadLen)
5156

5257
// Serialize frame to Writer.
5358
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
5459
return
5560
}
56-
if err = binary.Write(f.w, binary.BigEndian, uint32(len(frame.FlagIdValues))); err != nil {
61+
n := len(frame.FlagIdValues)
62+
if uint64(n) > math.MaxUint32 {
63+
return &Error{InvalidControlFrame, 0}
64+
}
65+
if err = binary.Write(f.w, binary.BigEndian, uint32(n)); err != nil {
5766
return
5867
}
5968
for _, flagIdValue := range frame.FlagIdValues {
@@ -154,29 +163,41 @@ func writeControlFrameHeader(w io.Writer, h ControlFrameHeader) error {
154163

155164
func writeHeaderValueBlock(w io.Writer, h http.Header) (n int, err error) {
156165
n = 0
157-
if err = binary.Write(w, binary.BigEndian, uint32(len(h))); err != nil {
166+
numHeaders := len(h)
167+
if numHeaders > math.MaxUint32 {
168+
return n, &Error{InvalidControlFrame, 0}
169+
}
170+
if err = binary.Write(w, binary.BigEndian, uint32(numHeaders)); err != nil {
158171
return
159172
}
160173
n += 2
161174
for name, values := range h {
162-
if err = binary.Write(w, binary.BigEndian, uint32(len(name))); err != nil {
175+
nameLen := len(name)
176+
if nameLen > math.MaxUint32 {
177+
return n, &Error{InvalidControlFrame, 0}
178+
}
179+
if err = binary.Write(w, binary.BigEndian, uint32(nameLen)); err != nil {
163180
return
164181
}
165182
n += 2
166183
name = strings.ToLower(name)
167184
if _, err = io.WriteString(w, name); err != nil {
168185
return
169186
}
170-
n += len(name)
187+
n += nameLen
171188
v := strings.Join(values, headerValueSeparator)
172-
if err = binary.Write(w, binary.BigEndian, uint32(len(v))); err != nil {
189+
vLen := len(v)
190+
if vLen > math.MaxUint32 {
191+
return n, &Error{InvalidControlFrame, 0}
192+
}
193+
if err = binary.Write(w, binary.BigEndian, uint32(vLen)); err != nil {
173194
return
174195
}
175196
n += 2
176197
if _, err = io.WriteString(w, v); err != nil {
177198
return
178199
}
179-
n += len(v)
200+
n += vLen
180201
}
181202
return
182203
}
@@ -200,7 +221,11 @@ func (f *Framer) writeSynStreamFrame(frame *SynStreamFrame) (err error) {
200221
// Set ControlFrameHeader.
201222
frame.CFHeader.version = Version
202223
frame.CFHeader.frameType = TypeSynStream
203-
frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 10)
224+
hLen := len(f.headerBuf.Bytes()) + 10
225+
if hLen > MaxDataLength {
226+
return &Error{InvalidControlFrame, 0}
227+
}
228+
frame.CFHeader.length = uint32(hLen)
204229

205230
// Serialize frame to Writer.
206231
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
@@ -244,7 +269,11 @@ func (f *Framer) writeSynReplyFrame(frame *SynReplyFrame) (err error) {
244269
// Set ControlFrameHeader.
245270
frame.CFHeader.version = Version
246271
frame.CFHeader.frameType = TypeSynReply
247-
frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 4)
272+
hLen := len(f.headerBuf.Bytes()) + 4
273+
if hLen > MaxDataLength {
274+
return &Error{InvalidControlFrame, 0}
275+
}
276+
frame.CFHeader.length = uint32(hLen)
248277

249278
// Serialize frame to Writer.
250279
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
@@ -279,7 +308,11 @@ func (f *Framer) writeHeadersFrame(frame *HeadersFrame) (err error) {
279308
// Set ControlFrameHeader.
280309
frame.CFHeader.version = Version
281310
frame.CFHeader.frameType = TypeHeaders
282-
frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 4)
311+
hLen := len(f.headerBuf.Bytes()) + 4
312+
if hLen > MaxDataLength {
313+
return &Error{InvalidControlFrame, 0}
314+
}
315+
frame.CFHeader.length = uint32(hLen)
283316

284317
// Serialize frame to Writer.
285318
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
@@ -307,7 +340,11 @@ func (f *Framer) writeDataFrame(frame *DataFrame) (err error) {
307340
if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
308341
return
309342
}
310-
flagsAndLength := uint32(frame.Flags)<<24 | uint32(len(frame.Data))
343+
dLen := len(frame.Data)
344+
if dLen > MaxDataLength {
345+
return &Error{InvalidDataFrame, frame.StreamId}
346+
}
347+
flagsAndLength := uint32(frame.Flags)<<24 | uint32(dLen)
311348
if err = binary.Write(f.w, binary.BigEndian, flagsAndLength); err != nil {
312349
return
313350
}

0 commit comments

Comments
 (0)