|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2018-03-02 17:40 UTC] lee at lboynton dot com
Description:
------------
Large rotate values passed to Imagick's rotateImage() method cause the PHP process to run indefinitely (at least on CLI) and cause high CPU usage.
Flagged as potential security issue since it could be used for denial of service? The rotation degrees value could quite easily be user input. However PHP's maximum execution limit is hit when I try this via apache so perhaps not a DoS?
Imagick details:
imagick module version => 3.4.3
imagick classes => Imagick, ImagickDraw, ImagickPixel, ImagickPixelIterator, ImagickKernel
imagick.locale_fix => 0 => 0
imagick.progress_monitor => 0 => 0
imagick.skip_version_check => 0 => 0
Test script:
---------------
<?php
$base64 = "iVBORw0KGgoAAAANSUhEUgAAAM0AAAD
NCAMAAAAsYgRbAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5c
cllPAAAABJQTFRF3NSmzMewPxIG//ncJEJsldTou1jHgAAAARBJREFUeNrs2EEK
gCAQBVDLuv+V20dENbMY831wKz4Y/VHb/5RGQ0NDQ0NDQ0NDQ0NDQ0NDQ
0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0PzMWtyaGhoaGhoaGhoaGhoaGhoxtb0QGho
aGhoaGhoaGhoaGhoaMbRLEvv50VTQ9OTQ5OpyZ01GpM2g0bfmDQaL7S+ofFC6x
v3ZpxJiywakzbvd9r3RWPS9I2+MWk0+kbf0Hih9Y17U0nTHibrDDQ0NDQ0NDQ0
NDQ0NDQ0NTXbRSL/AK72o6GhoaGhoRlL8951vwsNDQ0NDQ1NDc0WyHtDTEhD
Q0NDQ0NTS5MdGhoaGhoaGhoaGhoaGhoaGhoaGhoaGposzSHAAErMwwQ2HwRQ
AAAAAElFTkSuQmCC";
$imageBlob = base64_decode($base64);
$imagick = new Imagick();
$imagick->readImageBlob($imageBlob);
$imagick->rotateImage('#000000', 9999999999);
Expected result:
----------------
I would either expect the rotation to happen after a certain amount of time, or for an error/warning to be thrown straight away if the rotation value is too high.
Actual result:
--------------
On the CLI, after calling rotateImage() the process continues indefinitely. When executed via Apache, the maximum execution time of 30 seconds is reached.
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Fri Nov 07 18:00:01 2025 UTC |
OK, fair enough. There is something odd though, the processing time doesn't seem to correlate to the rotation value you supply. This completes in about 100ms for me: $imagick->rotateImage('#000000', 2147483776); Increasing the rotation by 1 degree to: $imagick->rotateImage('#000000', 2147483777); Causes the PHP process to hang. I've tried on PHP 5.6 and 7.2 in a docker container and get the same result.Lee provided some feedback elsewhere: Dockerfile FROM php:7.2.12 RUN apt update && apt install -y libmagickwand-dev --no-install-recommends && rm -rf /var/lib/apt/lists/* RUN pecl install imagick && docker-php-ext-enable imagick Instructions: Create a directory Save Dockerfile Save test.php Build docker file docker build . -t php-imagick Run script: docker run -v $PWD/test.php:/test.php php-imagick php /test.php This will hang indefinitely and use a lot of CPU, at least for me Running docker run -v $PWD/test.php:/test.php php-imagick php /test.php 5 returns immediately. test.php <?php $rotate = (int) $argv[1] ?? 9999999999; echo sprintf('Rotating by %d%s', $rotate, PHP_EOL); $base64 = "iVBORw0KGgoAAAANSUhEUgAAAM0AAAD NCAMAAAAsYgRbAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5c cllPAAAABJQTFRF3NSmzMewPxIG//ncJEJsldTou1jHgAAAARBJREFUeNrs2EEK gCAQBVDLuv+V20dENbMY831wKz4Y/VHb/5RGQ0NDQ0NDQ0NDQ0NDQ0NDQ 0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0PzMWtyaGhoaGhoaGhoaGhoaGhoxtb0QGho aGhoaGhoaGhoaGhoaMbRLEvv50VTQ9OTQ5OpyZ01GpM2g0bfmDQaL7S+ofFC6x v3ZpxJiywakzbvd9r3RWPS9I2+MWk0+kbf0Hih9Y17U0nTHibrDDQ0NDQ0NDQ0 NDQ0NDQ0NTXbRSL/AK72o6GhoaGhoRlL8951vwsNDQ0NDQ1NDc0WyHtDTEhD Q0NDQ0NTS5MdGhoaGhoaGhoaGhoaGhoaGhoaGhoaGposzSHAAErMwwQ2HwRQ AAAAAElFTkSuQmCC"; $imageBlob = base64_decode($base64); $imagick = new Imagick(); $imagick->readImageBlob($imageBlob); $imagick->rotateImage('#000000', $rotate);I can reproduce what you are seeing on the docker image. I extracted all of the maths that appears relevant in the ImageMagick extension relating to rotation, but it doesn't show the same issue. It also doesn't look like the code should be possible to hang - which implies something weird is happening. I think the next step in debugging this would be one of two things: i) Install gdb or strace in the docker image, and run the php scrip through that, and see if it is hanging on a system call, or find where it is hanging. ii) Recompile ImageMagick with "printf debugging" (i.e. a whole load of printf("Got here: 1\n")); and find what step it is failing at. Run example below with: # gcc -lm math_test.c -o main # ./main math_test.c #include <stdio.h> #include <math.h> #define MagickPI 3.14159265358979323846264338327950288419716939937510 static inline double DegreesToRadians(const double degrees) { return((double) (MagickPI*degrees/180.0)); } void letsRotate(const double degrees) { double angle; size_t rotations; angle=fmod(degrees,360.0); while (angle < -45.0) { angle+=360.0; } for (rotations=0; angle > 45.0; rotations++) { angle-=90.0; } float shear_x = (-tan((double) DegreesToRadians(angle)/2.0)); float shear_y = sin((double) DegreesToRadians(angle)); printf("angle = %f, rotations = %d \n", angle, rotations); printf("shear_x = %f, shear_y = %f \n", shear_x, shear_y); double coeff[20]; double cosine, sine, x,y,sx,sy,a,nx,ny; a = DegreesToRadians(a); cosine=cos(a); sine=sin(a); nx = 20; ny = 20; sx = sy = 1.0; coeff[0]=cosine/sx; coeff[1]=sine/sx; coeff[2]=x-nx*coeff[0]-ny*coeff[1]; coeff[3]=(-sine)/sy; coeff[4]=cosine/sy; coeff[5]=y-nx*coeff[3]-ny*coeff[4]; for(int i=0; i<6; i++) { printf("Coeff %d = %f\n", i, coeff[i]); } } int main () { double large = 99999999999999999999.0; letsRotate(large); return(0); }gdb output: #0 0x00007fffeb7ec500 in RotateImage () from /usr/lib/x86_64-linux-gnu/libMagickCore-6.Q16.so.3 #1 0x00007fffebc8a0ac in MagickRotateImage () from /usr/lib/x86_64-linux-gnu/libMagickWand-6.Q16.so.3 #2 0x00007fffebf438cb in zim_imagick_rotateimage () from /usr/lib/php/20170718/imagick.so #3 0x00007ffff2a7bcf5 in xdebug_execute_internal (current_execute_data=0x7ffff321c160, return_value=0x7fffffffa4b0) at ./build-7.2/xdebug.c:2021 #4 0x000055555583a5b4 in ?? () #5 0x000055555589f11a in execute_ex () #6 0x00007ffff2a7aefe in xdebug_execute_ex (execute_data=0x7ffff321c030) at ./build-7.2/xdebug.c:1912 #7 0x00005555558a75a7 in zend_execute () #8 0x00005555557f6192 in zend_execute_scripts () #9 0x0000555555792080 in php_execute_script () #10 0x00005555558a99bc in ?? () #11 0x000055555564057b in ?? () #12 0x00007ffff5ebcb97 in __libc_start_main (main=0x555555640160, argc=2, argv=0x7fffffffdfc8, init=<optimised out>, fini=<optimised out>, rtld_fini=<optimised out>, stack_end=0x7fffffffdfb8) at ../csu/libc-start.c:310 #13 0x000055555564071a in _start ()