Skip to content

Commit

Permalink
Buffer overflow in Image.connected_components with ImageMagick 7.0.10
Browse files Browse the repository at this point in the history
Fixes #496
  • Loading branch information
emcconville committed Sep 14, 2020
1 parent 67da354 commit 314cb9e
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 7 deletions.
22 changes: 19 additions & 3 deletions wand/cdefs/structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
.. versionadded:: 0.5.0
"""
from ctypes import POINTER, Structure, c_double, c_int, c_size_t
from ctypes import POINTER, Structure, c_bool, c_double, c_int, c_size_t
from wand.cdefs.wandtypes import c_ssize_t, c_magick_real_t, c_magick_size_t

__all__ = ('AffineMatrix', 'ChannelFeature', 'GeometryInfo', 'KernelInfo',
'MagickPixelPacket', 'PixelInfo', 'PointInfo', 'RectangleInfo')
__all__ = ('AffineMatrix', 'CCMaxMetrics', 'CCObjectInfo', 'CCObjectInfo70A',
'ChannelFeature', 'GeometryInfo', 'KernelInfo', 'MagickPixelPacket',
'PixelInfo', 'PointInfo', 'RectangleInfo')


class AffineMatrix(Structure):
Expand Down Expand Up @@ -173,6 +174,21 @@ class CCObjectInfo(Structure):
('census', c_double)]


CCMaxMetrics = 16


class CCObjectInfo70A(Structure):
CCMaxMetrics = CCMaxMetrics
_fields_ = [('_id', c_ssize_t),
('bounding_box', RectangleInfo),
('color', PixelInfo),
('centroid', PointInfo),
('area', c_double),
('census', c_double),
('merge', c_bool),
('metric', c_double * CCMaxMetrics)]


# All this will change with IM7, so let's not implement this just yet.
#
# class ImageChannelStatistics(Structure):
Expand Down
37 changes: 33 additions & 4 deletions wand/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
WandRuntimeError, WandLibraryVersionError)
from .font import Font
from .resource import DestroyedResourceError, Resource
from .cdefs.structures import (CCObjectInfo, ChannelFeature, GeometryInfo,
PixelInfo, RectangleInfo)
from .cdefs.structures import (CCObjectInfo, CCObjectInfo70A, ChannelFeature,
GeometryInfo, PixelInfo, RectangleInfo)
from .version import MAGICK_VERSION_NUMBER, MAGICK_HDRI


Expand Down Expand Up @@ -3965,13 +3965,16 @@ def connected_components(self, connectivity=4, area_threshold=None,
key,
b'{0}'.format(remove))
objects_ptr = ctypes.c_void_p(0)
ccoi_mem_size = ctypes.sizeof(CCObjectInfo)
CCObjectInfoStructure = CCObjectInfo
if MAGICK_VERSION_NUMBER > 0x709:
CCObjectInfoStructure = CCObjectInfo70A
ccoi_mem_size = ctypes.sizeof(CCObjectInfoStructure)
r = library.MagickConnectedComponentsImage(self.wand, connectivity,
ctypes.byref(objects_ptr))
objects = []
if r and objects_ptr.value:
for i in xrange(self.colors):
temp = CCObjectInfo()
temp = CCObjectInfoStructure()
src_addr = objects_ptr.value + (i * ccoi_mem_size)
ctypes.memmove(ctypes.addressof(temp), src_addr, ccoi_mem_size)
objects.append(ConnectedComponentObject(temp))
Expand Down Expand Up @@ -9841,6 +9844,8 @@ class ConnectedComponentObject(object):
<wand.image.BaseImage.connected_components>` method.
.. versionadded:: 0.5.5
.. versionchanged:: 0.6.3
Added :attr:`merge` & :attr:`metric` for ImageMagick 7.0.10
"""
#: (:class:`numbers.Integral`) Serialized object identifier
#: starting at `0`.
Expand Down Expand Up @@ -9876,9 +9881,22 @@ class ConnectedComponentObject(object):
#: shape.
mean_color = None

#: (:class:`bool`) Object merge flag. Only avaliable after
#: ImageMagick-7.0.10.
#: ..versionadded:: 0.6.3
merge = None

#: (:class:`list`) List of doubles used by metric. Only avaliable after
#: ImageMagick-7.0.10.
#: ..versionadded:: 0.6.3
metric = None

def __init__(self, cc_object=None):
if isinstance(cc_object, CCObjectInfo):
self.clone_from_cc_object_info(cc_object)
if isinstance(cc_object, CCObjectInfo70A):
self.clone_from_cc_object_info(cc_object)
self.clone_from_extra_70A_info(cc_object)

@property
def size(self):
Expand Down Expand Up @@ -9915,6 +9933,17 @@ def clone_from_cc_object_info(self, cc_object):
pinfo_size)
self.mean_color = Color(raw=raw_buffer)

def clone_from_extra_70A_info(self, cc_object):
"""Copy the additional values from CCObjectInfo structure. This is the
:attr:`merge` & :attr:`metric` properties added in ImageMagick 7.0.10.
.. versionadded:: 0.6.3
"""
self.merge = cc_object.merge
self.metric = []
for i in range(cc_object.CCMaxMetrics):
self.metric.append(cc_object.metric[i])

def __repr__(self):
fmt = ("{name}({_id}: {width}x{height}+{left}+{top} {center_x:.2f},"
"{center_y:.2f} {area:.0f} {mean_color})")
Expand Down

0 comments on commit 314cb9e

Please sign in to comment.