Commit 23848438 for libheif
commit 238484384bbb2fe156cf644c6433eb7570e61717
Author: Dirk Farin <dirk.farin@gmail.com>
Date: Sat May 16 01:36:36 2026 +0200
check for valid heif_image_crop() parameters (#1788)
diff --git a/libheif/api/libheif/heif_image.cc b/libheif/api/libheif/heif_image.cc
index f766969b..bc54219f 100644
--- a/libheif/api/libheif/heif_image.cc
+++ b/libheif/api/libheif/heif_image.cc
@@ -84,16 +84,20 @@ heif_error heif_image_crop(heif_image* img,
uint32_t w = img->image->get_width();
uint32_t h = img->image->get_height();
- if (w == 0 || w > 0x7FFFFFFF ||
- h == 0 || h > 0x7FFFFFFF) {
+ // Margins must be non-negative and must not consume the entire image.
+ // Without this check, `left + right >= w` would underflow the unsigned
+ // `w - 1 - right` computation below and cause an OOB read (issue #1746).
+ if (left < 0 || right < 0 || top < 0 || bottom < 0 ||
+ static_cast<int64_t>(left) + right >= w ||
+ static_cast<int64_t>(top) + bottom >= h) {
return heif_error{
heif_error_Usage_error,
- heif_suberror_Invalid_image_size,
- "Image size exceeds maximum supported size"
+ heif_suberror_Invalid_parameter_value,
+ "Invalid crop margins"
};
}
- auto cropResult = img->image->crop(left, static_cast<int>(w) - 1 - right, top, static_cast<int>(h) - 1 - bottom, nullptr);
+ auto cropResult = img->image->crop(left, w - 1 - right, top, h - 1 - bottom, nullptr);
if (!cropResult) {
return cropResult.error_struct(img->image.get());
}
diff --git a/libheif/api/libheif/heif_image.h b/libheif/api/libheif/heif_image.h
index a4b13215..b5bcdf6e 100644
--- a/libheif/api/libheif/heif_image.h
+++ b/libheif/api/libheif/heif_image.h
@@ -232,6 +232,27 @@ int heif_image_get_primary_width(const heif_image* img);
LIBHEIF_API
int heif_image_get_primary_height(const heif_image* img);
+/**
+ * Crop the image in place by removing margins from each edge.
+ *
+ * The four parameters specify the number of pixels to remove from each side,
+ * not absolute pixel coordinates. For example, to crop a 100x100 image down
+ * to its central 80x80 region, pass `left=10, right=10, top=10, bottom=10`.
+ * Passing all zeros leaves the image unchanged.
+ *
+ * The resulting image has dimensions `(w - left - right) x (h - top - bottom)`,
+ * which must be at least 1x1. All four values must be non-negative and the
+ * sums `left + right` and `top + bottom` must each be strictly less than the
+ * corresponding image dimension; otherwise `heif_error_Usage_error` /
+ * `heif_suberror_Invalid_parameter_value` is returned and the image is left
+ * unchanged.
+ *
+ * @param img the image to crop (modified in place on success)
+ * @param left number of pixels to remove from the left edge
+ * @param right number of pixels to remove from the right edge
+ * @param top number of pixels to remove from the top edge
+ * @param bottom number of pixels to remove from the bottom edge
+ */
LIBHEIF_API
heif_error heif_image_crop(heif_image* img,
int left, int right, int top, int bottom);
diff --git a/libheif/image/pixelimage.cc b/libheif/image/pixelimage.cc
index 43eaddcf..6d220f8b 100644
--- a/libheif/image/pixelimage.cc
+++ b/libheif/image/pixelimage.cc
@@ -1452,6 +1452,15 @@ Result<std::shared_ptr<HeifPixelImage>> HeifPixelImage::crop(uint32_t left, uint
// Either translate / resample these structures to the crop region, or
// return an error when the crop would invalidate them.
+ // (left, right, top, bottom) are coordinate endpoints of the kept region.
+ // Reject inverted or out-of-bounds rectangles so the unsigned arithmetic
+ // below cannot underflow into a multi-GB memcpy (issue #1746).
+ if (right < left || bottom < top || right >= m_width || bottom >= m_height) {
+ return Error{heif_error_Usage_error,
+ heif_suberror_Invalid_parameter_value,
+ "Invalid crop region"};
+ }
+
// --- for some subsampled chroma colorspaces, we have to transform to 4:4:4 before cropping
bool need_conversion = false;