diff --git a/backport-CVE-2024-56326.patch b/backport-CVE-2024-56326.patch new file mode 100644 index 0000000000000000000000000000000000000000..b9e7a6dca709bfc3df7cfa4c80a468cb09e4a532 --- /dev/null +++ b/backport-CVE-2024-56326.patch @@ -0,0 +1,171 @@ +From 48b0687e05a5466a91cd5812d604fa37ad0943b4 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 + +Reference:https://github.com/pallets/jinja/commit/48b0687e05a5466a91cd5812d604fa37ad0943b4 + +--- + Jinja2-2.11.2/CHANGES.rst | 3 ++ + Jinja2-2.11.2/src/jinja2/sandbox.py | 67 +++++++++++++++++----------- + Jinja2-2.11.2/tests/test_security.py | 17 +++++++ + 3 files changed, 60 insertions(+), 27 deletions(-) + +diff --git a/Jinja2-2.11.2/CHANGES.rst b/Jinja2-2.11.2/CHANGES.rst +index 2c7614b..61b7908 100644 +--- a/Jinja2-2.11.2/CHANGES.rst ++++ b/Jinja2-2.11.2/CHANGES.rst +@@ -1,5 +1,8 @@ + .. currentmodule:: jinja2 + ++- The sandboxed environment handles indirect calls to ``str.format``, such as ++ by passing a stored reference to a filter that calls its argument. ++ :ghsa:`q2x7-8rv6-6q7h` + - The ``xmlattr`` filter does not allow keys with ``/`` solidus, ``>`` + greater-than sign, or ``=`` equals sign, in addition to disallowing spaces. + Regardless of any validation done by Jinja, user input should never be used +diff --git a/Jinja2-2.11.2/src/jinja2/sandbox.py b/Jinja2-2.11.2/src/jinja2/sandbox.py +index cfd7993..2a79cf9 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,50 @@ 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): ++ """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 = value.__self__ ++ ++ if not isinstance(f_self, str): ++ return None ++ ++ str_type = type(f_self) ++ is_format_map = value.__name__ == "format_map" ++ formatter = SandboxedFormatter(self) ++ ++ 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: ++ vformat = formatter.vformat ++ ++ def wrapper(*args, **kwargs): ++ if is_format_map: ++ if kwargs: ++ raise TypeError("format_map() takes no keyword arguments") ++ ++ if len(args) != 1: + raise TypeError( +- "format_map() takes exactly one argument %d given" +- % (len(args) + (kwargs is not None)) ++ f"format_map() takes exactly one argument ({len(args)} given)" + ) + + kwargs = args[0] +- args = None +- +- kwargs = _MagicFormatMapping(args, kwargs) +- rv = formatter.vformat(s, args, kwargs) +- return type(s)(rv) ++ args = () ++ return str_type(vformat(f_self, args, kwargs)) ++ 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.33.0 + diff --git a/python-jinja2.spec b/python-jinja2.spec index d69ca9917b75e361a2d246e98a7fba90f65ad9c6..75e73891716fe2c3139b824f4c0d3d5c6dedaad6 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/ @@ -11,6 +11,7 @@ Source0: https://files.pythonhosted.org/packages/source/J/Jinja2/Jinja2-% Patch6000: backport-CVE-2020-28493.patch Patch6001: backport-CVE-2024-22195.patch Patch6002: backport-CVE-2024-34064.patch +Patch6003: backport-CVE-2024-56326.patch Patch9000: huawei-replace-instances-of-the-older-style-tmpdir-fixture.patch @@ -110,6 +111,12 @@ popd %doc Jinja2-%{version}/ext Jinja2-%{version}/examples %changelog +* Wed Dec 25 2024 weihaohao - 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