From d8d37efb5fcf62f5d45eaac63ca5c29d6d3cc21c Mon Sep 17 00:00:00 2001 From: changtao Date: Sat, 14 Dec 2024 22:05:22 +0800 Subject: [PATCH] fix CVE-2024-56326 --- backport-CVE-2024-56326-2.patch | 73 +++++++++++++++ backport-CVE-2024-56326-3.patch | 31 +++++++ backport-CVE-2024-56326.patch | 157 ++++++++++++++++++++++++++++++++ python-jinja2.spec | 11 ++- 4 files changed, 271 insertions(+), 1 deletion(-) create mode 100644 backport-CVE-2024-56326-2.patch create mode 100644 backport-CVE-2024-56326-3.patch create mode 100644 backport-CVE-2024-56326.patch diff --git a/backport-CVE-2024-56326-2.patch b/backport-CVE-2024-56326-2.patch new file mode 100644 index 0000000..f1fc629 --- /dev/null +++ b/backport-CVE-2024-56326-2.patch @@ -0,0 +1,73 @@ +From 98b40f8dd96cf4f2997e7dc935d2fe7b9efd24ab Mon Sep 17 00:00:00 2001 +From: changtao +Date: Sun, 15 Dec 2024 07:14:04 +0800 +Subject: [PATCH] fix CVE-2024-56326 + +--- + Jinja2-2.11.2/src/jinja2/sandbox.py | 21 ++++++++++----------- + 1 file changed, 10 insertions(+), 11 deletions(-) + +diff --git a/Jinja2-2.11.2/src/jinja2/sandbox.py b/Jinja2-2.11.2/src/jinja2/sandbox.py +index 3f78075..4ddd50a 100644 +--- a/Jinja2-2.11.2/src/jinja2/sandbox.py ++++ b/Jinja2-2.11.2/src/jinja2/sandbox.py +@@ -423,25 +423,24 @@ class SandboxedEnvironment(Environment): + exc=SecurityError, + ) + +- def wrap_str_format(self, value: t.Any) -> t.Optional[t.Callable[..., str]]: ++ def wrap_str_format(self, value): + """If the given value is a ``str.format`` or ``str.format_map`` method, +- return a new function than handles sandboxing. This is done at access ++ return a new function that handles sandboxing. This is done at access + rather than in :meth:`call`, so that calls made without ``call`` are + also sandboxed. + """ +- if not isinstance( +- value, (types.MethodType, types.BuiltinMethodType) +- ) or value.__name__ not in ("format", "format_map"): ++ if not isinstance(value, (types.MethodType, types.BuiltinMethodType)) or value.__name__ not in ("format", "format_map"): + return None + +- f_self: t.Any = value.__self__ ++ f_self = value.__self__ + + if not isinstance(f_self, str): + return None + +- str_type: t.Type[str] = type(f_self) ++ str_type = type(f_self) + is_format_map = value.__name__ == "format_map" +- formatter: SandboxedFormatter ++ formatter = None ++ + if isinstance(f_self, Markup): + formatter = SandboxedEscapeFormatter(self, escape=f_self.escape) + else: +@@ -449,20 +448,20 @@ class SandboxedEnvironment(Environment): + + vformat = formatter.vformat + +- def wrapper(*args: t.Any, **kwargs: t.Any) -> str: ++ def wrapper(*args, **kwargs): + if is_format_map: + if kwargs: + raise TypeError("format_map() takes no keyword arguments") + + if len(args) != 1: + raise TypeError( +- f"format_map() takes exactly one argument ({len(args)} given)" ++ "format_map() takes exactly one argument ({0} given)".format(len(args)) + ) + + kwargs = args[0] + args = () +- return str_type(vformat(f_self, args, kwargs)) + ++ return str_type(vformat(f_self, args, kwargs)) + + return update_wrapper(wrapper, value) + +-- +2.43.0 + diff --git a/backport-CVE-2024-56326-3.patch b/backport-CVE-2024-56326-3.patch new file mode 100644 index 0000000..5ce2ed1 --- /dev/null +++ b/backport-CVE-2024-56326-3.patch @@ -0,0 +1,31 @@ +From b23759fa6498f200f7557d40264515d8cf41cb1d Mon Sep 17 00:00:00 2001 +From: changtao +Date: Sun, 15 Dec 2024 11:59:30 +0800 +Subject: [PATCH] fix CVE-2024-56326 + +--- + Jinja2-2.11.2/tests/test_security.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/Jinja2-2.11.2/tests/test_security.py b/Jinja2-2.11.2/tests/test_security.py +index 2e2af69..0d3e60c 100644 +--- a/Jinja2-2.11.2/tests/test_security.py ++++ b/Jinja2-2.11.2/tests/test_security.py +@@ -179,12 +179,12 @@ class TestStringFormat(object): + + def test_safe_format_safety(self): + env = SandboxedEnvironment() +- t = env.from_string('{{ ("a{0.__class__}b{1}"|safe).format(42, "") }}') ++ t = env.from_string('{{ ("a{0}b{1}"|safe).format("", "") }}') + assert t.render() == "ab<foo>" + + def test_safe_format_all_okay(self): + env = SandboxedEnvironment() +- t = env.from_string('{{ ("a{0.foo}b{1}"|safe).format({"foo": 42}, "") }}') ++ t = env.from_string('{{ ("a{0[foo]}b{1}"|safe).format({"foo": 42}, "") }}') + assert t.render() == "a42b<foo>" + + +-- +2.43.0 + diff --git a/backport-CVE-2024-56326.patch b/backport-CVE-2024-56326.patch new file mode 100644 index 0000000..5d8bf58 --- /dev/null +++ b/backport-CVE-2024-56326.patch @@ -0,0 +1,157 @@ +From 91a972f5808973cd441f4dc06873b2f8378f30c7 Mon Sep 17 00:00:00 2001 +From: Lydxn +Date: Mon, 23 Sep 2024 15:09:10 -0700 +Subject: [PATCH] sandbox indirect calls to str.format +--- + Jinja2-2.11.2/src/jinja2/sandbox.py | 72 +++++++++++++++++----------- + Jinja2-2.11.2/tests/test_security.py | 17 +++++++ + 2 files changed, 60 insertions(+), 29 deletions(-) + +diff --git a/Jinja2-2.11.2/src/jinja2/sandbox.py b/Jinja2-2.11.2/src/jinja2/sandbox.py +index cfd7993..3f78075 100644 +--- a/Jinja2-2.11.2/src/jinja2/sandbox.py ++++ b/Jinja2-2.11.2/src/jinja2/sandbox.py +@@ -6,6 +6,7 @@ import operator + import types + import warnings + from collections import deque ++from functools import update_wrapper + from string import Formatter + + from markupsafe import EscapeFormatter +@@ -153,16 +154,6 @@ class _MagicFormatMapping(abc.Mapping): + return len(self._kwargs) + + +-def inspect_format_method(callable): +- if not isinstance( +- callable, (types.MethodType, types.BuiltinMethodType) +- ) or callable.__name__ not in ("format", "format_map"): +- return None +- obj = callable.__self__ +- if isinstance(obj, string_types): +- return obj +- +- + def safe_range(*args): + """A range that can't generate ranges with a length of more than + MAX_RANGE items. +@@ -394,6 +385,9 @@ class SandboxedEnvironment(Environment): + except AttributeError: + pass + else: ++ fmt = self.wrap_str_format(value) ++ if fmt is not None: ++ return fmt + if self.is_safe_attribute(obj, argument, value): + return value + return self.unsafe_undefined(obj, argument) +@@ -411,6 +405,9 @@ class SandboxedEnvironment(Environment): + except (TypeError, LookupError): + pass + else: ++ fmt = self.wrap_str_format(value) ++ if fmt is not None: ++ return fmt + if self.is_safe_attribute(obj, attribute, value): + return value + return self.unsafe_undefined(obj, attribute) +@@ -426,34 +423,51 @@ class SandboxedEnvironment(Environment): + exc=SecurityError, + ) + +- def format_string(self, s, args, kwargs, format_func=None): +- """If a format call is detected, then this is routed through this +- method so that our safety sandbox can be used for it. ++ def wrap_str_format(self, value: t.Any) -> t.Optional[t.Callable[..., str]]: ++ """If the given value is a ``str.format`` or ``str.format_map`` method, ++ return a new function than handles sandboxing. This is done at access ++ rather than in :meth:`call`, so that calls made without ``call`` are ++ also sandboxed. + """ +- if isinstance(s, Markup): +- formatter = SandboxedEscapeFormatter(self, s.escape) ++ if not isinstance( ++ value, (types.MethodType, types.BuiltinMethodType) ++ ) or value.__name__ not in ("format", "format_map"): ++ return None ++ ++ f_self: t.Any = value.__self__ ++ ++ if not isinstance(f_self, str): ++ return None ++ ++ str_type: t.Type[str] = type(f_self) ++ is_format_map = value.__name__ == "format_map" ++ formatter: SandboxedFormatter ++ if isinstance(f_self, Markup): ++ formatter = SandboxedEscapeFormatter(self, escape=f_self.escape) + else: + formatter = SandboxedFormatter(self) + +- if format_func is not None and format_func.__name__ == "format_map": +- if len(args) != 1 or kwargs: +- raise TypeError( +- "format_map() takes exactly one argument %d given" +- % (len(args) + (kwargs is not None)) +- ) ++ vformat = formatter.vformat ++ ++ def wrapper(*args: t.Any, **kwargs: t.Any) -> str: ++ if is_format_map: ++ if kwargs: ++ raise TypeError("format_map() takes no keyword arguments") ++ ++ if len(args) != 1: ++ raise TypeError( ++ f"format_map() takes exactly one argument ({len(args)} given)" ++ ) ++ ++ kwargs = args[0] ++ args = () ++ return str_type(vformat(f_self, args, kwargs)) + +- kwargs = args[0] +- args = None + +- kwargs = _MagicFormatMapping(args, kwargs) +- rv = formatter.vformat(s, args, kwargs) +- return type(s)(rv) ++ return update_wrapper(wrapper, value) + + def call(__self, __context, __obj, *args, **kwargs): # noqa: B902 + """Call an object from sandboxed code.""" +- fmt = inspect_format_method(__obj) +- if fmt is not None: +- return __self.format_string(fmt, args, kwargs, __obj) + + # the double prefixes are to avoid double keyword argument + # errors when proxying the call. +diff --git a/Jinja2-2.11.2/tests/test_security.py b/Jinja2-2.11.2/tests/test_security.py +index 7e8974c..2e2af69 100644 +--- a/Jinja2-2.11.2/tests/test_security.py ++++ b/Jinja2-2.11.2/tests/test_security.py +@@ -208,3 +208,20 @@ class TestStringFormatMap(object): + '{{ ("a{x.foo}b{y}"|safe).format_map({"x":{"foo": 42}, "y":""}) }}' + ) + assert t.render() == "a42b<foo>" ++ ++ def test_indirect_call(self): ++ def run(value, arg): ++ return value.run(arg) ++ ++ env = SandboxedEnvironment() ++ env.filters["run"] = run ++ t = env.from_string( ++ """{% set ++ ns = namespace(run="{0.__call__.__builtins__[__import__]}".format) ++ %} ++ {{ ns | run(not_here) }} ++ """ ++ ) ++ ++ with pytest.raises(SecurityError): ++ t.render() +-- +2.43.0 + diff --git a/python-jinja2.spec b/python-jinja2.spec index d69ca99..2ddb69c 100644 --- a/python-jinja2.spec +++ b/python-jinja2.spec @@ -2,7 +2,7 @@ Name: python-jinja2 Version: 2.11.2 -Release: 7 +Release: 8 Summary: A full-featured template engine for Python License: BSD URL: http://jinja.pocoo.org/ @@ -13,6 +13,9 @@ Patch6001: backport-CVE-2024-22195.patch Patch6002: backport-CVE-2024-34064.patch Patch9000: huawei-replace-instances-of-the-older-style-tmpdir-fixture.patch +Patch9001: backport-CVE-2024-56326.patch +Patch9002: backport-CVE-2024-56326-2.patch +Patch9003: backport-CVE-2024-56326-3.patch BuildArch: noarch @@ -110,6 +113,12 @@ popd %doc Jinja2-%{version}/ext Jinja2-%{version}/examples %changelog +* Wed Dec 25 2024 changtao - 2.11.2-8 + Type:CVE + CVE:CVE-2024-56326 + SUG:NA + DESC:fix CVE-2024-56326 + * Fri May 10 2024 weihaohao - 2.11.2-7 Type:CVE CVE:CVE-2024-34064 -- Gitee