
漏洞详情:
受影响版本:多个Magick.NET NuGet包(包括x64和arm64架构,Q8、Q16、HDRI及OpenMP变体)的14.9.0及更早版本均受此漏洞影响。
描述:
摘要:CLAHE实现中存在一个根本原因——区块宽度/高度变为零——导致了两种不同但相关的不安全行为。漏洞存在于ImageMagick的MagickCore/enhance.c文件的CLAHEImage()函数中。
tile_info.height == 0时,表达式tile_info.height - 1(无符号)会回绕成一个非常大的值;在指针运算中使用该值会产生巨大的偏移量并导致越界内存访问(引发内存损坏、SIGSEGV或资源耗尽)。这两种行为均由相同的无效区块条件触发(例如,通过CLI命令-clahe 0x0!,或者对于非常小的图像,自动推导出的区块尺寸dim >> 3 == 0)。
详情:
无符号整数下溢(可导致越界)
MagickCore/enhance.c,第609行附近。enhance.c: 609
p += (ptrdiff_t) clahe_info->width * (tile.height - 1);tile.height == 0,那么(tile.height - 1)会下溢至UINT_MAX。将其与clahe_info->width相乘会产生一个接近SIZE_MAX的巨大值。将此值加到p上会导致指针算术下溢。
除零操作
MagickCore/enhance.c,第669行附近。enhance.c: 669-673
if ((image->columns % tile_info.width) != 0)
tile_info.x=(ssize_t) (tile_info.width-(image->columns % tile_info.width));
tile_info.y=0;
if ((image->rows % tile_info.height) != 0)
tile_info.y=(ssize_t) (tile_info.height-(image->rows % tile_info.height));tile_info.width或tile_info.height为0,则会触发除零操作。零值可以通过以下方式到达此处:clahe 0x0!(!强制直接使用零值)。!)时,代码会从图像尺寸(例如,dim >> 3)推导出默认值。对于尺寸小于8的图像,除非进行限制,否则结果为0。
重现步骤:
无符号整数下溢
环境:启用AddressSanitizer和UndefinedBehaviorSanitizer的构建。
export UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1
export ASAN_OPTIONS=abort_on_error=1:allocator_may_return_null=1:detect_leaks=0命令:
./magick xc:black -clahe 0x0 null: - 输出显示未定义行为错误。./magick -size 10x10 xc:black -clahe 0x0 null: - 导致内存区域损坏。除零操作
环境:启用了ASan/UBSan的构建。
export UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1
export ASAN_OPTIONS=abort_on_error=1:allocator_may_return_null=1:detect_leaks=0命令:
./magick -size 16x2 gradient: -type TrueColor -depth 8 -clahe 0x0! null:
输出:触发除零错误,进程中止。在没有检测器的情况下,进程可能仅以“已中止”状态终止(仍构成DoS)。
影响:
clahe 0x0!或向使用ImageMagick的服务上传极小的图像来触发。建议的修复代码片段:
在CLAHEImage()函数中,计算完tile_info之后,但在任何除法、模运算或指针算术之前应用以下检查:
if (exact_tiles_requested && (tile_info.width == 0 || tile_info.height == 0)) {
ThrowMagickException(exception, GetMagickModule(), OptionError,
"CLAHEInvalidTile", "%lux%lu",
(unsigned long) tile_info.width,
(unsigned long) tile_info.height);
return (Image *) NULL;
}
if (!exact_tiles_requested) {
tile_info.width = (tile_info.width == 0) ? MagickMax((size_t)1, image->columns >> 3) : tile_info.width;
tile_info.height = (tile_info.height == 0) ? MagickMax((size_t)1, image->rows >> 3) : tile_info.height;
}
if (tile_info.width == 0 || tile_info.height == 0) {
ThrowMagickException(exception, GetMagickModule(), OptionError,
"CLAHEInvalidTile", "%lux%lu",
(unsigned long) tile_info.width,
(unsigned long) tile_info.height);
return (Image *) NULL;
}
ssize_t tile_h_minus1 = (ssize_t)tile_info.height - 1;
if (tile_h_minus1 < 0) {
ThrowMagickException(exception, GetMagickModule(), OptionError,
"CLAHEInvalidTile", "%lux%lu",
(unsigned long) tile_info.width,
(unsigned long) tile_info.height);
return (Image *) NULL;
}
p += (ptrdiff_t) clahe_info->width * tile_h_minus1;关于 exact_tiles_requested 的说明:
如果CLI/Wand解析器已经暴露了是否存在!标志,则使用它。如果没有,在解析时添加一个标志,以便CLAHEImage能够知道零值是字面量还是自动计算值。
参考链接:
源项目地址:https://github.com/ImageMagick/ImageMagick.git