Summary – 10.10.2011
Name: Apple OSX / iPhone iOS ImageIO TIFF getBandProcTIFF TileWidth Heap Overflow
Reference: NGS00062
Discoverer: Dominic Chell
Vendor: Apple
Vendor Reference: 145575681
Systems Affected: Apple OSX / iPhone iOS / Possibly others using LibTiff
Risk: High
Status: Fixed
TimeLine
Discovered: 27 February 2011
Released: 27 February 2011
Approved: 29 March 2011
Reported: 29 March 2011
Fixed: 23 June 2011
Published: 10 October 2011
Description
Heap overflow caused by overly large tilewidth image tag in getBandProcTiff()
Technical Details
The Offset 8BE6 is changed from 17 to 42. This field is the tiff tag StripByteCounts. Valid value is 1701 which signifies the StripByteCounts tiff tag. Flipping the stripbytescount field to 4201 causes the stripbytescount tag to be removed for the first page in the tiff image and be replaced with the tilewidth image tag. The definition of this image tag can be found here:
http://www.awaresystems.be/imaging/tiff/tifftags/tilewidth.html
The value for the tilewidth tag is read from 8BEE to 8BF1 inclusive. Setting the tilewidth to 00800000 (8388608) causes the following crash:
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x00000001007ca000
[Switching to process 2342]
0x00007fffffe00847 in __memcpy ()
(gdb) i r
rax 0xffffffffeb790000 -344391680
rbx 0x10078c000 4302880768
rcx 0xfffffffffff3e000 -794624
rdx 0x0 0
rsi 0x1150fc000 4648321024
rdi 0x10088c000 4303929344
rbp 0x102ed7790 0x102ed7790
rsp 0x102ed7790 0x102ed7790
r8 0x15dafbfff 5866766335
r9 0x7 7
r10 0x10340ddf0 4349550064
r11 0x10078c000 4302880768
r12 0x1 1
r13 0x100000 1048576
r14 0x0 0
r15 0x0 0
rip 0x7fffffe00847 0x7fffffe00847 <__memcpy+167>
eflags 0x10286 66182
cs 0x27 39
ss 0x0 0
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) x/i $rip
0x7fffffe00847 <__memcpy+167>: movdqa XMMWORD PTR [rdi+rcx],xmm0
(gdb)
Reducing the tilewidth to 0000FF00 or 65280 we get a different crash:
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x00000001007c7000
[Switching to process 2379]
0x00007fffffe007c5 in __memcpy ()
(gdb) i r
rax 0xffffffff 4294967295
rbx 0x1007c5030 4303114288
rcx 0x4 4
rdx 0x20 32
rsi 0x1159c4194 4657529236
rdi 0x1007c7000 4303122432
rbp 0x10067d790 0x10067d790
rsp 0x10067d790 0x10067d790
r8 0x1159f3e9f 4657725087
r9 0x7 7
r10 0x100122cc0 4296158400
r11 0x1007c5030 4303114288
r12 0x473 1139
r13 0x1fe0 8160
r14 0x0 0
r15 0x0 0
rip 0x7fffffe007c5 0x7fffffe007c5 <__memcpy+37>
eflags 0x10202 66050
cs 0x27 39
ss 0x0 0
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) x/i $rip
0x7fffffe007c5 <__memcpy+37>: mov DWORD PTR [rdi],eax
(gdb)
(gdb) bt
#0 0x00007fffffe007c5 in __memcpy ()
#1 0x00007fff80f766ef in getBandProcTIFF ()
Disassembly of function:
Breakpoint here:
0x00007fff80f765a4
Function reads the value of the TileWidth, arguments:
rsi 0x142 322
esi contains the tiff image tag for tile width that this function extracts the value for, in this instance its 322 which is TileWidth.
0x00007fff80f765a9
0x00007fff80f765ad
0x00007fff80f765b4
0x00007fff80f765b8
0x00007fff80f765bd
0x00007fff80f765bf
0x00007fff80f765c4
0x00007fff80f765c7
0x00007fff80f765ca
0x00007fff80f765cd
0x00007fff80f765cf
0x00007fff80f765d2
0x00007fff80f765d9
0x00007fff80f765dc
0x00007fff80f765e1
0x00007fff80f765e8
0x00007fff80f765ec
0x00007fff80f765f0
0x00007fff80f765f7
0x00007fff80f765fb
0x00007fff80f76602
0x00007fff80f76609
0x00007fff80f7660b
0x00007fff80f7660e
0x00007fff80f76612
0x00007fff80f76619
0x00007fff80f7661c
0x00007fff80f76623
0x00007fff80f7662a
0x00007fff80f7662e
0x00007fff80f76632
0x00007fff80f76639
0x00007fff80f76640
0x00007fff80f76643
0x00007fff80f76648
0x00007fff80f7664b
0x00007fff80f76652
0x00007fff80f76657
0x00007fff80f7665b
0x00007fff80f7665e
0x00007fff80f76661
0x00007fff80f76664
0x00007fff80f7666b
0x00007fff80f76670
0x00007fff80f76672
0x00007fff80f76674
0x00007fff80f7667b
0x00007fff80f76680
0x00007fff80f76683
0x00007fff80f76686
0x00007fff80f7668d
0x00007fff80f7668f
0x00007fff80f76696
0x00007fff80f76699
0x00007fff80f7669b
0x00007fff80f7669e
0x00007fff80f766a5
0x00007fff80f766a9
0x00007fff80f766ad
0x00007fff80f766b1
0x00007fff80f766b5
0x00007fff80f766b9
0x00007fff80f766bd
0x00007fff80f766c1
0x00007fff80f766c8
0x00007fff80f766cc
// loops copying from a ptr in to a buffer
0x00007fff80f766cf
0x00007fff80f766d1
0x00007fff80f766d9
0x00007fff80f766e0
0x00007fff80f766e4
0x00007fff80f766e7
0x00007fff80f766ea
0x00007fff80f766ef
0x00007fff80f766f6
0x00007fff80f766f9
0x00007fff80f766fc
0x00007fff80f76703
0x00007fff80f76705
0x00007fff80f76709
0x00007fff80f7670c
0x00007fff80f76713
0x00007fff80f76719
0x00007fff80f76720
0x00007fff80f76727
0x00007fff80f7672d
0x00007fff80f76734
0x00007fff80f76739
0x00007fff80f76740
0x00007fff80f76744
0x00007fff80f7674a
It appears as the tileWidth controls the size of the iterator in a previous loop. In turn we can control the number of times the memcpy() is called and the amount of buffer copied.
For example, tileWidth = FF00:
Breakpoint 6, 0x00007fff80f766ea in getBandProcTIFF ()
r12 0x473 1139
0x7fff80f766ea
The number of iterations is stored in the $r12 register.
Decreasing the tileWidth causes the loop to iterate more, tileWidth=DD00 because the value incremented is lower:
r12 0x478 1144
When we use a large value such as, 00800000 (8388608) we only call memcpy() once:
r12 0x1 1
(gdb) x/i $rip
0x7fffffe00847 <__memcpy+167>: movdqa XMMWORD PTR [rdi+rcx],xmm0
(gdb)
I believe this triggers the integer overflow and in turn an overflow in the memcpy.
Fix Information
Apple has released a patch that addresses the issue. The announcement of the patch can be found here:
http://support.apple.com/kb/HT4723