summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2023-08-28 06:17:55 +0000
committerCoprDistGit <infra@openeuler.org>2023-08-28 06:17:55 +0000
commitc488fbc28dc66541bf179562113977911856fa86 (patch)
tree29dde03ec29d0f6f3ddda3233a2c891533b2f0cd
parent5f37caad6befbdd2c40cd0bbe2dfd1a2684337a4 (diff)
automatic import of python-reportlabopeneuler22.03_LTS_SP2
-rw-r--r--.gitignore1
-rw-r--r--backport-CVE-2023-33733-fix-RCE-attack-via-method-eval.patch346
-rw-r--r--python-reportlab.spec96
-rw-r--r--sources1
4 files changed, 444 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index e69de29..88b7948 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
diff --git a/sources b/sources
new file mode 100644
index 0000000..05dca57
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+e1b29929ee0013d2e6f7caaf9df264e7 reportlab-3.6.10.tar.gz