[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: tiff / CVE-2018-7456



Hi Brian,

> > Under certain conditions, the td->td_transferfunction table might not
> > have the excepted size, that is it may not have the excepted number of
> > samples per pixel (td->td_samplesperpixel). In this case for example,
> > the table is only 3 rows large while td->td_samplesperpixel is 4. Then,
> > the program segfaults when it comes to td->td_transferfunction[3][0].
> 
> The faulty test case is where the table is suppose to have three
> entries, but only two entries are provided.

Sure ? To me it looked like three entries are provided, but the fourth
(td->td_transferfunction[3]) isn't.

$ ASAN_OPTIONS=abort_on_error=1 gdb tiffinfo
[snip]
(gdb) r -c ../1-tiffinfo-c-null
Starting program: /usr/local/bin/tiffinfo -c ../1-tiffinfo-c-null
[Thread debugging using libthread_db enabled]
Using host libthread_db library
"/lib/x86_64-linux-gnu/libthread_db.so.1".
TIFFReadDirectoryCheckOrder: Warning, Invalid TIFF directory; tags are
not sorted in ascending order.
TIFFReadDirectory: Warning, Unknown field with tag 314 (0x13a)
encountered.
TIFFReadDirectory: Warning, Unknown field with tag 54034 (0xd312)
encountered.
TIFFFetchNormalTag: Warning, Incorrect count for "YResolution"; tag
ignored.
TIFF Directory at offset 0x767fe (485374)
  Image Width: 1024 Image Length: 768
  Resolution: 2, 0 (unitless)
  Bits/Sample: 8
  Compression Scheme: LZW
  Photometric Interpretation: RGB color
  Samples/Pixel: 4
  Planar Configuration: single image plane
  Transfer Function:
 
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff6bb1da1 in TIFFPrintDirectory (tif=0x619000000080,
fd=0x7ffff5ed8600 <_IO_2_1_stdout_>, flags=6) at tif_print.c:551
551                         td->td_transferfunction[i][l]);
(gdb) l
546                 uint16 i;
547                 fprintf(fd, "    %2ld: %5u",
548                     l, td->td_transferfunction[0][l]);
549                 for (i = 1; i < td->td_samplesperpixel; i++)
550                     fprintf(fd, " %5u",
551                         td->td_transferfunction[i][l]);
552                 fputc('\n', fd);
553             }
554         } else
555             fprintf(fd, "(present)\n");
(gdb) p td->td_transferfunction
$1 = {0x615000000580, 0x615000000800, 0x615000000a80}

> The defintion of td_transferfunction is:
> 
> typedef struct {
>     ...
>     uint16* td_transferfunction[3];
>     ...
> } TIFFDirectory;
>
> My assumption was that the list would be NULL terminated. In practise it
> is NULL terminated (might be accidental due to newly allocated memory
> being initialized to 0), but I should double check this.

I think we should really avoid relying on NULL termination for this
patch, because nothing guarantees us that this fourth element has been
initialized to 0 at any moment, right ?
 
> However, as this table is only 3 entries long (huh? Is that hardcoded
> value really safe here?), so it cannot be null terminated for the case
> where there are three tables.

Hum well, actually the specification states:

    The TransferFunction can be applied to images with a
    PhotometricInterpretation value of RGB, Palette, YCbCr, WhiteIsZero,
    and BlackIsZero. The TransferFunction is not used with other
    PhotometricInterpretation types.

    TIFF 6.0 Specification, p84[0]

Palette => td->td_samplesperpixel = 1
YCbCr => td->td_samplesperpixel = 3
WhiteIsZero => td->td_samplesperpixel = 1
RGB => td->td_samplesperpixel = 3 (unless ExtraSamples specified, we
                                   will take a look at it later)

So, in fact it may very well be that the size of the TransferFunction table
is always at most 3 rows and this definition is right.

However, there is still the case of RGB where we may still have
td->td_samplesperpixel > 3 (this is our case, here td->td_samplesperpixel = 4
and td->td_photometric = 2 which is RGB).

There are two possibilities
    (1) ExtraSamples = 1 => Associated alpha data (with pre-multiplied color)
    (2) ExtraSamples = 2 => Unassociated alpha data

I didn't have time to read all information about these two cases, but at
a first glance I noticed something interesting.

The specification states:

    Since the ExtraSamples field is independent of other fields, this
    scheme permits alpha information to be stored in whatever organization
    is appropriate. In particular, components can be stored packed
    (PlanarConfiguration=1); [... snip] However, if this scheme is used,
    TIFF readers must not derive the SamplesPerPixel from the value of the
    PhotometricInterpretation field (e.g., if RGB, then SamplesPerPixel is
    3).

    TIFF 6.0 Specification, p78[0]

In our case, while components are stored packed (because td->td_planarconfig = 1),
the td->td_samplesperpixel is still 4 and not 3, so the specification isn't
really respected, right ?

> However, it still could be null terminated for less then three entries.

Maybe, but if I don't misunderstand the problem, the bug is not affecting
us if td->td_samplesperpixel < 3 because there is no inconsistency anymore,
that is td->td_samplesperpixel is not bigger than the td_transferfunction
array. 

Cheers,
 Hugo

[0] https://www.itu.int/itudoc/itu-t/com16/tiff-fx/docs/tiff6.pdf

-- 
             Hugo Lefeuvre (hle)    |    www.owl.eu.com
4096/ 9C4F C8BF A4B0 8FC5 48EB 56B8 1962 765B B9A8 BACA

Attachment: signature.asc
Description: PGP signature


Reply to: