Skip to content

Commit 6d63eae

Browse files
committed
Reject padded frames with invalid padding lengths
1 parent 28aa5b9 commit 6d63eae

File tree

3 files changed

+42
-2
lines changed

3 files changed

+42
-2
lines changed

hyperframe/exceptions.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,10 @@ def __str__(self):
2323
"UnknownFrameError: Unknown frame type 0x%X received, "
2424
"length %d bytes" % (self.frame_type, self.length)
2525
)
26+
27+
28+
class InvalidPaddingError(ValueError):
29+
"""
30+
A frame with invalid padding was received.
31+
"""
32+
pass

hyperframe/frame.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import collections
1111
import struct
1212

13-
from .exceptions import UnknownFrameError
13+
from .exceptions import UnknownFrameError, InvalidPaddingError
1414
from .flags import Flag, Flags
1515

1616
# The maximum initial length of a frame. Some frames have shorter maximum lengths.
@@ -232,6 +232,9 @@ def parse_body(self, data):
232232
self.data = data[padding_data_length:len(data)-self.total_padding].tobytes()
233233
self.body_len = len(data)
234234

235+
if self.total_padding >= self.body_len:
236+
raise InvalidPaddingError("Padding is too long.")
237+
235238
@property
236239
def flow_controlled_length(self):
237240
"""
@@ -393,6 +396,9 @@ def parse_body(self, data):
393396
self.data = data[padding_data_length + 4:].tobytes()
394397
self.body_len = len(data)
395398

399+
if self.total_padding >= self.body_len:
400+
raise InvalidPaddingError("Padding is too long.")
401+
396402

397403
class PingFrame(Frame):
398404
"""
@@ -564,6 +570,9 @@ def parse_body(self, data):
564570
self.body_len = len(data)
565571
self.data = data[priority_data_length:len(data)-self.total_padding].tobytes()
566572

573+
if self.total_padding >= self.body_len:
574+
raise InvalidPaddingError("Padding is too long.")
575+
567576

568577
class ContinuationFrame(Frame):
569578
"""

test/test_frames.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
PushPromiseFrame, PingFrame, GoAwayFrame, WindowUpdateFrame, HeadersFrame,
55
ContinuationFrame, AltSvcFrame, Origin, BlockedFrame,
66
)
7-
from hyperframe.exceptions import UnknownFrameError
7+
from hyperframe.exceptions import UnknownFrameError, InvalidPaddingError
88
import pytest
99

1010

@@ -146,6 +146,14 @@ def test_body_length_behaves_correctly(self):
146146
data = f.serialize()
147147
assert f.body_len == 300
148148

149+
def test_data_frame_with_invalid_padding_fails_to_parse(self):
150+
# This frame has a padding length of 6 bytes, but a total length of
151+
# only 5.
152+
data = b'\x00\x00\x05\x00\x0b\x00\x00\x00\x01\x06\x54\x65\x73\x74'
153+
154+
with pytest.raises(InvalidPaddingError):
155+
decode_frame(data)
156+
149157

150158
class TestPriorityFrame(object):
151159
payload = b'\x00\x00\x05\x02\x00\x00\x00\x00\x01\x80\x00\x00\x04\x40'
@@ -308,6 +316,14 @@ def test_push_promise_frame_parses_properly(self):
308316
assert f.data == b'hello world'
309317
assert f.body_len == 15
310318

319+
def test_push_promise_frame_with_invalid_padding_fails_to_parse(self):
320+
# This frame has a padding length of 6 bytes, but a total length of
321+
# only 5.
322+
data = b'\x00\x00\x05\x05\x08\x00\x00\x00\x01\x06\x54\x65\x73\x74'
323+
324+
with pytest.raises(InvalidPaddingError):
325+
decode_frame(data)
326+
311327

312328
class TestPingFrame(object):
313329
def test_ping_frame_has_only_one_flag(self):
@@ -482,6 +498,14 @@ def test_headers_frame_with_priority_serializes_properly(self):
482498

483499
assert f.serialize() == s
484500

501+
def test_headers_frame_with_invalid_padding_fails_to_parse(self):
502+
# This frame has a padding length of 6 bytes, but a total length of
503+
# only 5.
504+
data = b'\x00\x00\x05\x01\x08\x00\x00\x00\x01\x06\x54\x65\x73\x74'
505+
506+
with pytest.raises(InvalidPaddingError):
507+
decode_frame(data)
508+
485509

486510
class TestContinuationFrame(object):
487511
def test_continuation_frame_flags(self):

0 commit comments

Comments
 (0)