Compare commits

...

10 Commits
main ... 9.0.x

Author SHA1 Message Date
Andrew Murray
6deac9e3a2 9.0.1 version bump 2022-02-03 10:45:27 +11:00
Andrew Murray
c04d812b90 Update CHANGES.rst [ci skip] 2022-02-03 10:44:21 +11:00
Andrew Murray
4fabec3619 Added release notes for 9.0.1 2022-02-03 10:15:42 +11:00
Andrew Murray
02affaa491 Added delay after opening image with xdg-open 2022-02-03 10:10:40 +11:00
Andrew Murray
ca0b585218 Updated formatting
Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com>
2022-02-03 10:09:45 +11:00
Andrew Murray
427221ef5f In show_file, use os.remove to remove temporary images 2022-02-03 10:08:38 +11:00
Andrew Murray
c930be0758 Restrict builtins within lambdas for ImageMath.eval 2022-02-03 10:03:54 +11:00
Hugo van Kemenade
75b69dd239 Dont need to pin for GHA
Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com>
2022-02-03 08:41:43 +11:00
Hugo van Kemenade
cd938a7744 Autolink CWE numbers with sphinx-issues 2022-02-03 08:41:34 +11:00
Hugo van Kemenade
2e9c461ca4 Add CVE IDs 2022-02-03 08:41:18 +11:00
9 changed files with 117 additions and 40 deletions

View File

@ -2,16 +2,25 @@
Changelog (Pillow)
==================
9.0.1 (2022-02-03)
------------------
- In show_file, use os.remove to remove temporary images. CVE-2022-24303 #6010
[radarhere, hugovk]
- Restrict builtins within lambdas for ImageMath.eval. CVE-2022-22817 #6009
[radarhere]
9.0.0 (2022-01-02)
------------------
- Restrict builtins for ImageMath.eval(). CVE TBD #5923
- Restrict builtins for ImageMath.eval(). CVE-2022-22817 #5923
[radarhere]
- Ensure JpegImagePlugin stops at the end of a truncated file #5921
[radarhere]
- Fixed ImagePath.Path array handling. CVEs TBD #5920
- Fixed ImagePath.Path array handling. CVE-2022-22815, CVE-2022-22816 #5920
[radarhere]
- Remove consecutive duplicate tiles that only differ by their offset #5919

View File

@ -52,9 +52,17 @@ def test_ops():
assert pixel(ImageMath.eval("float(B)**33", images)) == "F 8589934592.0"
def test_prevent_exec():
@pytest.mark.parametrize(
"expression",
(
"exec('pass')",
"(lambda: exec('pass'))()",
"(lambda: (lambda: exec('pass'))())()",
),
)
def test_prevent_exec(expression):
with pytest.raises(ValueError):
ImageMath.eval("exec('pass')")
ImageMath.eval(expression)
def test_logical():

View File

@ -119,15 +119,16 @@ Google's `OSS-Fuzz`_ project for finding this issue.
Restrict builtins available to ImageMath.eval
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To limit :py:class:`PIL.ImageMath` to working with images, Pillow will now restrict the
builtins available to :py:meth:`PIL.ImageMath.eval`. This will help prevent problems
arising if users evaluate arbitrary expressions, such as
``ImageMath.eval("exec(exit())")``. CVE TBD
:cve:`CVE-2022-22817`: To limit :py:class:`PIL.ImageMath` to working with images, Pillow
will now restrict the builtins available to :py:meth:`PIL.ImageMath.eval`. This will
help prevent problems arising if users evaluate arbitrary expressions, such as
``ImageMath.eval("exec(exit())")``.
Fixed ImagePath.Path array handling
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
CWE-126 and CWE-665 were found when initializing ``ImagePath.Path``. CVEs TBD
:cve:`CVE-2022-22815` (:cwe:`CWE-126`) and :cve:`CVE-2022-22816` (:cwe:`CWE-665`) were
found when initializing ``ImagePath.Path``.
.. _OSS-Fuzz: https://github.com/google/oss-fuzz

View File

@ -0,0 +1,23 @@
9.0.1
-----
Security
========
This release addresses several security problems.
:cve:`CVE-2022-24303`: If the path to the temporary directory on Linux or macOS
contained a space, this would break removal of the temporary image file after
``im.show()`` (and related actions), and potentially remove an unrelated file. This
been present since PIL.
:cve:`CVE-2022-22817`: While Pillow 9.0 restricted top-level builtins available to
:py:meth:`PIL.ImageMath.eval`, it did not prevent builtins available to lambda
expressions. These are now also restricted.
Other Changes
=============
Pillow 9.0 added support for ``xdg-open`` as an image viewer, but there have been
reports that the temporary image file was removed too quickly to be loaded into the
final application. A delay has been added.

View File

@ -14,6 +14,7 @@ expected to be backported to earlier versions.
.. toctree::
:maxdepth: 2
9.0.1
9.0.0
8.4.0
8.3.2

View File

@ -12,7 +12,7 @@ pytest-cov
pytest-timeout
sphinx>=2.4
sphinx-copybutton
sphinx-issues
sphinx-issues>=3.0.1
sphinx-removed-in
sphinx-rtd-theme>=1.0
sphinxext-opengraph

View File

@ -246,11 +246,18 @@ def eval(expression, _dict={}, **kw):
if hasattr(v, "im"):
args[k] = _Operand(v)
code = compile(expression, "<string>", "eval")
for name in code.co_names:
if name not in args and name != "abs":
raise ValueError(f"'{name}' not allowed")
compiled_code = compile(expression, "<string>", "eval")
def scan(code):
for const in code.co_consts:
if type(const) == type(compiled_code):
scan(const)
for name in code.co_names:
if name not in args and name != "abs":
raise ValueError(f"'{name}' not allowed")
scan(compiled_code)
out = builtins.eval(expression, {"__builtins": {"abs": abs}}, args)
try:
return out.im

View File

@ -15,7 +15,6 @@ import os
import shutil
import subprocess
import sys
import tempfile
from shlex import quote
from PIL import Image
@ -106,10 +105,20 @@ class Viewer:
return self.show_file(self.save_image(image), **options)
def show_file(self, file, **options):
"""Display the given file."""
"""Display given file"""
os.system(self.get_command(file, **options))
return 1
def _remove_file_after_delay(self, file):
subprocess.Popen(
[
sys.executable,
"-c",
"import os, sys, time; time.sleep(20); os.remove(sys.argv[1])",
file,
]
)
# --------------------------------------------------------------------
@ -147,16 +156,8 @@ class MacViewer(Viewer):
def show_file(self, file, **options):
"""Display given file"""
fd, path = tempfile.mkstemp()
with os.fdopen(fd, "w") as f:
f.write(file)
with open(path) as f:
subprocess.Popen(
["im=$(cat); open -a Preview.app $im; sleep 20; rm -f $im"],
shell=True,
stdin=f,
)
os.remove(path)
subprocess.call(["open", "-a", "Preview.app", file])
self._remove_file_after_delay(file)
return 1
@ -172,19 +173,6 @@ class UnixViewer(Viewer):
command = self.get_command_ex(file, **options)[0]
return f"({command} {quote(file)}; rm -f {quote(file)})&"
def show_file(self, file, **options):
"""Display given file"""
fd, path = tempfile.mkstemp()
with os.fdopen(fd, "w") as f:
f.write(file)
with open(path) as f:
command = self.get_command_ex(file, **options)[0]
subprocess.Popen(
["im=$(cat);" + command + " $im; rm -f $im"], shell=True, stdin=f
)
os.remove(path)
return 1
class XDGViewer(UnixViewer):
"""
@ -195,6 +183,12 @@ class XDGViewer(UnixViewer):
command = executable = "xdg-open"
return command, executable
def show_file(self, file, **options):
"""Display given file"""
subprocess.Popen(["xdg-open", file])
self._remove_file_after_delay(file)
return 1
class DisplayViewer(UnixViewer):
"""
@ -208,6 +202,17 @@ class DisplayViewer(UnixViewer):
command += f" -name {quote(title)}"
return command, executable
def show_file(self, file, **options):
"""Display given file"""
args = ["display"]
if "title" in options:
args += ["-name", options["title"]]
args.append(file)
subprocess.Popen(args)
os.remove(file)
return 1
class GmDisplayViewer(UnixViewer):
"""The GraphicsMagick ``gm display`` command."""
@ -217,6 +222,12 @@ class GmDisplayViewer(UnixViewer):
command = "gm display"
return command, executable
def show_file(self, file, **options):
"""Display given file"""
subprocess.Popen(["gm", "display", file])
os.remove(file)
return 1
class EogViewer(UnixViewer):
"""The GNOME Image Viewer ``eog`` command."""
@ -226,6 +237,12 @@ class EogViewer(UnixViewer):
command = "eog -n"
return command, executable
def show_file(self, file, **options):
"""Display given file"""
subprocess.Popen(["eog", "-n", file])
os.remove(file)
return 1
class XVViewer(UnixViewer):
"""
@ -241,6 +258,17 @@ class XVViewer(UnixViewer):
command += f" -name {quote(title)}"
return command, executable
def show_file(self, file, **options):
"""Display given file"""
args = ["xv"]
if "title" in options:
args += ["-name", options["title"]]
args.append(file)
subprocess.Popen(args)
os.remove(file)
return 1
if sys.platform not in ("win32", "darwin"): # unixoids
if shutil.which("xdg-open"):

View File

@ -1,2 +1,2 @@
# Master version for Pillow
__version__ = "9.0.0"
__version__ = "9.0.1"