From af1cf0789aef7baa4c8093b52058bbcc4672c1f7 Mon Sep 17 00:00:00 2001
From: Su Laus <[EMAIL REDACTED]>
Date: Tue, 9 Aug 2022 15:15:57 +0000
Subject: [PATCH] TIFFSetValue(): Writing IFD8 & LONG8 tags to ClassicTIFF
corrected (fixes #442)
---
libtiff/tif_dir.c | 70 +++++++++++++++++++++++++++++-
libtiff/tif_dirwrite.c | 97 +++++++++++++++++++++++++++++++++++++++++-
2 files changed, 164 insertions(+), 3 deletions(-)
diff --git a/libtiff/tif_dir.c b/libtiff/tif_dir.c
index e90f14a0..ce3e2297 100644
--- a/libtiff/tif_dir.c
+++ b/libtiff/tif_dir.c
@@ -652,6 +652,30 @@ _TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap)
/*--: Rational2Double: For Rationals tv_size is set above to 4 or 8 according to fip->set_field_type! */
_TIFFmemcpy(tv->value, va_arg(ap, void *),
tv->count * tv_size);
+ /* Test here for too big values for LONG8, SLONG8 in ClassicTIFF and delete custom field from custom list */
+ if (!(tif->tif_flags & TIFF_BIGTIFF)) {
+ if (tv->info->field_type == TIFF_LONG8) {
+ uint64_t *pui64 = (uint64_t *)tv->value;
+ for (int i = 0; i < tv->count; i++) {
+ if (pui64[i] > 0xffffffffu) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Bad LONG8 value %"PRIu64" at %d. array position for \"%s\" tag %d in ClassicTIFF. Tag won't be written to file",
+ tif->tif_name, pui64[i], i, fip ? fip->field_name : "Unknown", tag);
+ goto badvalueifd8long8;
+ }
+ }
+ } else if (tv->info->field_type == TIFF_SLONG8) {
+ int64_t *pi64 = (int64_t *)tv->value;
+ for (int i = 0; i < tv->count; i++) {
+ if (pi64[i] > 2147483647 || pi64[i] < (-2147483647 - 1)) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Bad SLONG8 value %"PRIi64" at %d. array position for \"%s\" tag %d in ClassicTIFF. Tag won't be written to file",
+ tif->tif_name, pi64[i], i, fip ? fip->field_name : "Unknown", tag);
+ goto badvalueifd8long8;
+ }
+ }
+ }
+ }
} else {
char *val = (char *)tv->value;
assert( tv->count == 1 );
@@ -700,12 +724,26 @@ _TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap)
{
uint64_t v2 = va_arg(ap, uint64_t);
_TIFFmemcpy(val, &v2, tv_size);
+ /* Test here for too big values for ClassicTIFF and delete custom field from custom list */
+ if (!(tif->tif_flags & TIFF_BIGTIFF) && (v2 > 0xffffffffu)) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Bad LONG8 or IFD8 value %"PRIu64" for \"%s\" tag %d in ClassicTIFF. Tag won't be written to file",
+ tif->tif_name, v2, fip ? fip->field_name : "Unknown", tag);
+ goto badvalueifd8long8;
+ }
}
break;
case TIFF_SLONG8:
{
int64_t v2 = va_arg(ap, int64_t);
_TIFFmemcpy(val, &v2, tv_size);
+ /* Test here for too big values for ClassicTIFF and delete custom field from custom list */
+ if (!(tif->tif_flags & TIFF_BIGTIFF) && ((v2 > 2147483647) || (v2 < (-2147483647 - 1)))) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Bad SLONG8 value %"PRIi64" for \"%s\" tag %d in ClassicTIFF. Tag won't be written to file",
+ tif->tif_name, v2, fip ? fip->field_name : "Unknown", tag);
+ goto badvalueifd8long8;
+ }
}
break;
case TIFF_RATIONAL:
@@ -787,7 +825,37 @@ _TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap)
va_end(ap);
}
return (0);
-}
+badvalueifd8long8:
+ {
+ /* Error message issued already above. */
+ TIFFTagValue *tv2 = NULL;
+ int iCustom2, iC2;
+ /* Find the existing entry for this custom value. */
+ for (iCustom2 = 0; iCustom2 < td->td_customValueCount; iCustom2++) {
+ if (td->td_customValues[iCustom2].info->field_tag == tag) {
+ tv2 = td->td_customValues + (iCustom2);
+ break;
+ }
+ }
+ if (tv2 != NULL) {
+ /* Remove custom field from custom list */
+ if (tv2->value != NULL) {
+ _TIFFfree(tv2->value);
+ tv2->value = NULL;
+ }
+ /* Shorten list and close gap in customValues list.
+ * Re-allocation of td_customValues not necessary here. */
+ td->td_customValueCount--;
+ for (iC2 = iCustom2; iC2 < td->td_customValueCount; iC2++) {
+ td->td_customValues[iC2] = td->td_customValues[iC2+1];
+ }
+ } else {
+ assert(0);
+ }
+ va_end(ap);
+ }
+ return (0);
+} /*-- _TIFFVSetField() --*/
/*
* Return 1/0 according to whether or not
diff --git a/libtiff/tif_dirwrite.c b/libtiff/tif_dirwrite.c
index 2fef6d82..1d8b80a8 100644
--- a/libtiff/tif_dirwrite.c
+++ b/libtiff/tif_dirwrite.c
@@ -1553,15 +1553,59 @@ TIFFWriteDirectoryTagLong8(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_
}
#endif
+/************************************************************************/
+/* TIFFWriteDirectoryTagLong8Array() */
+/* */
+/* Write either Long8 or Long array depending on file type. */
+/************************************************************************/
static int
TIFFWriteDirectoryTagLong8Array(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint64_t* value)
{
+ static const char module[] = "TIFFWriteDirectoryTagLong8Array";
+ uint64_t *ma;
+ uint32_t mb;
+ uint32_t *p;
+ uint32_t *q;
+ int o;
+
+ /* is this just a counting pass? */
if (dir==NULL)
{
(*ndir)++;
return(1);
}
- return(TIFFWriteDirectoryTagCheckedLong8Array(tif,ndir,dir,tag,count,value));
+
+ /* We always write Long8 for BigTIFF, no checking needed. */
+ if (tif->tif_flags & TIFF_BIGTIFF)
+ return(TIFFWriteDirectoryTagCheckedLong8Array(tif, ndir, dir, tag, count, value));
+
+ /*
+ ** For classic tiff we want to verify everything is in range for long
+ ** and convert to long format.
+ */
+ p = _TIFFmalloc(count * sizeof(uint32_t));
+ if (p == NULL)
+ {
+ TIFFErrorExt(tif->tif_clientdata, module, "Out of memory");
+ return(0);
+ }
+
+ for (q = p, ma = value, mb = 0; mb < count; ma++, mb++, q++)
+ {
+ if (*ma > 0xFFFFFFFF)
+ {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Attempt to write unsigned long value %"PRIu64" larger than 0xFFFFFFFF for tag %d in Classic TIFF file. TIFF file writing aborted", *ma, tag);
+ _TIFFfree(p);
+ return(0);
+ }
+ *q = (uint32_t)(*ma);
+ }
+
+ o = TIFFWriteDirectoryTagCheckedLongArray(tif, ndir, dir, tag, count, p);
+ _TIFFfree(p);
+
+ return(o);
}
#ifdef notdef
@@ -1577,15 +1621,64 @@ TIFFWriteDirectoryTagSlong8(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16
}
#endif
+/************************************************************************/
+/* TIFFWriteDirectoryTagSlong8Array() */
+/* */
+/* Write either SLong8 or SLong array depending on file type. */
+/************************************************************************/
static int
TIFFWriteDirectoryTagSlong8Array(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, int64_t* value)
{
+ static const char module[] = "TIFFWriteDirectoryTagSlong8Array";
+ int64_t *ma;
+ uint32_t mb;
+ int32_t *p;
+ int32_t *q;
+ int o;
+
+ /* is this just a counting pass? */
if (dir==NULL)
{
(*ndir)++;
return(1);
}
- return(TIFFWriteDirectoryTagCheckedSlong8Array(tif,ndir,dir,tag,count,value));
+ /* We always write SLong8 for BigTIFF, no checking needed. */
+ if (tif->tif_flags & TIFF_BIGTIFF)
+ return(TIFFWriteDirectoryTagCheckedSlong8Array(tif, ndir, dir, tag, count, value));
+
+ /*
+ ** For classic tiff we want to verify everything is in range for signed-long
+ ** and convert to signed-long format.
+ */
+ p = _TIFFmalloc(count * sizeof(uint32_t));
+ if (p == NULL)
+ {
+ TIFFErrorExt(tif->tif_clientdata, module, "Out of memory");
+ return(0);
+ }
+
+ for (q = p, ma = value, mb = 0; mb < count; ma++, mb++, q++)
+ {
+ if (*ma > (2147483647))
+ {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Attempt to write signed long value %"PRIi64" larger than 0x7FFFFFFF (2147483647) for tag %d in Classic TIFF file. TIFF writing to file aborted", *ma, tag);
+ _TIFFfree(p);
+ return(0);
+ } else if (*ma < (-2147483647 - 1))
+ {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Attempt to write signed long value %"PRIi64" smaller than 0x80000000 (-2147483648) for tag %d in Classic TIFF file. TIFF writing to file aborted", *ma, tag);
+ _TIFFfree(p);
+ return(0);
+ }
+ *q = (int32_t)(*ma);
+ }
+
+ o = TIFFWriteDirectoryTagCheckedSlongArray(tif, ndir, dir, tag, count, p);
+ _TIFFfree(p);
+
+ return(o);
}
static int