diff options
author | CoprDistGit <infra@openeuler.org> | 2023-08-28 06:17:55 +0000 |
---|---|---|
committer | CoprDistGit <infra@openeuler.org> | 2023-08-28 06:17:55 +0000 |
commit | c488fbc28dc66541bf179562113977911856fa86 (patch) | |
tree | 29dde03ec29d0f6f3ddda3233a2c891533b2f0cd | |
parent | 5f37caad6befbdd2c40cd0bbe2dfd1a2684337a4 (diff) |
automatic import of python-reportlabopeneuler22.03_LTS_SP2
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | backport-CVE-2023-33733-fix-RCE-attack-via-method-eval.patch | 346 | ||||
-rw-r--r-- | python-reportlab.spec | 96 | ||||
-rw-r--r-- | sources | 1 |
4 files changed, 444 insertions, 0 deletions
@@ -0,0 +1 @@ +/reportlab-3.6.10.tar.gz diff --git a/backport-CVE-2023-33733-fix-RCE-attack-via-method-eval.patch b/backport-CVE-2023-33733-fix-RCE-attack-via-method-eval.patch new file mode 100644 index 0000000..896f185 --- /dev/null +++ b/backport-CVE-2023-33733-fix-RCE-attack-via-method-eval.patch @@ -0,0 +1,346 @@ +From 1bd6d30aed39acb026f51c309b81d81e8b79e5ad Mon Sep 17 00:00:00 2001 +From: liningjie <liningjie@xfusion.com> +Date: Sat, 17 Jun 2023 18:21:22 +0800 +Subject: [PATCH] CVE-2023-33733 with rl_safe_eval & rl_config.toColorCanUse + changes + +--- + src/reportlab/lib/colors.py | 75 +++++++++++++++++++++++++------ + src/reportlab/lib/rl_safe_eval.py | 71 ++++++++++++++++++++++++++++- + src/reportlab/lib/utils.py | 2 +- + src/reportlab/rl_settings.py | 5 ++- + tests/test_lib_rl_safe_eval.py | 49 ++++++++++++++++++-- + 5 files changed, 181 insertions(+), 21 deletions(-) + +diff --git a/src/reportlab/lib/colors.py b/src/reportlab/lib/colors.py +index 84e8679..09d078f 100644 +--- a/src/reportlab/lib/colors.py ++++ b/src/reportlab/lib/colors.py +@@ -41,7 +41,8 @@ ValueError: css color 'pcmyka(100,0,0,0)' has wrong number of components + ''' + import math, re, functools + from reportlab.lib.rl_accel import fp_str +-from reportlab.lib.utils import asNative, isStr, rl_safe_eval ++from reportlab.lib.utils import asNative, isStr, rl_safe_eval, rl_extended_literal_eval ++from reportlab import rl_config + from ast import literal_eval + + class Color: +@@ -835,6 +836,17 @@ class cssParse: + cssParse=cssParse() + + class toColor: ++ """Accepot an expression returnng a Color subclass. ++ ++ This used to accept arbitrary Python expressions, which resulted in increasngly devilish CVEs and ++ security holes from tie to time. In April 2023 we are creating explicit, "dumb" parsing code to ++ replace this. Acceptable patterns are ++ ++ a Color instance passed in by the Python programmer ++ a named list of colours ('pink' etc') ++ list of 3 or 4 numbers ++ all CSS colour expression ++ """ + _G = {} #globals we like (eventually) + + def __init__(self): +@@ -860,21 +872,58 @@ class toColor: + C = getAllNamedColors() + s = arg.lower() + if s in C: return C[s] +- G = C.copy() +- G.update(self.extraColorsNS) +- if not self._G: +- C = globals() +- self._G = {s:C[s] for s in '''Blacker CMYKColor CMYKColorSep Color ColorType HexColor PCMYKColor PCMYKColorSep Whiter +- _chooseEnforceColorSpace _enforceCMYK _enforceError _enforceRGB _enforceSEP _enforceSEP_BLACK +- _enforceSEP_CMYK _namedColors _re_css asNative cmyk2rgb cmykDistance color2bw colorDistance +- cssParse describe fade fp_str getAllNamedColors hsl2rgb hue2rgb isStr linearlyInterpolatedColor +- literal_eval obj_R_G_B opaqueColor rgb2cmyk setColors toColor toColorOrNone'''.split()} +- G.update(self._G) ++ ++ ++ # allow expressions like 'Blacker(red, 0.5)' ++ # >>> re.compile(r"(Blacker|Whiter)\((\w+)\,\s?([0-9.]+)\)").match(msg).groups() ++ # ('Blacker', 'red', '0.5') ++ # >>> ++ pat = re.compile(r"(Blacker|Whiter)\((\w+)\,\s?([0-9.]+)\)") ++ m = pat.match(arg) ++ if m: ++ funcname, rootcolor, num = m.groups() ++ if funcname == 'Blacker': ++ return Blacker(rootcolor, float(num)) ++ else: ++ return Whiter(rootcolor, float(num)) ++ + try: +- return toColor(rl_safe_eval(arg,g=G,l={})) +- except: ++ import ast ++ expr = ast.literal_eval(arg) #safe probably only a tuple or list of values ++ return toColor(expr) ++ except (SyntaxError, ValueError): + pass + ++ if rl_config.toColorCanUse=='rl_safe_eval': ++ #the most dangerous option ++ G = C.copy() ++ G.update(self.extraColorsNS) ++ if not self._G: ++ C = globals() ++ self._G = {s:C[s] for s in '''Blacker CMYKColor CMYKColorSep Color ColorType HexColor PCMYKColor PCMYKColorSep Whiter ++ _chooseEnforceColorSpace _enforceCMYK _enforceError _enforceRGB _enforceSEP _enforceSEP_BLACK ++ _enforceSEP_CMYK _namedColors _re_css asNative cmyk2rgb cmykDistance color2bw colorDistance ++ cssParse describe fade fp_str getAllNamedColors hsl2rgb hue2rgb isStr linearlyInterpolatedColor ++ literal_eval obj_R_G_B opaqueColor rgb2cmyk setColors toColor toColorOrNone'''.split()} ++ G.update(self._G) ++ try: ++ return toColor(rl_safe_eval(arg,g=G,l={})) ++ except: ++ pass ++ elif rl_config.toColorCanUse=='rl_extended_literal_eval': ++ C = globals() ++ S = getAllNamedColors().copy() ++ C = {k:C[k] for k in '''Blacker CMYKColor CMYKColorSep Color ColorType HexColor PCMYKColor PCMYKColorSep Whiter ++ _chooseEnforceColorSpace _enforceCMYK _enforceError _enforceRGB _enforceSEP _enforceSEP_BLACK ++ _enforceSEP_CMYK _namedColors _re_css asNative cmyk2rgb cmykDistance color2bw colorDistance ++ cssParse describe fade fp_str getAllNamedColors hsl2rgb hue2rgb linearlyInterpolatedColor ++ obj_R_G_B opaqueColor rgb2cmyk setColors toColor toColorOrNone'''.split() ++ if callable(C.get(k,None))} ++ try: ++ return rl_extended_literal_eval(arg,C,S) ++ except (ValueError, SyntaxError): ++ pass ++ + try: + return HexColor(arg) + except: +diff --git a/src/reportlab/lib/rl_safe_eval.py b/src/reportlab/lib/rl_safe_eval.py +index 49828c9..50834f6 100644 +--- a/src/reportlab/lib/rl_safe_eval.py ++++ b/src/reportlab/lib/rl_safe_eval.py +@@ -3,7 +3,7 @@ + #https://github.com/zopefoundation/RestrictedPython + #https://github.com/danthedeckie/simpleeval + #hopefully we are standing on giants' shoulders +-import sys, os, ast, re, weakref, time, copy, math ++import sys, os, ast, re, weakref, time, copy, math, types + eval_debug = int(os.environ.get('EVAL_DEBUG','0')) + strTypes = (bytes,str) + isPy39 = sys.version_info[:2]>=(3,9) +@@ -53,7 +53,9 @@ __rl_unsafe__ = frozenset('''builtins breakpoint __annotations__ co_argcount co_ + func_doc func_globals func_name gi_code gi_frame gi_running gi_yieldfrom + __globals__ im_class im_func im_self __iter__ __kwdefaults__ __module__ + __name__ next __qualname__ __self__ tb_frame tb_lasti tb_lineno tb_next +- globals vars locals'''.split() ++ globals vars locals ++ type eval exec aiter anext compile open ++ dir print classmethod staticmethod __import__ super property'''.split() + ) + __rl_unsafe_re__ = re.compile(r'\b(?:%s)' % '|'.join(__rl_unsafe__),re.M) + +@@ -1204,5 +1206,70 @@ class __rl_safe_eval__: + class __rl_safe_exec__(__rl_safe_eval__): + mode = 'exec' + ++def rl_extended_literal_eval(expr, safe_callables=None, safe_names=None): ++ if safe_callables is None: ++ safe_callables = {} ++ if safe_names is None: ++ safe_names = {} ++ safe_names = safe_names.copy() ++ safe_names.update({'None': None, 'True': True, 'False': False}) ++ #make these readonly with MappingProxyType ++ safe_names = types.MappingProxyType(safe_names) ++ safe_callables = types.MappingProxyType(safe_callables) ++ if isinstance(expr, str): ++ expr = ast.parse(expr, mode='eval') ++ if isinstance(expr, ast.Expression): ++ expr = expr.body ++ try: ++ # Python 3.4 and up ++ ast.NameConstant ++ safe_test = lambda n: isinstance(n, ast.NameConstant) or isinstance(n,ast.Name) and n.id in safe_names ++ safe_extract = lambda n: n.value if isinstance(n,ast.NameConstant) else safe_names[n.id] ++ except AttributeError: ++ # Everything before ++ safe_test = lambda n: isinstance(n, ast.Name) and n.id in safe_names ++ safe_extract = lambda n: safe_names[n.id] ++ def _convert(node): ++ if isinstance(node, (ast.Str, ast.Bytes)): ++ return node.s ++ elif isinstance(node, ast.Num): ++ return node.n ++ elif isinstance(node, ast.Tuple): ++ return tuple(map(_convert, node.elts)) ++ elif isinstance(node, ast.List): ++ return list(map(_convert, node.elts)) ++ elif isinstance(node, ast.Dict): ++ return dict((_convert(k), _convert(v)) for k, v ++ in zip(node.keys, node.values)) ++ elif safe_test(node): ++ return safe_extract(node) ++ elif isinstance(node, ast.UnaryOp) and \ ++ isinstance(node.op, (ast.UAdd, ast.USub)) and \ ++ isinstance(node.operand, (ast.Num, ast.UnaryOp, ast.BinOp)): ++ operand = _convert(node.operand) ++ if isinstance(node.op, ast.UAdd): ++ return + operand ++ else: ++ return - operand ++ elif isinstance(node, ast.BinOp) and \ ++ isinstance(node.op, (ast.Add, ast.Sub)) and \ ++ isinstance(node.right, (ast.Num, ast.UnaryOp, ast.BinOp)) and \ ++ isinstance(node.right.n, complex) and \ ++ isinstance(node.left, (ast.Num, ast.UnaryOp, astBinOp)): ++ left = _convert(node.left) ++ right = _convert(node.right) ++ if isinstance(node.op, ast.Add): ++ return left + right ++ else: ++ return left - right ++ elif isinstance(node, ast.Call) and \ ++ isinstance(node.func, ast.Name) and \ ++ node.func.id in safe_callables: ++ return safe_callables[node.func.id]( ++ *[_convert(n) for n in node.args], ++ **{kw.arg: _convert(kw.value) for kw in node.keywords}) ++ raise ValueError('Bad expression') ++ return _convert(expr) ++ + rl_safe_exec = __rl_safe_exec__() + rl_safe_eval = __rl_safe_eval__() +diff --git a/src/reportlab/lib/utils.py b/src/reportlab/lib/utils.py +index 5a6b5d7..a53a05c 100644 +--- a/src/reportlab/lib/utils.py ++++ b/src/reportlab/lib/utils.py +@@ -11,7 +11,7 @@ from io import BytesIO + from hashlib import md5 + + from reportlab.lib.rltempfile import get_rl_tempfile, get_rl_tempdir +-from . rl_safe_eval import rl_safe_exec, rl_safe_eval, safer_globals ++from . rl_safe_eval import rl_safe_exec, rl_safe_eval, safer_globals, rl_extended_literal_eval + from PIL import Image + + class __UNSET__: +diff --git a/src/reportlab/rl_settings.py b/src/reportlab/rl_settings.py +index 30e7547..1a9e520 100644 +--- a/src/reportlab/rl_settings.py ++++ b/src/reportlab/rl_settings.py +@@ -67,7 +67,8 @@ documentLang + encryptionStrength + trustedHosts + trustedSchemes +-renderPMBackend'''.split()) ++renderPMBackend ++toColorCanUse'''.split()) + + allowTableBoundsErrors = 1 # set to 0 to die on too large elements in tables in debug (recommend 1 for production use) + shapeChecking = 1 +@@ -158,6 +159,8 @@ trustedSchemes=['file', 'rml', 'data', 'https', #these url schemes are trust + 'http', 'ftp'] + renderPMBackend='_renderPM' #or 'rlPyCairo' if available + ++toColorCanUse='rl_extended_literal_eval' #change to None or 'rl_safe_eval' depending on trust ++ + # places to look for T1Font information + T1SearchPath = ( + 'c:/Program Files/Adobe/Acrobat 9.0/Resource/Font', +diff --git a/tests/test_lib_rl_safe_eval.py b/tests/test_lib_rl_safe_eval.py +index 84bd86f..fd556eb 100644 +--- a/tests/test_lib_rl_safe_eval.py ++++ b/tests/test_lib_rl_safe_eval.py +@@ -1,6 +1,6 @@ + #Copyright ReportLab Europe Ltd. 2000-2017 + #see license.txt for license details +-"""Tests for reportlab.lib.rl_eval ++"""Tests for reportlab.lib.rl_safe_eval + """ + __version__='3.5.33' + from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, printLocation +@@ -10,7 +10,7 @@ import reportlab + from reportlab import rl_config + import unittest + from reportlab.lib import colors +-from reportlab.lib.utils import rl_safe_eval, rl_safe_exec, annotateException ++from reportlab.lib.utils import rl_safe_eval, rl_safe_exec, annotateException, rl_extended_literal_eval + from reportlab.lib.rl_safe_eval import BadCode + + testObj = [1,('a','b',2),{'A':1,'B':2.0},"32"] +@@ -52,7 +52,6 @@ class SafeEvalTestSequenceMeta(type): + 'dict(a=1).get("a",2)', + 'dict(a=1).pop("a",2)', + '{"_":1+_ for _ in (1,2)}.pop(1,None)', +- '(type(1),type(str),type(testObj),type(TestClass))', + '1 if True else "a"', + '1 if False else "a"', + 'testFunc(bad=False)', +@@ -74,6 +73,8 @@ class SafeEvalTestSequenceMeta(type): + ( + 'fail', + ( ++ 'vars()', ++ '(type(1),type(str),type(testObj),type(TestClass))', + 'open("/tmp/myfile")', + 'SafeEvalTestCase.__module__', + ("testInst.__class__.__bases__[0].__subclasses__()",dict(g=dict(testInst=testInst))), +@@ -97,6 +98,8 @@ class SafeEvalTestSequenceMeta(type): + 'testFunc(bad=True)', + 'getattr(testInst,"__class__",14)', + '"{1}{2}".format(1,2)', ++ 'builtins', ++ '[ [ [ [ ftype(ctype(0, 0, 0, 0, 3, 67, b"t\\x00d\\x01\\x83\\x01\\xa0\\x01d\\x02\\xa1\\x01\\x01\\x00d\\x00S\\x00", (None, "os", "touch /tmp/exploited"), ("__import__", "system"), (), "<stdin>", "", 1, b"\\x12\\x01"), {})() for ftype in [type(lambda: None)] ] for ctype in [type(getattr(lambda: {None}, Word("__code__")))] ] for Word in [orgTypeFun("Word", (str,), { "mutated": 1, "startswith": lambda self, x: False, "__eq__": lambda self,x: self.mutate() and self.mutated < 0 and str(self) == x, "mutate": lambda self: {setattr(self, "mutated", self.mutated - 1)}, "__hash__": lambda self: hash(str(self)) })] ] for orgTypeFun in [type(type(1))]] and "red"', + ) + ), + ): +@@ -155,8 +158,46 @@ class SafeEvalTestBasics(unittest.TestCase): + def test_002(self): + self.assertTrue(rl_safe_eval("GA=='ga'")) + ++class ExtendedLiteralEval(unittest.TestCase): ++ def test_001(self): ++ S = colors.getAllNamedColors().copy() ++ C = {s:getattr(colors,s) for s in '''Blacker CMYKColor CMYKColorSep Color ColorType HexColor PCMYKColor PCMYKColorSep Whiter ++ _chooseEnforceColorSpace _enforceCMYK _enforceError _enforceRGB _enforceSEP _enforceSEP_BLACK ++ _enforceSEP_CMYK _namedColors _re_css asNative cmyk2rgb cmykDistance color2bw colorDistance ++ cssParse describe fade fp_str getAllNamedColors hsl2rgb hue2rgb linearlyInterpolatedColor ++ obj_R_G_B opaqueColor rgb2cmyk setColors toColor toColorOrNone'''.split() ++ if callable(getattr(colors,s,None))} ++ def showVal(s): ++ try: ++ r = rl_extended_literal_eval(s,C,S) ++ except: ++ r = str(sys.exc_info()[1]) ++ return r ++ ++ for expr, expected in ( ++ ('1.0', 1.0), ++ ('1', 1), ++ ('red', colors.red), ++ ('True', True), ++ ('False', False), ++ ('None', None), ++ ('Blacker(red,0.5)', colors.Color(.5,0,0,1)), ++ ('PCMYKColor(21,10,30,5,spotName="ABCD")', colors.PCMYKColor(21,10,30,5,spotName='ABCD',alpha=100)), ++ ('HexColor("#ffffff")', colors.Color(1,1,1,1)), ++ ('linearlyInterpolatedColor(red, blue, 0, 1, 0.5)', colors.Color(.5,0,.5,1)), ++ ('red.rgb()', 'Bad expression'), ++ ('__import__("sys")', 'Bad expression'), ++ ('globals()', 'Bad expression'), ++ ('locals()', 'Bad expression'), ++ ('vars()', 'Bad expression'), ++ ('builtins', 'Bad expression'), ++ ('__file__', 'Bad expression'), ++ ('__name__', 'Bad expression'), ++ ): ++ self.assertEqual(showVal(expr),expected,f"rl_extended_literal_eval({expr!r}) is not equal to expected {expected}") ++ + def makeSuite(): +- return makeSuiteForClasses(SafeEvalTestCase,SafeEvalTestBasics) ++ return makeSuiteForClasses(SafeEvalTestCase,SafeEvalTestBasics,ExtendedLiteralEval) + + if __name__ == "__main__": #noruntests + unittest.TextTestRunner().run(makeSuite()) +-- +2.30.0.windows.2 + diff --git a/python-reportlab.spec b/python-reportlab.spec new file mode 100644 index 0000000..a2ac321 --- /dev/null +++ b/python-reportlab.spec @@ -0,0 +1,96 @@ +%global cmapdir %(echo `rpm -qls ghostscript | grep CMap | awk '{print $2}'`) + +%bcond_without tests + +Name: python-reportlab +Version: 3.6.10 +Release: 2 +Summary: ReportLab library to create PDF documents and graphic +License: BSD +URL: https://www.reportlab.com/ +Source0: https://pypi.python.org/packages/source/r/reportlab/reportlab-%{version}.tar.gz +BuildRequires: libart_lgpl-devel freetype-devel + +Patch0: backport-CVE-2023-33733-fix-RCE-attack-via-method-eval.patch + +%description +The ReportLab Toolkit. An Open Source Python library for generating PDFs and graphics. + +%package -n python3-reportlab +Summary: ReportLab library to create PDF documents and graphic +BuildRequires: python3-devel python3-pillow gcc +Requires: dejavu-sans-fonts python3-pillow +%{?python_provide:%python_provide python3-reportlab} + +%description -n python3-reportlab +The ReportLab Toolkit. An Open Source Python library for generating PDFs and graphics. + +%package help +Summary: Documentation for python-reportlab +BuildArch: noarch +Requires: %{name} = %{version}-%{release} +Provides: %{name}-doc = %{version}-%{release} +Obsoletes: %{name}-doc < %{version}-%{release} %{name}-docs < %{version}-%{release} + +%description help +Help documents for ReportLab. + +%prep +%autosetup -n reportlab-%{version} -p1 + +find src -name '*.py' | xargs sed -i -e '/^#!\//d' + +sed -i '/\~\/\.local\/share\/fonts\/CMap/i''\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ '\'"%{cmapdir}"\''\,' \ +src/reportlab/rl_settings.py + +rm -rf src/reportlab.egg-info + +rm -rf src/rl_addons/renderPM/libart_lgpl + +%build +CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS} -Isrc/rl_addons/renderPM -I%{_includedir}/libart-2.0}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\ + %{__python3} setup.py --use-system-libart --no-download-t1-files build --executable="%{__python3} -s" + +%install +CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS} -Isrc/rl_addons/renderPM -I%{_includedir}/libart-2.0}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\ + %{__python3} setup.py --use-system-libart --no-download-t1-files install -O1 --skip-build --root ${RPM_BUILD_ROOT} + +%if %{with tests} +%check +# Tests need in-build compiled Python modules to be executed +# Tests pre-generate userguide PDF +cp -a build/lib.%{python3_platform}-%{python3_version}/reportlab tests/ +cp -a build/lib.%{python3_platform}-%{python3_version}/reportlab docs/ +cp -a build/lib.%{python3_platform}-%{python3_version}/reportlab docs/userguide/ +%{__python3} setup.py tests +%endif + +%files -n python3-reportlab +%doc README.txt CHANGES.md +%license LICENSE.txt +%{python3_sitearch}/{reportlab/,reportlab-%{version}-py%{python3_version}.egg-info} + +%files help +%doc demos/ tools/ + +%changelog +* Wed Jun 28 2023 liningjie <liningjie@xfusion.com> - 3.6.10-2 +- Fix CVE-2023-33733 + +* Thu Jun 23 2022 SimpleUpdate Robot <tc@openeuler.org> - 3.6.10-1 +- Upgrade to version 3.6.10 + +* Wed Jan 12 2022 Chengshaowei <chenshaowei3@huawei.com> - 3.4.0-14 +- Fix can not import error + +* Wed Jul 21 2021 yaoxin <yaoxin30@huawei.com> - 3.4.0-13 +- Fix CVE-2019-17626 + +* Mon May 31 2021 huanghaitao <huanghaitao8@huawei.com> - 3.4.0-12 +- Completing build dependencies + +* Fri Sep 11 2020 wangyue<wangyue92@huawei.com> - 3.4.0-11 +- Remove python2-reportlab + +* Mon Mar 02 2020 Jiangping Hu <hujp1985@foxmail.com> - 3.4.0-10 +- Package init @@ -0,0 +1 @@ +e1b29929ee0013d2e6f7caaf9df264e7 reportlab-3.6.10.tar.gz |