Skip to content

Commit 7d01a7d

Browse files
authored
Merge pull request python-hyper#23 from python-hyper/issue/22
CVE-2016-6580
2 parents 4374888 + f09599a commit 7d01a7d

File tree

8 files changed

+157
-2
lines changed

8 files changed

+157
-2
lines changed

HISTORY.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,23 @@
11
Changelog
22
=========
33

4+
1.2.0 (2016-08-04)
5+
------------------
6+
7+
**Security Fixes**
8+
9+
- CVE-2016-6580: All versions of this library prior to 1.2.0 are vulnerable to
10+
a denial of service attack whereby a remote peer can cause a user to insert
11+
an unbounded number of streams into the priority tree, eventually consuming
12+
all available memory.
13+
14+
This version adds a ``TooManyStreamsError`` exception that is raised when
15+
too many streams are inserted into the priority tree. It also adds a keyword
16+
argument to the priority tree, ``maximum_streams``, which limits how many
17+
streams may be inserted. By default, this number is set to 1000.
18+
Implementations should strongly consider whether they can set this value
19+
lower.
20+
421
1.1.1 (2016-05-28)
522
------------------
623

docs/source/api.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ Exceptions
1717
.. autoclass:: priority.DuplicateStreamError
1818

1919
.. autoclass:: priority.MissingStreamError
20+
21+
.. autoclass:: priority.TooManyStreamsError

docs/source/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Contents:
2323
installation
2424
using-priority
2525
api
26+
security/index
2627
license
2728
authors
2829

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
:orphan:
2+
3+
DoS via Unlimited Stream Insertion
4+
==================================
5+
6+
Hyper Project security advisory, August 4th 2016.
7+
8+
Vulnerability
9+
-------------
10+
11+
A HTTP/2 implementation built using the priority library could be targetted by
12+
a malicious peer by having that peer assign priority information for every
13+
possible HTTP/2 stream ID. The priority tree would happily continue to store
14+
the priority information for each stream, and would therefore allocate
15+
unbounded amounts of memory. Attempting to actually *use* a tree like this
16+
would also cause extremely high CPU usage to maintain the tree.
17+
18+
We are not aware of any active exploits of this vulnerability, but as this
19+
class of attack was publicly described in `this report`_, users should assume
20+
that they are at imminent risk of this kind of attack.
21+
22+
Info
23+
----
24+
25+
This issue has been given the name CVE-2016-6580.
26+
27+
Affected Versions
28+
-----------------
29+
30+
This issue affects all versions of the priority library prior to 1.2.0.
31+
32+
The Solution
33+
------------
34+
35+
In version 1.2.0, the priority library limits the maximum number of streams
36+
that can be inserted into the tree. By default this limit is 1000, but it is
37+
user-configurable.
38+
39+
If it is necessary to backport a patch, the patch can be found in
40+
`this GitHub pull request`_.
41+
42+
Recommendations
43+
---------------
44+
45+
We suggest you take the following actions immediately, in order of preference:
46+
47+
1. Update priority to 1.2.0 immediately, and consider revising the maximum
48+
number of streams downward to a suitable value for your application.
49+
2. Backport the patch made available on GitHub.
50+
3. Manually enforce a limit on the number of priority settings you'll allow at
51+
once.
52+
53+
Timeline
54+
--------
55+
56+
This class of vulnerability was publicly reported in `this report`_ on the
57+
3rd of August. We requested a CVE ID from Mitre the same day.
58+
59+
Priority 1.2.0 was released on the 4th of August, at the same time as the
60+
publication of this advisory.
61+
62+
63+
.. _this report: http://www.imperva.com/docs/Imperva_HII_HTTP2.pdf
64+
.. _this GitHub pull request: https://github.com/python-hyper/priority/pull/23

docs/source/security/index.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Vulnerability Notifications
2+
===========================
3+
4+
This section of the page contains all known vulnerabilities in the priority
5+
library. These vulnerabilities have all been reported to us via our
6+
`vulnerability disclosure policy`_.
7+
8+
Known Vulnerabilities
9+
---------------------
10+
11+
+----+---------------------------+----------------+---------------+--------------+---------------+
12+
| \# | Vulnerability | Date Announced | First Version | Last Version | CVE |
13+
+====+===========================+================+===============+==============+===============+
14+
| 1 | :doc:`DoS via unlimited | 2016-08-04 | 1.0.0 | 1.1.1 | CVE-2016-6580 |
15+
| | stream insertion. | | | | |
16+
| | <CVE-2016-6580>` | | | | |
17+
+----+---------------------------+----------------+---------------+--------------+---------------+
18+
19+
.. _vulnerability disclosure policy: http://python-hyper.org/en/latest/security.html#vulnerability-disclosure

src/priority/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
"""
55
from .priority import ( # noqa
66
Stream, PriorityTree, DeadlockError, PriorityLoop, DuplicateStreamError,
7-
MissingStreamError
7+
MissingStreamError, TooManyStreamsError
88
)

src/priority/priority.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,16 @@ class MissingStreamError(KeyError, Exception):
4343
pass
4444

4545

46+
class TooManyStreamsError(Exception):
47+
"""
48+
An attempt was made to insert a dangerous number of streams into the
49+
priority tree at the same time.
50+
51+
.. versionadded:: 1.2.0
52+
"""
53+
pass
54+
55+
4656
class Stream(object):
4757
"""
4858
Priority information for a given stream.
@@ -199,13 +209,33 @@ class PriorityTree(object):
199209
A HTTP/2 Priority Tree.
200210
201211
This tree stores HTTP/2 streams according to their HTTP/2 priorities.
212+
213+
.. versionchanged:: 1.2.0
214+
Added ``maximum_streams`` keyword argument.
215+
216+
:param maximum_streams: The maximum number of streams that may be active in
217+
the priority tree at any one time. If this number is exceeded, the
218+
priority tree will raise a :class:`TooManyStreamsError
219+
<priority.TooManyStreamsError>` and will refuse to insert the stream.
220+
221+
This parameter exists to defend against the possibility of DoS attack
222+
by attempting to overfill the priority tree. If any endpoint is
223+
attempting to manage the priority of this many streams at once it is
224+
probably trying to screw with you, so it is sensible to simply refuse
225+
to play ball at that point.
226+
227+
While we allow the user to configure this, we don't really *expect*
228+
them too, unless they want to be even more conservative than we are by
229+
default.
230+
:type maximum_streams: ``int``
202231
"""
203-
def __init__(self):
232+
def __init__(self, maximum_streams=1000):
204233
# This flat array keeps hold of all the streams that are logically
205234
# dependent on stream 0.
206235
self._root_stream = Stream(stream_id=0, weight=1)
207236
self._root_stream.active = False
208237
self._streams = {0: self._root_stream}
238+
self._maximum_streams = maximum_streams
209239

210240
def _exclusive_insert(self, parent_stream, inserted_stream):
211241
"""
@@ -233,6 +263,13 @@ def insert_stream(self,
233263
if stream_id in self._streams:
234264
raise DuplicateStreamError("Stream %d already in tree" % stream_id)
235265

266+
if (len(self._streams) + 1) > self._maximum_streams:
267+
raise TooManyStreamsError(
268+
"Refusing to insert %d streams into priority tree at once" % (
269+
self._maximum_streams + 1
270+
)
271+
)
272+
236273
stream = Stream(stream_id, weight)
237274

238275
if exclusive:

test/test_priority.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,21 @@ def test_priority_raises_good_errors_for_missing_streams(self):
292292
with pytest.raises(priority.MissingStreamError):
293293
p.remove_stream(3)
294294

295+
@pytest.mark.parametrize('count', range(2, 10000, 100))
296+
def test_priority_refuses_to_allow_too_many_streams_in_tree(self, count):
297+
"""
298+
Attempting to insert more streams than maximum_streams into the tree
299+
fails.
300+
"""
301+
p = priority.PriorityTree(maximum_streams=count)
302+
303+
# This isn't an off-by-one error: stream 0 is in the tree by default.
304+
for x in range(1, count):
305+
p.insert_stream(x)
306+
307+
with pytest.raises(priority.TooManyStreamsError):
308+
p.insert_stream(x + 1)
309+
295310

296311
class TestPriorityTreeOutput(object):
297312
"""

0 commit comments

Comments
 (0)