Bug 234080 - media-libs/tiff <3.8.2-r4 buffer underflow in LZW decoding (CVE-2008-2327)
Bug#: 234080 (CVE-2008-2327) Product:  Gentoo Security Version: unspecified Platform: All
OS/Version: Linux Status: RESOLVED Severity: normal Priority: P2
Resolution: FIXED Assigned To: security@gentoo.org Reported By: rbu@gentoo.org
Component: Vulnerabilities
URL: 
Summary: media-libs/tiff <3.8.2-r4 buffer underflow in LZW decoding (CVE-2008-2327)
Keywords:  
Status Whiteboard: A2 [glsa]
Opened: 2008-08-06 12:15 0000
Description:   Opened: 2008-08-06 12:15 0000
** Please note that this issue is confidential and no information should be
disclosed until it is made public, see "Whiteboard" for a date **

Drew Yao writes:
We have found a security issue in libTIFF's handling of LZW-encoded  
images.  The use of uninitialized data could lead to a buffer  
underflow and a crash or arbitrary code execution.

CVE-ID: CVE-2008-2327

Versions known to be affected:
v3.8.2

Timing:
This issue should remain embargoed until 8/25/2008.

Credit:
Drew Yao of Apple Product Security

We have contacted the libTIFF maintainers about this issue.

A brief introduction to LZW decoding:
http://www.fileformat.info/format/tiff/corion-lzw.htm
http://en.wikipedia.org/wiki/Lzw#Decoding

The LZW algorithm is based on a translation table, or string table,  
that maps strings of input characters into codes. The TIFF  
implementation uses variable-length codes, with a maximum code length  
of 12 bits
The string table is initialized to contain all possible single- 
character strings. There are 256 of them, numbered 0 through 255,  
since our characters are bytes.  There are also special codes:
#define CODE_CLEAR      256             /* code to clear string table */
#define CODE_EOI        257             /* end-of-information code */
#define CODE_FIRST      258             /* first free code entry */
As decoding continues, longer strings are added to the string table as  
linked lists of characters.  If the string table gets full(4096  
entries), there is a "Clear code" which signals to reinitialize the  
string table.

tif_lzw.c

In LZWSetupDecode():
              sp->dec_codetab = (code_t*)_TIFFmalloc(CSIZE*sizeof  (code_t));

In LZWPreDecode():
       sp->dec_free_entp = sp->dec_codetab + CODE_FIRST;
      /*
       * Zero entries that are not yet filled in.  We do
       * this to guard against bogus input data that causes
       * us to index into undefined entries.  If you can
       * come up with a way to safely bounds-check input codes
       * while decoding then you can remove this operation.
       */
      _TIFFmemset(sp->dec_free_entp, 0, (CSIZE-CODE_FIRST)*sizeof  (code_t));


In LZWDecodeCompat(), LZWDecode(), and LZWDecodeVector(), when a  
CODE_CLEAR code is received, the string table does not get re-zeroed,  
leading to uninitialized data in the table being used, if the next  
code after the CODE_CLEAR is > CODE_FIRST.

For example in LZWDecodeCompat():
      while (occ > 0) {
              NextCode(tif, sp, bp, code, GetNextCodeCompat);
              if (code == CODE_EOI)
                      break;
              if (code == CODE_CLEAR) {
                      free_entp = sp->dec_codetab +  CODE_FIRST;          <--
free_entp points to the first free entry  
after the constant entries.
                      nbits = BITS_MIN;
                      nbitsmask = MAXCODE(BITS_MIN);
                      maxcodep = sp->dec_codetab + nbitsmask;
                      NextCode(tif, sp, bp, code,  GetNextCodeCompat);     <--
get the next code.   The implementation  
expects it to be < CODE_FIRST, but that might not be true in a  
malicious file.
                      if (code == CODE_EOI)
                              break;
                      *op++ = code, occ--;
                      oldcodep = sp->dec_codetab + code;
                      continue;
              }
              codep = sp->dec_codetab + code;              <--codep  
points into uninitialized data
...

                      do {
                              *--tp = codep->value;                    <--
potential buffer underflow
                      } while( (codep = codep->next) != NULL);


[...]

A simple fix is to zero out the whole string table starting at  
CODE_FIRST whenever a CODE_CLEAR is received.
The attached patch against 3.8.2 does this.

I have tested this fix to properly display a bunch of valid files, and  
not crash after heavy fuzzing.

------- Comment #1 From Robert Buchholz 2008-08-06 12:39:06 0000 -------
Drew also informed us about the following issue:
http://bugzilla.maptools.org/show_bug.cgi?id=1929

------- Comment #2 From Robert Buchholz 2008-08-06 12:44:31 0000 -------
Created an attachment (id=162354) [details]
tiff-3.8.2-CVE-2008-2327.patch

------- Comment #3 From Robert Buchholz 2008-08-06 12:44:51 0000 -------
Created an attachment (id=162356) [details]
tiff-3.8.2-bug1929.patch

------- Comment #4 From Robert Buchholz 2008-08-20 12:48:15 0000 -------
We have no upstream comment on either of the two patches, and probably won't
have until after the embargo timeline. I'll attach an ebuild applying the
existing patches, and we can update them later if upstream decides otherwise.

------- Comment #5 From Robert Buchholz 2008-08-20 12:48:34 0000 -------
Created an attachment (id=163378) [details]
tiff-3.8.2-r4.ebuild

------- Comment #6 From Robert Buchholz 2008-08-20 12:49:25 0000 -------
Arch Security Liaisons, please test the attached ebuild and report it stable on
this bug.
Target keywords : "alpha amd64 arm hppa ia64 m68k ppc ppc64 s390 sh sparc x86"

CC'ing current Liaisons:
   alpha : yoswink, armin76
   amd64 : keytoaster, tester
    hppa : jer
     ppc : dertobi123
   ppc64 : corsair
   sparc : fmccor
     x86 : maekke, armin76

------- Comment #7 From Jeroen Roovers 2008-08-20 15:47:43 0000 -------
HPPA is OK.

------- Comment #8 From Markus Meier 2008-08-20 17:50:38 0000 -------
looks good on amd64/x86.

------- Comment #9 From Markus Rothe 2008-08-20 22:39:48 0000 -------
looks good on ppc64

------- Comment #10 From Jose Luis Rivero (yoswink) 2008-08-20 23:24:44 0000 -------
alpha is ok

------- Comment #11 From Robert Buchholz 2008-08-26 14:32:05 0000 -------
now public via http://secunia.com/advisories/31610/

------- Comment #12 From Robert Buchholz 2008-08-26 14:53:44 0000 -------
I combined both patches into one because it was decided to combine both issues
(Drew Yao and the upstream bug) into the CVE. Committed the ebuild to the tree
with the gathered keywords, still to do:

Arches, please test and mark stable:
=media-libs/tiff-3.8.2-r4
Target keywords : "alpha amd64 arm hppa ia64 m68k ppc ppc64 s390 sh sparc x86"
Already stabled : "alpha amd64 hppa ppc64 x86"
Missing keywords: "arm ia64 m68k ppc s390 sh sparc"

------- Comment #13 From Raúl Porcel 2008-08-26 15:04:09 0000 -------
ia64/sparc stable

------- Comment #14 From Tobias Scherbaum 2008-08-30 11:30:45 0000 -------
ppc stable

------- Comment #15 From Tobias Heinlein 2008-09-02 17:01:59 0000 -------
GLSA request filed.

------- Comment #16 From Pierre-Yves Rofes 2008-09-08 18:01:22 0000 -------
GLSA 200809-07