Skip to content

CPU exhaustion in SeekBlob #867

Closed
Closed
@henices

Description

@henices

Hello all.
We found a denial of service (DoS) issue in ImageMagick 7.0.7-12 Q16 x86_64 , which can cause huge CPU consumption. (cpu 100%)

The policy.xml is as following

<policymap>
  <policy domain="resource" name="temporary-path" value="/tmp"/>
  <policy domain="resource" name="memory" value="256MiB"/>
  <policy domain="resource" name="map" value="512MiB"/>
  <policy domain="resource" name="width" value="8KP"/>
  <policy domain="resource" name="height" value="8KP"/>
  <policy domain="resource" name="area" value="16KP"/>
  <policy domain="resource" name="disk" value="1GiB"/>
  <policy domain="resource" name="file" value="768"/>
  <policy domain="resource" name="thread" value="2"/>
  <policy domain="resource" name="throttle" value="0"/>
  <policy domain="resource" name="time" value="120"/>
  <policy domain="system" name="precision" value="6"/>
  <policy domain="coder" rights="none" pattern="MVG" />
  <policy domain="filter" rights="none" pattern="*" />
  <policy domain="delegate" rights="none" pattern="HTTPS" />  
  <policy domain="path" rights="none" pattern="@*"/>  
</policymap>

convert SeekBlob-cpu-exhaustion /dev/null

gdb backtrace

(gdb) bt                                       
#0  0x00007ffff6ef1330 in __read_nocancel () at ../sysdeps/unix/syscall-template.S:81          
#1  0x00007ffff6e7abe9 in _IO_new_file_seekoff (fp=0x63ff40, offset=238935896, dir=<optimized out>, mode=3) at fileops.c:1079                                                                  
#2  0x00007ffff6e748c7 in fseeko (fp=0x63ff40, offset=offset@entry=8, whence=whence@entry=1) at fseeko.c:39                                                                                    
#3  0x00007ffff779b1d2 in SeekBlob (image=image@entry=0x6366b0, offset=offset@entry=8, whence=whence@entry=1) at MagickCore/blob.c:4627                                                        
#4  0x00007ffff794e964 in SkipDXTMipmaps (image=0x6366b0, dds_info=0x7fffffff45e0, texel_size=8, exception=<optimized out>) at coders/dds.c:2552                                               
#5  0x00007ffff794de03 in ReadDDSImage (image_info=0x61fe10, exception=0x612c90) at coders/dds.c:1830                                                                                          
#6  0x00007ffff77c962f in ReadImage (image_info=image_info@entry=0x61cb20, exception=exception@entry=0x612c90) at MagickCore/constitute.c:555                                                  
#7  0x00007ffff77ca64f in ReadImages (image_info=image_info@entry=0x619830, filename=filename@entry=0x611c10 "/tmp/cpu-poc2", exception=exception@entry=0x612c90)                              
    at MagickCore/constitute.c:866                                                             
#8  0x00007ffff742dbb3 in ConvertImageCommand (image_info=0x619830, argc=3, argv=0x611b50, metadata=0x7fffffffc180, exception=0x612c90) at MagickWand/convert.c:641                            
#9  0x00007ffff7499764 in MagickCommandGenesis (image_info=image_info@entry=0x616540, command=command@entry=0x400f50 <ConvertImageCommand@plt>, argc=argc@entry=3,                             
    argv=argv@entry=0x7fffffffe4d8, metadata=0x0, exception=exception@entry=0x612c90) at MagickWand/mogrify.c:183                                                                              
#10 0x00000000004011cf in MagickMain (argc=3, argv=0x7fffffffe4d8) at utilities/magick.c:149   
#11 0x00007ffff6e23f45 in __libc_start_main (main=0x400fd0 <main>, argc=3, argv=0x7fffffffe4d8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>,                         
    stack_end=0x7fffffffe4c8) at libc-start.c:287                                              
#12 0x0000000000400ffe in _start ()  

when debug found dds_info->mipmapcount is very large

2549          for (i = 1; (i < (ssize_t) dds_info->mipmapcount) && w && h; i++)                                                                                                        [67/733]
(gdb)                                                                                                                                                                                          
2551            offset=(MagickOffsetType)((w+3)/4)*((h+3)/4)*texel_size;                                                                                                                       
(gdb)                                                                                                                                                                                          
2552            if (SeekBlob(image,offset,SEEK_CUR) < 0)                                                                                                                                       
(gdb)                                                                                                                                                                                          
2551            offset=(MagickOffsetType)((w+3)/4)*((h+3)/4)*texel_size;                                                                                                                       
(gdb)                                                                                                                                                                                          
2552            if (SeekBlob(image,offset,SEEK_CUR) < 0)                                                                                                                                       
(gdb)                                                                                                                                                                                          
2551            offset=(MagickOffsetType)((w+3)/4)*((h+3)/4)*texel_size;                                                                                                                       
(gdb)                                                                                                                                                                                          
2552            if (SeekBlob(image,offset,SEEK_CUR) < 0)                                                                                                                                       
(gdb)                                                                                                                                                                                          
2554            w=DIV2(w);                                                                                                                                                                     
(gdb)                                                                                                                                                                                          
2555            h=DIV2(h);                                                                                                                                                                     
(gdb)                                                                                                                                                                                          
2549          for (i = 1; (i < (ssize_t) dds_info->mipmapcount) && w && h; i++)                                                                                                                
(gdb)                                                                                                                                                                                          
2551            offset=(MagickOffsetType)((w+3)/4)*((h+3)/4)*texel_size;                                                                                                                       
(gdb)                                          
2552            if (SeekBlob(image,offset,SEEK_CUR) < 0)                                       
(gdb)                                          
2551            offset=(MagickOffsetType)((w+3)/4)*((h+3)/4)*texel_size;                       
(gdb)                                          
2552            if (SeekBlob(image,offset,SEEK_CUR) < 0)                                       
(gdb)                                          
2551            offset=(MagickOffsetType)((w+3)/4)*((h+3)/4)*texel_size;                       
(gdb)                                                                                                                                                                                          
2552            if (SeekBlob(image,offset,SEEK_CUR) < 0)                                                                                                                                       
(gdb)                                                                                                                                                                                          
2554            w=DIV2(w);                                                                                                                                                                     
(gdb)                                          
2555            h=DIV2(h);                                                                                                                                                                     
(gdb)                                                                                                                                                                                          
2549          for (i = 1; (i < (ssize_t) dds_info->mipmapcount) && w && h; i++)                                                                                                                
(gdb)                                                                                          
2551            offset=(MagickOffsetType)((w+3)/4)*((h+3)/4)*texel_size;                                                                                                                       
(gdb)                                                                                          
2552            if (SeekBlob(image,offset,SEEK_CUR) < 0)                                       
(gdb)                                          
2551            offset=(MagickOffsetType)((w+3)/4)*((h+3)/4)*texel_size;                                      
(gdb) p dds_info->mipmapcount                  
$1 = 4289331201           

testcase:
https://github.com/henices/pocs/raw/master/SeekBlob--cpu-exhaustion

Credit: NSFocus Security Team <security (at) nsfocus (dot) com>

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions