Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions changes/bd45773cff22d0cf547370e90918ba58.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
desc: Added a patch for Python ``http.cookies`` module to address CVE-2024-7592 exposure.
prs: []
type: bug
...
15 changes: 15 additions & 0 deletions synapse/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import contextlib
import collections

import http.cookies

import yaml
import regex

Expand All @@ -38,6 +40,8 @@
import synapse.lib.structlog as s_structlog

import synapse.vendor.cpython.lib.ipaddress as ipaddress
import synapse.vendor.cpython.lib.http.cookies as v_cookies


try:
from yaml import CSafeLoader as Loader
Expand Down Expand Up @@ -1218,6 +1222,17 @@
assert n > plen
return f'{text[:mlen]}{placeholder}'

def _patch_http_cookies():
'''
Patch stdlib http.cookies._unquote from the 3.11.10 implementation if
the interpreter we are using is not patched for CVE-2024-7592.
'''
if not hasattr(http.cookies, '_QuotePatt'):
return
http.cookies._unquote = v_cookies._unquote

Check warning on line 1232 in synapse/common.py

View check run for this annotation

Codecov / codecov/patch

synapse/common.py#L1232

Added line #L1232 was not covered by tests

_patch_http_cookies()

# TODO: Switch back to using asyncio.wait_for when we are using py 3.12+
# This is a workaround for a race where asyncio.wait_for can end up
# ignoring cancellation https://github.com/python/cpython/issues/86296
Expand Down
Empty file.
59 changes: 59 additions & 0 deletions synapse/vendor/cpython/lib/http/cookies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
##############################################################################
# Taken from the cpython 3.11 source branch after the 3.11.10 release.
##############################################################################
####
# Copyright 2000 by Timothy O'Malley <timo@alum.mit.edu>
#
# All Rights Reserved
#
# Permission to use, copy, modify, and distribute this software
# and its documentation for any purpose and without fee is hereby
# granted, provided that the above copyright notice appear in all
# copies and that both that copyright notice and this permission
# notice appear in supporting documentation, and that the name of
# Timothy O'Malley not be used in advertising or publicity
# pertaining to distribution of the software without specific, written
# prior permission.
#
# Timothy O'Malley DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
# SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS, IN NO EVENT SHALL Timothy O'Malley BE LIABLE FOR
# ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
#

#
# Import our required modules
#
import re

_unquote_sub = re.compile(r'\\(?:([0-3][0-7][0-7])|(.))').sub

def _unquote_replace(m):
if m[1]:
return chr(int(m[1], 8))

Check warning on line 37 in synapse/vendor/cpython/lib/http/cookies.py

View check run for this annotation

Codecov / codecov/patch

synapse/vendor/cpython/lib/http/cookies.py#L36-L37

Added lines #L36 - L37 were not covered by tests
else:
return m[2]

Check warning on line 39 in synapse/vendor/cpython/lib/http/cookies.py

View check run for this annotation

Codecov / codecov/patch

synapse/vendor/cpython/lib/http/cookies.py#L39

Added line #L39 was not covered by tests

def _unquote(str):
# If there aren't any doublequotes,
# then there can't be any special characters. See RFC 2109.
if str is None or len(str) < 2:
return str
if str[0] != '"' or str[-1] != '"':
return str

Check warning on line 47 in synapse/vendor/cpython/lib/http/cookies.py

View check run for this annotation

Codecov / codecov/patch

synapse/vendor/cpython/lib/http/cookies.py#L44-L47

Added lines #L44 - L47 were not covered by tests

# We have to assume that we must decode this string.
# Down to work.

# Remove the "s
str = str[1:-1]

Check warning on line 53 in synapse/vendor/cpython/lib/http/cookies.py

View check run for this annotation

Codecov / codecov/patch

synapse/vendor/cpython/lib/http/cookies.py#L53

Added line #L53 was not covered by tests

# Check for special sequences. Examples:
# \012 --> \n
# \" --> "
#
return _unquote_sub(_unquote_replace, str)

Check warning on line 59 in synapse/vendor/cpython/lib/http/cookies.py

View check run for this annotation

Codecov / codecov/patch

synapse/vendor/cpython/lib/http/cookies.py#L59

Added line #L59 was not covered by tests
49 changes: 49 additions & 0 deletions synapse/vendor/cpython/lib/test/test_http_cookies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
##############################################################################
# Taken from the cpython 3.11 source branch after the 3.11.10 release.
# It has been modified for vendored imports and vendored test harness.
##############################################################################

# Simple test suite for http/cookies.py

from http import cookies

# s_v_utils runs the monkeypatch
import synapse.vendor.utils as s_v_utils

class CookieTests(s_v_utils.VendorTest):

def test_unquote(self):
cases = [
(r'a="b=\""', 'b="'),
(r'a="b=\\"', 'b=\\'),
(r'a="b=\="', 'b=='),
(r'a="b=\n"', 'b=n'),
(r'a="b=\042"', 'b="'),
(r'a="b=\134"', 'b=\\'),
(r'a="b=\377"', 'b=\xff'),
(r'a="b=\400"', 'b=400'),
(r'a="b=\42"', 'b=42'),
(r'a="b=\\042"', 'b=\\042'),
(r'a="b=\\134"', 'b=\\134'),
(r'a="b=\\\""', 'b=\\"'),
(r'a="b=\\\042"', 'b=\\"'),
(r'a="b=\134\""', 'b=\\"'),
(r'a="b=\134\042"', 'b=\\"'),
]
for encoded, decoded in cases:
with self.subTest(encoded):
C = cookies.SimpleCookie()
C.load(encoded)
self.assertEqual(C['a'].value, decoded)

def test_unquote_large(self):
n = 10**6
for encoded in r'\\', r'\134':
with self.subTest(encoded):
data = 'a="b=' + encoded * n + ';"'
C = cookies.SimpleCookie()
C.load(data)
value = C['a'].value
self.assertEqual(value[:3], 'b=\\')
self.assertEqual(value[-2:], '\\;')
self.assertEqual(len(value), n + 3)
Loading