!37 [sync] PR-32: Fix CVE-2023-23934 and CVE-2023-25577
From: @openeuler-sync-bot Reviewed-by: @lyn1001 Signed-off-by: @lyn1001
This commit is contained in:
commit
4189be018f
73
CVE-2023-23934.patch
Normal file
73
CVE-2023-23934.patch
Normal file
@ -0,0 +1,73 @@
|
||||
From ff93ffb858db15ec70ba57b7850cb9cb01d531c8 Mon Sep 17 00:00:00 2001
|
||||
From: starlet-dx <15929766099@163.com>
|
||||
Date: Tue, 15 Aug 2023 09:56:10 +0800
|
||||
Subject: [PATCH 1/1] don't strip leading = when parsing cookie
|
||||
|
||||
Origin:
|
||||
https://github.com/pallets/werkzeug/commit/8c2b4b82d0cade0d37e6a88e2cd2413878e8ebd4
|
||||
---
|
||||
src/werkzeug/_internal.py | 13 +++++++++----
|
||||
tests/test_http.py | 2 ++
|
||||
2 files changed, 11 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/werkzeug/_internal.py b/src/werkzeug/_internal.py
|
||||
index 1d2eaf5..fe69ccb 100644
|
||||
--- a/src/werkzeug/_internal.py
|
||||
+++ b/src/werkzeug/_internal.py
|
||||
@@ -40,7 +40,7 @@ _quote_re = re.compile(br"[\\].")
|
||||
_legal_cookie_chars_re = br"[\w\d!#%&\'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\=]"
|
||||
_cookie_re = re.compile(
|
||||
br"""
|
||||
- (?P<key>[^=;]+)
|
||||
+ (?P<key>[^=;]*)
|
||||
(?:\s*=\s*
|
||||
(?P<val>
|
||||
"(?:[^\\"]|\\.)*" |
|
||||
@@ -316,16 +316,21 @@ def _cookie_parse_impl(b):
|
||||
"""Lowlevel cookie parsing facility that operates on bytes."""
|
||||
i = 0
|
||||
n = len(b)
|
||||
+ b += b";"
|
||||
|
||||
while i < n:
|
||||
- match = _cookie_re.search(b + b";", i)
|
||||
+ match = _cookie_re.match(b, i)
|
||||
+
|
||||
if not match:
|
||||
break
|
||||
|
||||
- key = match.group("key").strip()
|
||||
- value = match.group("val") or b""
|
||||
i = match.end(0)
|
||||
+ key = match.group("key").strip()
|
||||
+
|
||||
+ if not key:
|
||||
+ continue
|
||||
|
||||
+ value = match.group("val") or b""
|
||||
yield _cookie_unquote(key), _cookie_unquote(value)
|
||||
|
||||
|
||||
diff --git a/tests/test_http.py b/tests/test_http.py
|
||||
index 5725170..58042c0 100644
|
||||
--- a/tests/test_http.py
|
||||
+++ b/tests/test_http.py
|
||||
@@ -446,6 +446,7 @@ class TestHTTPUtility(object):
|
||||
cookies = http.parse_cookie(
|
||||
"dismiss-top=6; CP=null*; PHPSESSID=0a539d42abc001cdc762809248d4beed;"
|
||||
' a=42; b="\\";"; ; fo234{=bar;blub=Blah;'
|
||||
+ "==__Host-eq=bad;__Host-eq=good;"
|
||||
)
|
||||
assert cookies.to_dict() == {
|
||||
"CP": u"null*",
|
||||
@@ -455,6 +456,7 @@ class TestHTTPUtility(object):
|
||||
"b": u'";',
|
||||
"fo234{": u"bar",
|
||||
"blub": u"Blah",
|
||||
+ "__Host-eq": "good",
|
||||
}
|
||||
|
||||
def test_dump_cookie(self):
|
||||
--
|
||||
2.30.0
|
||||
|
||||
146
CVE-2023-25577.patch
Normal file
146
CVE-2023-25577.patch
Normal file
@ -0,0 +1,146 @@
|
||||
From dbd3af18b9e7e6e081181594fd6a9fb8daa01a91 Mon Sep 17 00:00:00 2001
|
||||
From: starlet-dx <15929766099@163.com>
|
||||
Date: Tue, 15 Aug 2023 10:04:11 +0800
|
||||
Subject: [PATCH 1/1] limit the maximum number of multipart form parts
|
||||
|
||||
Origin:
|
||||
https://github.com/pallets/werkzeug/commit/fe899d0cdf767a7289a8bf746b7f72c2907a1b4b
|
||||
---
|
||||
src/werkzeug/formparser.py | 16 ++++++++++++++--
|
||||
src/werkzeug/wrappers/base_request.py | 8 ++++++++
|
||||
tests/test_formparser.py | 9 +++++++++
|
||||
3 files changed, 31 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/werkzeug/formparser.py b/src/werkzeug/formparser.py
|
||||
index ffdb9b0..40959fb 100644
|
||||
--- a/src/werkzeug/formparser.py
|
||||
+++ b/src/werkzeug/formparser.py
|
||||
@@ -168,6 +168,8 @@ class FormDataParser(object):
|
||||
:param cls: an optional dict class to use. If this is not specified
|
||||
or `None` the default :class:`MultiDict` is used.
|
||||
:param silent: If set to False parsing errors will not be caught.
|
||||
+ :param max_form_parts: The maximum number of parts to be parsed. If this is
|
||||
+ exceeded, a :exc:`~exceptions.RequestEntityTooLarge` exception is raised.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -179,6 +181,7 @@ class FormDataParser(object):
|
||||
max_content_length=None,
|
||||
cls=None,
|
||||
silent=True,
|
||||
+ max_form_parts=None,
|
||||
):
|
||||
if stream_factory is None:
|
||||
stream_factory = default_stream_factory
|
||||
@@ -191,6 +194,7 @@ class FormDataParser(object):
|
||||
cls = MultiDict
|
||||
self.cls = cls
|
||||
self.silent = silent
|
||||
+ self.max_form_parts = max_form_parts
|
||||
|
||||
def get_parse_func(self, mimetype, options):
|
||||
return self.parse_functions.get(mimetype)
|
||||
@@ -244,6 +248,7 @@ class FormDataParser(object):
|
||||
self.errors,
|
||||
max_form_memory_size=self.max_form_memory_size,
|
||||
cls=self.cls,
|
||||
+ max_form_parts=self.max_form_parts,
|
||||
)
|
||||
boundary = options.get("boundary")
|
||||
if boundary is None:
|
||||
@@ -333,10 +338,12 @@ class MultiPartParser(object):
|
||||
max_form_memory_size=None,
|
||||
cls=None,
|
||||
buffer_size=64 * 1024,
|
||||
+ max_form_parts=None,
|
||||
):
|
||||
self.charset = charset
|
||||
self.errors = errors
|
||||
self.max_form_memory_size = max_form_memory_size
|
||||
+ self.max_form_parts = max_form_parts
|
||||
self.stream_factory = (
|
||||
default_stream_factory if stream_factory is None else stream_factory
|
||||
)
|
||||
@@ -528,11 +535,12 @@ class MultiPartParser(object):
|
||||
|
||||
yield _end, None
|
||||
|
||||
- def parse_parts(self, file, boundary, content_length):
|
||||
+ def parse_parts(self, file, boundary, content_length, max_parts=None):
|
||||
"""Generate ``('file', (name, val))`` and
|
||||
``('form', (name, val))`` parts.
|
||||
"""
|
||||
in_memory = 0
|
||||
+ _parts_decoded = 0
|
||||
|
||||
for ellt, ell in self.parse_lines(file, boundary, content_length):
|
||||
if ellt == _begin_file:
|
||||
@@ -562,6 +570,9 @@ class MultiPartParser(object):
|
||||
self.in_memory_threshold_reached(in_memory)
|
||||
|
||||
elif ellt == _end:
|
||||
+ _parts_decoded += 1
|
||||
+ if max_parts is not None and _parts_decoded > max_parts:
|
||||
+ raise exceptions.RequestEntityTooLarge()
|
||||
if is_file:
|
||||
container.seek(0)
|
||||
yield (
|
||||
@@ -577,7 +588,8 @@ class MultiPartParser(object):
|
||||
|
||||
def parse(self, file, boundary, content_length):
|
||||
formstream, filestream = tee(
|
||||
- self.parse_parts(file, boundary, content_length), 2
|
||||
+ self.parse_parts(file, boundary, content_length,
|
||||
+ max_parts=self.max_form_parts), 2
|
||||
)
|
||||
form = (p[1] for p in formstream if p[0] == "form")
|
||||
files = (p[1] for p in filestream if p[0] == "file")
|
||||
diff --git a/src/werkzeug/wrappers/base_request.py b/src/werkzeug/wrappers/base_request.py
|
||||
index 1f21db2..0c1e221 100644
|
||||
--- a/src/werkzeug/wrappers/base_request.py
|
||||
+++ b/src/werkzeug/wrappers/base_request.py
|
||||
@@ -98,6 +98,13 @@ class BaseRequest(object):
|
||||
#: .. versionadded:: 0.5
|
||||
max_form_memory_size = None
|
||||
|
||||
+ #: The maximum number of multipart parts to parse, passed to
|
||||
+ #: :attr:`form_data_parser_class`. Parsing form data with more than this
|
||||
+ #: many parts will raise :exc:`~.RequestEntityTooLarge`.
|
||||
+ #:
|
||||
+ #: .. versionadded:: 2.2.3
|
||||
+ max_form_parts = 1000
|
||||
+
|
||||
#: the class to use for `args` and `form`. The default is an
|
||||
#: :class:`~werkzeug.datastructures.ImmutableMultiDict` which supports
|
||||
#: multiple values per key. alternatively it makes sense to use an
|
||||
@@ -293,6 +300,7 @@ class BaseRequest(object):
|
||||
self.max_form_memory_size,
|
||||
self.max_content_length,
|
||||
self.parameter_storage_class,
|
||||
+ max_form_parts=self.max_form_parts,
|
||||
)
|
||||
|
||||
def _load_form_data(self):
|
||||
diff --git a/tests/test_formparser.py b/tests/test_formparser.py
|
||||
index 6d85838..2a8d635 100644
|
||||
--- a/tests/test_formparser.py
|
||||
+++ b/tests/test_formparser.py
|
||||
@@ -124,6 +124,15 @@ class TestFormParser(object):
|
||||
req.max_form_memory_size = 400
|
||||
strict_eq(req.form["foo"], u"Hello World")
|
||||
|
||||
+ req = Request.from_values(
|
||||
+ input_stream=io.BytesIO(data),
|
||||
+ content_length=len(data),
|
||||
+ content_type="multipart/form-data; boundary=foo",
|
||||
+ method="POST",
|
||||
+ )
|
||||
+ req.max_form_parts = 1
|
||||
+ pytest.raises(RequestEntityTooLarge, lambda: req.form["foo"])
|
||||
+
|
||||
def test_missing_multipart_boundary(self):
|
||||
data = (
|
||||
b"--foo\r\nContent-Disposition: form-field; name=foo\r\n\r\n"
|
||||
--
|
||||
2.30.0
|
||||
|
||||
@ -3,11 +3,13 @@
|
||||
Name: python-werkzeug
|
||||
Summary: A comprehensive WSGI web application library
|
||||
Version: 1.0.1
|
||||
Release: 1
|
||||
Release: 2
|
||||
License: BSD
|
||||
URL: https://github.com/pallets/werkzeug
|
||||
Source0: https://github.com/pallets/werkzeug/archive/1.0.1.tar.gz
|
||||
Patch0: Disable-tests-because-need-pytest-3.9.patch
|
||||
Patch1: CVE-2023-23934.patch
|
||||
Patch2: CVE-2023-25577.patch
|
||||
BuildArch: noarch
|
||||
|
||||
%global _description\
|
||||
@ -123,6 +125,9 @@ popd
|
||||
|
||||
|
||||
%changelog
|
||||
* Mon Aug 14 2023 yaoxin <yao_xin001@hoperun.com> - 1.0.1-2
|
||||
- Fix CVE-2023-23934 and CVE-2023-25577
|
||||
|
||||
* Tue Aug 17 2021 huanghaitao <huanghaitao8@huawei.com> - 1.0.1-1
|
||||
- Update to 1.0.1
|
||||
- Disable tests because need pytest-3.9
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user