openbsd-ports/graphics/tiff/patches/patch-libtiff_tif_dirread_c
naddy fab96bfad1 SECURITY fixes for CVE-2006-2656 and CVE-2006-3459 through 3465.
Man page fixes.

Mostly via FreeBSD.  Approving noises from bernd@ and jasper@
2008-10-25 09:39:29 +00:00

325 lines
12 KiB
Plaintext

$OpenBSD: patch-libtiff_tif_dirread_c,v 1.5 2008/10/25 09:39:29 naddy Exp $
CVE-2006-3459,3463,3464,3465
--- libtiff/tif_dirread.c.orig Tue Mar 21 17:42:50 2006
+++ libtiff/tif_dirread.c Fri Oct 24 18:54:00 2008
@@ -29,6 +29,9 @@
*
* Directory Read Support Routines.
*/
+
+#include <limits.h>
+
#include "tiffiop.h"
#define IGNORE 0 /* tag placeholder used below */
@@ -81,6 +84,7 @@ TIFFReadDirectory(TIFF* tif)
uint16 dircount;
toff_t nextdiroff;
int diroutoforderwarning = 0;
+ int compressionknown = 0;
toff_t* new_dirlist;
tif->tif_diroff = tif->tif_nextdiroff;
@@ -147,13 +151,20 @@ TIFFReadDirectory(TIFF* tif)
} else {
toff_t off = tif->tif_diroff;
- if (off + sizeof (uint16) > tif->tif_size) {
- TIFFErrorExt(tif->tif_clientdata, module,
- "%s: Can not read TIFF directory count",
- tif->tif_name);
- return (0);
+ /*
+ * Check for integer overflow when validating the dir_off, otherwise
+ * a very high offset may cause an OOB read and crash the client.
+ * -- taviso@google.com, 14 Jun 2006.
+ */
+ if (off + sizeof (uint16) > tif->tif_size ||
+ off > (UINT_MAX - sizeof(uint16))) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Can not read TIFF directory count",
+ tif->tif_name);
+ return (0);
} else
- _TIFFmemcpy(&dircount, tif->tif_base + off, sizeof (uint16));
+ _TIFFmemcpy(&dircount, tif->tif_base + off,
+ sizeof (uint16));
off += sizeof (uint16);
if (tif->tif_flags & TIFF_SWAB)
TIFFSwabShort(&dircount);
@@ -254,6 +265,7 @@ TIFFReadDirectory(TIFF* tif)
while (fix < tif->tif_nfields &&
tif->tif_fieldinfo[fix]->field_tag < dp->tdir_tag)
fix++;
+
if (fix >= tif->tif_nfields ||
tif->tif_fieldinfo[fix]->field_tag != dp->tdir_tag) {
@@ -264,17 +276,23 @@ TIFFReadDirectory(TIFF* tif)
dp->tdir_tag,
dp->tdir_tag,
dp->tdir_type);
-
- TIFFMergeFieldInfo(tif,
- _TIFFCreateAnonFieldInfo(tif,
- dp->tdir_tag,
- (TIFFDataType) dp->tdir_type),
- 1 );
+ /*
+ * creating anonymous fields prior to knowing the compression
+ * algorithm (ie, when the field info has been merged) could cause
+ * crashes with pathological directories.
+ * -- taviso@google.com 15 Jun 2006
+ */
+ if (compressionknown)
+ TIFFMergeFieldInfo(tif, _TIFFCreateAnonFieldInfo(tif, dp->tdir_tag,
+ (TIFFDataType) dp->tdir_type), 1 );
+ else goto ignore;
+
fix = 0;
while (fix < tif->tif_nfields &&
tif->tif_fieldinfo[fix]->field_tag < dp->tdir_tag)
fix++;
}
+
/*
* Null out old tags that we ignore.
*/
@@ -326,6 +344,7 @@ TIFFReadDirectory(TIFF* tif)
dp->tdir_type, dp->tdir_offset);
if (!TIFFSetField(tif, dp->tdir_tag, (uint16)v))
goto bad;
+ else compressionknown++;
break;
/* XXX: workaround for broken TIFFs */
} else if (dp->tdir_type == TIFF_LONG) {
@@ -540,6 +559,7 @@ TIFFReadDirectory(TIFF* tif)
* Attempt to deal with a missing StripByteCounts tag.
*/
if (!TIFFFieldSet(tif, FIELD_STRIPBYTECOUNTS)) {
+ const TIFFFieldInfo* fip = _TIFFFieldWithTag(tif, TIFFTAG_STRIPBYTECOUNTS);
/*
* Some manufacturers violate the spec by not giving
* the size of the strips. In this case, assume there
@@ -556,7 +576,7 @@ TIFFReadDirectory(TIFF* tif)
"%s: TIFF directory is missing required "
"\"%s\" field, calculating from imagelength",
tif->tif_name,
- _TIFFFieldWithTag(tif,TIFFTAG_STRIPBYTECOUNTS)->field_name);
+ fip ? fip->field_name : "Unknown");
if (EstimateStripByteCounts(tif, dir, dircount) < 0)
goto bad;
/*
@@ -580,6 +600,7 @@ TIFFReadDirectory(TIFF* tif)
} else if (td->td_nstrips == 1
&& td->td_stripoffset[0] != 0
&& BYTECOUNTLOOKSBAD) {
+ const TIFFFieldInfo* fip = _TIFFFieldWithTag(tif, TIFFTAG_STRIPBYTECOUNTS);
/*
* XXX: Plexus (and others) sometimes give a value of zero for
* a tag when they don't know what the correct value is! Try
@@ -589,13 +610,14 @@ TIFFReadDirectory(TIFF* tif)
TIFFWarningExt(tif->tif_clientdata, module,
"%s: Bogus \"%s\" field, ignoring and calculating from imagelength",
tif->tif_name,
- _TIFFFieldWithTag(tif,TIFFTAG_STRIPBYTECOUNTS)->field_name);
+ fip ? fip->field_name : "Unknown");
if(EstimateStripByteCounts(tif, dir, dircount) < 0)
goto bad;
} else if (td->td_planarconfig == PLANARCONFIG_CONTIG
&& td->td_nstrips > 2
&& td->td_compression == COMPRESSION_NONE
&& td->td_stripbytecount[0] != td->td_stripbytecount[1]) {
+ const TIFFFieldInfo* fip = _TIFFFieldWithTag(tif, TIFFTAG_STRIPBYTECOUNTS);
/*
* XXX: Some vendors fill StripByteCount array with absolutely
* wrong values (it can be equal to StripOffset array, for
@@ -604,7 +626,7 @@ TIFFReadDirectory(TIFF* tif)
TIFFWarningExt(tif->tif_clientdata, module,
"%s: Wrong \"%s\" field, ignoring and calculating from imagelength",
tif->tif_name,
- _TIFFFieldWithTag(tif,TIFFTAG_STRIPBYTECOUNTS)->field_name);
+ fip ? fip->field_name : "Unknown");
if (EstimateStripByteCounts(tif, dir, dircount) < 0)
goto bad;
}
@@ -870,8 +892,14 @@ EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir,
register TIFFDirEntry *dp;
register TIFFDirectory *td = &tif->tif_dir;
- uint16 i;
+
+ /* i is used to iterate over td->td_nstrips, so must be
+ * at least the same width.
+ * -- taviso@google.com 15 Jun 2006
+ */
+ uint32 i;
+
if (td->td_stripbytecount)
_TIFFfree(td->td_stripbytecount);
td->td_stripbytecount = (uint32*)
@@ -947,16 +975,18 @@ MissingRequired(TIFF* tif, const char* tagname)
static int
CheckDirCount(TIFF* tif, TIFFDirEntry* dir, uint32 count)
{
+ const TIFFFieldInfo* fip = _TIFFFieldWithTag(tif, dir->tdir_tag);
+
if (count > dir->tdir_count) {
TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
"incorrect count for field \"%s\" (%lu, expecting %lu); tag ignored",
- _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name,
+ fip ? fip->field_name : "Unknown",
dir->tdir_count, count);
return (0);
} else if (count < dir->tdir_count) {
TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
"incorrect count for field \"%s\" (%lu, expecting %lu); tag trimmed",
- _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name,
+ fip ? fip->field_name : "Unknown",
dir->tdir_count, count);
return (1);
}
@@ -970,6 +1000,7 @@ static tsize_t
TIFFFetchData(TIFF* tif, TIFFDirEntry* dir, char* cp)
{
int w = TIFFDataWidth((TIFFDataType) dir->tdir_type);
+ const TIFFFieldInfo* fip = _TIFFFieldWithTag(tif, dir->tdir_tag);
tsize_t cc = dir->tdir_count * w;
/* Check for overflow. */
@@ -1013,7 +1044,7 @@ TIFFFetchData(TIFF* tif, TIFFDirEntry* dir, char* cp)
bad:
TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
"Error fetching data for field \"%s\"",
- _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
+ fip ? fip->field_name : "Unknown");
return (tsize_t) 0;
}
@@ -1039,10 +1070,12 @@ TIFFFetchString(TIFF* tif, TIFFDirEntry* dir, char* cp
static int
cvtRational(TIFF* tif, TIFFDirEntry* dir, uint32 num, uint32 denom, float* rv)
{
+ const TIFFFieldInfo* fip;
if (denom == 0) {
+ fip = _TIFFFieldWithTag(tif, dir->tdir_tag);
TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
"%s: Rational with zero denominator (num = %lu)",
- _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name, num);
+ fip ? fip->field_name : "Unknown", num);
return (0);
} else {
if (dir->tdir_type == TIFF_RATIONAL)
@@ -1159,6 +1192,20 @@ TIFFFetchShortArray(TIFF* tif, TIFFDirEntry* dir, uint
static int
TIFFFetchShortPair(TIFF* tif, TIFFDirEntry* dir)
{
+ /*
+ * Prevent overflowing the v stack arrays below by performing a sanity
+ * check on tdir_count, this should never be greater than two.
+ * -- taviso@google.com 14 Jun 2006.
+ */
+ if (dir->tdir_count > 2) {
+ const TIFFFieldInfo* fip = _TIFFFieldWithTag(tif, dir->tdir_tag);
+ TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
+ "unexpected count for field \"%s\", %lu, expected 2; ignored.",
+ fip ? fip->field_name : "Unknown",
+ dir->tdir_count);
+ return 0;
+ }
+
switch (dir->tdir_type) {
case TIFF_BYTE:
case TIFF_SBYTE:
@@ -1329,14 +1376,15 @@ TIFFFetchAnyArray(TIFF* tif, TIFFDirEntry* dir, double
case TIFF_DOUBLE:
return (TIFFFetchDoubleArray(tif, dir, (double*) v));
default:
+ { const TIFFFieldInfo* fip = _TIFFFieldWithTag(tif, dir->tdir_tag);
/* TIFF_NOTYPE */
/* TIFF_ASCII */
/* TIFF_UNDEFINED */
TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
"cannot read TIFF_ANY type %d for field \"%s\"",
dir->tdir_type,
- _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
- return (0);
+ fip ? fip->field_name : "Unknown");
+ return (0); }
}
return (1);
}
@@ -1351,6 +1399,9 @@ TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp)
int ok = 0;
const TIFFFieldInfo* fip = _TIFFFieldWithTag(tif, dp->tdir_tag);
+ if (fip == NULL) {
+ return (0);
+ }
if (dp->tdir_count > 1) { /* array of values */
char* cp = NULL;
@@ -1493,6 +1544,7 @@ static int
TIFFFetchPerSampleShorts(TIFF* tif, TIFFDirEntry* dir, uint16* pl)
{
uint16 samples = tif->tif_dir.td_samplesperpixel;
+ const TIFFFieldInfo* fip;
int status = 0;
if (CheckDirCount(tif, dir, (uint32) samples)) {
@@ -1510,9 +1562,10 @@ TIFFFetchPerSampleShorts(TIFF* tif, TIFFDirEntry* dir,
for (i = 1; i < check_count; i++)
if (v[i] != v[0]) {
+ fip = _TIFFFieldWithTag(tif, dir->tdir_tag);
TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
"Cannot handle different per-sample values for field \"%s\"",
- _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
+ fip ? fip->field_name : "Unknown");
goto bad;
}
*pl = v[0];
@@ -1534,6 +1587,7 @@ static int
TIFFFetchPerSampleLongs(TIFF* tif, TIFFDirEntry* dir, uint32* pl)
{
uint16 samples = tif->tif_dir.td_samplesperpixel;
+ const TIFFFieldInfo* fip;
int status = 0;
if (CheckDirCount(tif, dir, (uint32) samples)) {
@@ -1551,9 +1605,10 @@ TIFFFetchPerSampleLongs(TIFF* tif, TIFFDirEntry* dir,
check_count = samples;
for (i = 1; i < check_count; i++)
if (v[i] != v[0]) {
+ fip = _TIFFFieldWithTag(tif, dir->tdir_tag);
TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
"Cannot handle different per-sample values for field \"%s\"",
- _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
+ fip ? fip->field_name : "Unknown");
goto bad;
}
*pl = v[0];
@@ -1574,6 +1629,7 @@ static int
TIFFFetchPerSampleAnys(TIFF* tif, TIFFDirEntry* dir, double* pl)
{
uint16 samples = tif->tif_dir.td_samplesperpixel;
+ const TIFFFieldInfo* fip;
int status = 0;
if (CheckDirCount(tif, dir, (uint32) samples)) {
@@ -1591,9 +1647,10 @@ TIFFFetchPerSampleAnys(TIFF* tif, TIFFDirEntry* dir, d
for (i = 1; i < check_count; i++)
if (v[i] != v[0]) {
+ fip = _TIFFFieldWithTag(tif, dir->tdir_tag);
TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
"Cannot handle different per-sample values for field \"%s\"",
- _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
+ fip ? fip->field_name : "Unknown");
goto bad;
}
*pl = v[0];