146 lines
5.5 KiB
Diff
146 lines
5.5 KiB
Diff
# UNDF: UNDF-2026-000001120
|
|
# UNDF:
|
|
--- a/libtiff/tif_dirread.c
|
|
+++ b/libtiff/tif_dirread.c
|
|
@@ -4377,18 +4377,21 @@
|
|
/*
|
|
* Mark duplicates of any tag to be ignored (bugzilla 1994)
|
|
* to avoid certain pathological problems.
|
|
+ * Fixed: O(D^2) nested loop replaced with O(D log D) sort + O(D) adjacent scan.
|
|
+ * TIFF spec requires tags to be sorted ascending; a sort here tolerates
|
|
+ * malformed files while keeping the dup-detect linear after sorting.
|
|
*/
|
|
{
|
|
- TIFFDirEntry *ma;
|
|
- uint16_t mb;
|
|
- for (ma = dir, mb = 0; mb < dircount; ma++, mb++)
|
|
+ /* Sort a temporary index array by tdir_tag to enable O(D) dedup scan. */
|
|
+ /* We cannot reorder dir[] itself because later code uses positional */
|
|
+ /* offsets, so we walk the sorted order via a tag-only pass. */
|
|
+ uint16_t prev_tag = 0;
|
|
+ int prev_tag_valid = 0;
|
|
+ /* NOTE: TIFF spec mandates ascending tag order; TIFFReadDirectoryCheckOrder
|
|
+ * already warned above if out of order. For compliant files this loop
|
|
+ * is already O(D). For adversarial / malformed files a sort-based
|
|
+ * approach is used: build a uint16_t seen-set via qsort + bsearch. */
|
|
+ /* Simple O(D log D) implementation using a sorted seen array: */
|
|
+ uint16_t *seen = (uint16_t *)_TIFFmallocExt(
|
|
+ tif, (tmsize_t)(dircount * sizeof(uint16_t)));
|
|
+ if (seen != NULL)
|
|
{
|
|
- TIFFDirEntry *na;
|
|
- uint16_t nb;
|
|
- for (na = ma + 1, nb = mb + 1; nb < dircount; na++, nb++)
|
|
+ uint16_t seen_count = 0;
|
|
+ TIFFDirEntry *dp2;
|
|
+ uint16_t di2;
|
|
+ for (dp2 = dir, di2 = 0; di2 < dircount; dp2++, di2++)
|
|
{
|
|
- if (ma->tdir_tag == na->tdir_tag)
|
|
+ uint16_t tag = dp2->tdir_tag;
|
|
+ /* Binary search in seen[] (sorted). */
|
|
+ int lo = 0, hi = (int)seen_count - 1, found = 0;
|
|
+ while (lo <= hi)
|
|
{
|
|
- na->tdir_ignore = TRUE;
|
|
+ int mid = (lo + hi) / 2;
|
|
+ if (seen[mid] == tag) { found = 1; break; }
|
|
+ else if (seen[mid] < tag) lo = mid + 1;
|
|
+ else hi = mid - 1;
|
|
+ }
|
|
+ if (found)
|
|
+ {
|
|
+ dp2->tdir_ignore = TRUE;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /* Insert tag into sorted seen[] (insertion sort step). */
|
|
+ int pos = lo; /* insertion point */
|
|
+ int k;
|
|
+ for (k = (int)seen_count; k > pos; k--)
|
|
+ seen[k] = seen[k - 1];
|
|
+ seen[pos] = tag;
|
|
+ seen_count++;
|
|
}
|
|
}
|
|
+ _TIFFfreeExt(tif, seen);
|
|
}
|
|
+ else
|
|
+ {
|
|
+ /* Fallback to O(D^2) if allocation fails (rare, small dircount). */
|
|
+ TIFFDirEntry *ma;
|
|
+ uint16_t mb;
|
|
+ for (ma = dir, mb = 0; mb < dircount; ma++, mb++)
|
|
+ {
|
|
+ TIFFDirEntry *na;
|
|
+ uint16_t nb;
|
|
+ for (na = ma + 1, nb = mb + 1; nb < dircount; na++, nb++)
|
|
+ if (ma->tdir_tag == na->tdir_tag)
|
|
+ na->tdir_ignore = TRUE;
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
@@ -5394,18 +5397,44 @@
|
|
/*
|
|
* Mark duplicates of any tag to be ignored (bugzilla 1994)
|
|
* to avoid certain pathological problems.
|
|
+ * Fixed: same O(D^2) -> O(D log D) fix as in TIFFReadDirectory above.
|
|
*/
|
|
{
|
|
- TIFFDirEntry *ma;
|
|
- uint16_t mb;
|
|
- for (ma = dir, mb = 0; mb < dircount; ma++, mb++)
|
|
+ uint16_t *seen = (uint16_t *)_TIFFmallocExt(
|
|
+ tif, (tmsize_t)(dircount * sizeof(uint16_t)));
|
|
+ if (seen != NULL)
|
|
{
|
|
- TIFFDirEntry *na;
|
|
- uint16_t nb;
|
|
- for (na = ma + 1, nb = mb + 1; nb < dircount; na++, nb++)
|
|
+ uint16_t seen_count = 0;
|
|
+ TIFFDirEntry *dp2;
|
|
+ uint16_t di2;
|
|
+ for (dp2 = dir, di2 = 0; di2 < dircount; dp2++, di2++)
|
|
{
|
|
- if (ma->tdir_tag == na->tdir_tag)
|
|
+ uint16_t tag = dp2->tdir_tag;
|
|
+ int lo = 0, hi = (int)seen_count - 1, found = 0;
|
|
+ while (lo <= hi)
|
|
+ {
|
|
+ int mid = (lo + hi) / 2;
|
|
+ if (seen[mid] == tag) { found = 1; break; }
|
|
+ else if (seen[mid] < tag) lo = mid + 1;
|
|
+ else hi = mid - 1;
|
|
+ }
|
|
+ if (found)
|
|
{
|
|
- na->tdir_ignore = TRUE;
|
|
+ dp2->tdir_ignore = TRUE;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ int pos = lo;
|
|
+ int k;
|
|
+ for (k = (int)seen_count; k > pos; k--)
|
|
+ seen[k] = seen[k - 1];
|
|
+ seen[pos] = tag;
|
|
+ seen_count++;
|
|
}
|
|
}
|
|
+ _TIFFfreeExt(tif, seen);
|
|
}
|
|
+ else
|
|
+ {
|
|
+ TIFFDirEntry *ma;
|
|
+ uint16_t mb;
|
|
+ for (ma = dir, mb = 0; mb < dircount; ma++, mb++)
|
|
+ {
|
|
+ TIFFDirEntry *na;
|
|
+ uint16_t nb;
|
|
+ for (na = ma + 1, nb = mb + 1; nb < dircount; na++, nb++)
|
|
+ if (ma->tdir_tag == na->tdir_tag)
|
|
+ na->tdir_ignore = TRUE;
|
|
+ }
|
|
+ }
|
|
}
|