summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHitendra Prajapati <hprajapati@mvista.com>2023-10-03 18:00:56 +0530
committerSteve Sakoman <steve@sakoman.com>2023-10-18 05:13:24 -1000
commitde59761cbb0ce740736a381fc579530bb767704c (patch)
tree1eeb3db4c5261fec2741c47f92bf09f4cfe2f969
parent3a3afebf41077e097150bc33f3e292eed929ba11 (diff)
downloadpoky-de59761cbb0ce740736a381fc579530bb767704c.tar.gz
libtiff: fix CVE-2022-40090 improved IFD-Loop handling
Upstream-Status: Backport from https://gitlab.com/libtiff/libtiff/-/commit/c7caec9a4d8f24c17e667480d2c7d0d51c9fae41 (From OE-Core rev: 1effa609b5b527eb9afa5a2c529bdc0b317e4be0) Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> Signed-off-by: Steve Sakoman <steve@sakoman.com>
-rw-r--r--meta/recipes-multimedia/libtiff/tiff/CVE-2022-40090.patch569
-rw-r--r--meta/recipes-multimedia/libtiff/tiff_4.3.0.bb1
2 files changed, 570 insertions, 0 deletions
diff --git a/meta/recipes-multimedia/libtiff/tiff/CVE-2022-40090.patch b/meta/recipes-multimedia/libtiff/tiff/CVE-2022-40090.patch
new file mode 100644
index 0000000000..fe48dc6028
--- /dev/null
+++ b/meta/recipes-multimedia/libtiff/tiff/CVE-2022-40090.patch
@@ -0,0 +1,569 @@
1From c7caec9a4d8f24c17e667480d2c7d0d51c9fae41 Mon Sep 17 00:00:00 2001
2From: Su Laus <sulau@freenet.de>
3Date: Thu, 6 Oct 2022 10:11:05 +0000
4Subject: [PATCH] Improved IFD-Loop Handling (fixes #455)
5
6IFD infinite looping was not fixed by MR 20 (see #455).
7An improved IFD loop handling is proposed.
8
9Basic approach:
10
11- The order in the entire chain must be checked, and not only whether an offset has already been read once.
12- To do this, pairs of directory number and offset are stored and checked.
13- The offset of a directory number can change.
14- TIFFAdvanceDirectory() must also perform an IFD loop check.
15- TIFFCheckDirOffset() is replaced by _TIFFCheckDirNumberAndOffset().
16
17Rules for the check:
18
19- If an offset is already in the list, it must have the same IFD number. Otherwise it is an IDF loop.
20- If the offset is not in the list and the IFD number is greater than there are list entries, a new list entry is added.
21- Otherwise, the offset of the IFD number is updated.
22
23Reference is also made to old bugzilla bug 2772 and MR 20, which did not solve the general issue.
24This MR closes #455
25
26Upstream-Status: Backport [https://gitlab.com/libtiff/libtiff/-/commit/c7caec9a4d8f24c17e667480d2c7d0d51c9fae41]
27CVE: CVE-2022-40090
28Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
29---
30 libtiff/tif_close.c | 6 +-
31 libtiff/tif_dir.c | 129 +++++++++++++++++++++++++-----------
32 libtiff/tif_dir.h | 2 +
33 libtiff/tif_dirread.c | 147 +++++++++++++++++++++++++++++++++---------
34 libtiff/tif_open.c | 3 +-
35 libtiff/tiffiop.h | 3 +-
36 6 files changed, 219 insertions(+), 71 deletions(-)
37
38diff --git a/libtiff/tif_close.c b/libtiff/tif_close.c
39index 0fe7af4..2fe2bde 100644
40--- a/libtiff/tif_close.c
41+++ b/libtiff/tif_close.c
42@@ -52,8 +52,10 @@ TIFFCleanup(TIFF* tif)
43 (*tif->tif_cleanup)(tif);
44 TIFFFreeDirectory(tif);
45
46- if (tif->tif_dirlist)
47- _TIFFfree(tif->tif_dirlist);
48+ if (tif->tif_dirlistoff)
49+ _TIFFfree(tif->tif_dirlistoff);
50+ if (tif->tif_dirlistdirn)
51+ _TIFFfree(tif->tif_dirlistdirn);
52
53 /*
54 * Clean up client info links.
55diff --git a/libtiff/tif_dir.c b/libtiff/tif_dir.c
56index 1402c8e..6d4bf58 100644
57--- a/libtiff/tif_dir.c
58+++ b/libtiff/tif_dir.c
59@@ -1511,12 +1511,22 @@ TIFFDefaultDirectory(TIFF* tif)
60 }
61
62 static int
63-TIFFAdvanceDirectory(TIFF* tif, uint64_t* nextdir, uint64_t* off)
64+TIFFAdvanceDirectory(TIFF* tif, uint64_t* nextdiroff, uint64_t* off, uint16_t* nextdirnum)
65 {
66 static const char module[] = "TIFFAdvanceDirectory";
67+
68+ /* Add this directory to the directory list, if not already in. */
69+ if (!_TIFFCheckDirNumberAndOffset(tif, *nextdirnum, *nextdiroff)) {
70+ TIFFErrorExt(tif->tif_clientdata, module, "Starting directory %"PRIu16" at offset 0x%"PRIx64" (%"PRIu64") might cause an IFD loop",
71+ *nextdirnum, *nextdiroff, *nextdiroff);
72+ *nextdiroff = 0;
73+ *nextdirnum = 0;
74+ return(0);
75+ }
76+
77 if (isMapped(tif))
78 {
79- uint64_t poff=*nextdir;
80+ uint64_t poff=*nextdiroff;
81 if (!(tif->tif_flags&TIFF_BIGTIFF))
82 {
83 tmsize_t poffa,poffb,poffc,poffd;
84@@ -1527,7 +1537,7 @@ TIFFAdvanceDirectory(TIFF* tif, uint64_t* nextdir, uint64_t* off)
85 if (((uint64_t)poffa != poff) || (poffb < poffa) || (poffb < (tmsize_t)sizeof(uint16_t)) || (poffb > tif->tif_size))
86 {
87 TIFFErrorExt(tif->tif_clientdata,module,"Error fetching directory count");
88- *nextdir=0;
89+ *nextdiroff=0;
90 return(0);
91 }
92 _TIFFmemcpy(&dircount,tif->tif_base+poffa,sizeof(uint16_t));
93@@ -1545,7 +1555,7 @@ TIFFAdvanceDirectory(TIFF* tif, uint64_t* nextdir, uint64_t* off)
94 _TIFFmemcpy(&nextdir32,tif->tif_base+poffc,sizeof(uint32_t));
95 if (tif->tif_flags&TIFF_SWAB)
96 TIFFSwabLong(&nextdir32);
97- *nextdir=nextdir32;
98+ *nextdiroff=nextdir32;
99 }
100 else
101 {
102@@ -1577,11 +1587,10 @@ TIFFAdvanceDirectory(TIFF* tif, uint64_t* nextdir, uint64_t* off)
103 }
104 if (off!=NULL)
105 *off=(uint64_t)poffc;
106- _TIFFmemcpy(nextdir,tif->tif_base+poffc,sizeof(uint64_t));
107+ _TIFFmemcpy(nextdiroff,tif->tif_base+poffc,sizeof(uint64_t));
108 if (tif->tif_flags&TIFF_SWAB)
109- TIFFSwabLong8(nextdir);
110+ TIFFSwabLong8(nextdiroff);
111 }
112- return(1);
113 }
114 else
115 {
116@@ -1589,7 +1598,7 @@ TIFFAdvanceDirectory(TIFF* tif, uint64_t* nextdir, uint64_t* off)
117 {
118 uint16_t dircount;
119 uint32_t nextdir32;
120- if (!SeekOK(tif, *nextdir) ||
121+ if (!SeekOK(tif, *nextdiroff) ||
122 !ReadOK(tif, &dircount, sizeof (uint16_t))) {
123 TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory count",
124 tif->tif_name);
125@@ -1610,13 +1619,13 @@ TIFFAdvanceDirectory(TIFF* tif, uint64_t* nextdir, uint64_t* off)
126 }
127 if (tif->tif_flags & TIFF_SWAB)
128 TIFFSwabLong(&nextdir32);
129- *nextdir=nextdir32;
130+ *nextdiroff=nextdir32;
131 }
132 else
133 {
134 uint64_t dircount64;
135 uint16_t dircount16;
136- if (!SeekOK(tif, *nextdir) ||
137+ if (!SeekOK(tif, *nextdiroff) ||
138 !ReadOK(tif, &dircount64, sizeof (uint64_t))) {
139 TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory count",
140 tif->tif_name);
141@@ -1636,17 +1645,27 @@ TIFFAdvanceDirectory(TIFF* tif, uint64_t* nextdir, uint64_t* off)
142 else
143 (void) TIFFSeekFile(tif,
144 dircount16*20, SEEK_CUR);
145- if (!ReadOK(tif, nextdir, sizeof (uint64_t))) {
146+ if (!ReadOK(tif, nextdiroff, sizeof (uint64_t))) {
147 TIFFErrorExt(tif->tif_clientdata, module,
148 "%s: Error fetching directory link",
149 tif->tif_name);
150 return (0);
151 }
152 if (tif->tif_flags & TIFF_SWAB)
153- TIFFSwabLong8(nextdir);
154+ TIFFSwabLong8(nextdiroff);
155 }
156- return (1);
157 }
158+ if (*nextdiroff != 0) {
159+ (*nextdirnum)++;
160+ /* Check next directory for IFD looping and if so, set it as last directory. */
161+ if (!_TIFFCheckDirNumberAndOffset(tif, *nextdirnum, *nextdiroff)) {
162+ TIFFWarningExt(tif->tif_clientdata, module, "the next directory %"PRIu16" at offset 0x%"PRIx64" (%"PRIu64") might be an IFD loop. Treating directory %"PRIu16" as last directory",
163+ *nextdirnum, *nextdiroff, *nextdiroff, *nextdirnum-1);
164+ *nextdiroff = 0;
165+ (*nextdirnum)--;
166+ }
167+ }
168+ return (1);
169 }
170
171 /*
172@@ -1656,14 +1675,16 @@ uint16_t
173 TIFFNumberOfDirectories(TIFF* tif)
174 {
175 static const char module[] = "TIFFNumberOfDirectories";
176- uint64_t nextdir;
177+ uint64_t nextdiroff;
178+ uint16_t nextdirnum;
179 uint16_t n;
180 if (!(tif->tif_flags&TIFF_BIGTIFF))
181- nextdir = tif->tif_header.classic.tiff_diroff;
182+ nextdiroff = tif->tif_header.classic.tiff_diroff;
183 else
184- nextdir = tif->tif_header.big.tiff_diroff;
185+ nextdiroff = tif->tif_header.big.tiff_diroff;
186+ nextdirnum = 0;
187 n = 0;
188- while (nextdir != 0 && TIFFAdvanceDirectory(tif, &nextdir, NULL))
189+ while (nextdiroff != 0 && TIFFAdvanceDirectory(tif, &nextdiroff, NULL, &nextdirnum))
190 {
191 if (n != 65535) {
192 ++n;
193@@ -1686,28 +1707,30 @@ TIFFNumberOfDirectories(TIFF* tif)
194 int
195 TIFFSetDirectory(TIFF* tif, uint16_t dirn)
196 {
197- uint64_t nextdir;
198+ uint64_t nextdiroff;
199+ uint16_t nextdirnum;
200 uint16_t n;
201
202 if (!(tif->tif_flags&TIFF_BIGTIFF))
203- nextdir = tif->tif_header.classic.tiff_diroff;
204+ nextdiroff = tif->tif_header.classic.tiff_diroff;
205 else
206- nextdir = tif->tif_header.big.tiff_diroff;
207- for (n = dirn; n > 0 && nextdir != 0; n--)
208- if (!TIFFAdvanceDirectory(tif, &nextdir, NULL))
209+ nextdiroff = tif->tif_header.big.tiff_diroff;
210+ nextdirnum = 0;
211+ for (n = dirn; n > 0 && nextdiroff != 0; n--)
212+ if (!TIFFAdvanceDirectory(tif, &nextdiroff, NULL, &nextdirnum))
213 return (0);
214- tif->tif_nextdiroff = nextdir;
215+ /* If the n-th directory could not be reached (does not exist),
216+ * return here without touching anything further. */
217+ if (nextdiroff == 0 || n > 0)
218+ return (0);
219+
220+ tif->tif_nextdiroff = nextdiroff;
221 /*
222 * Set curdir to the actual directory index. The
223 * -1 is because TIFFReadDirectory will increment
224 * tif_curdir after successfully reading the directory.
225 */
226 tif->tif_curdir = (dirn - n) - 1;
227- /*
228- * Reset tif_dirnumber counter and start new list of seen directories.
229- * We need this to prevent IFD loops.
230- */
231- tif->tif_dirnumber = 0;
232 return (TIFFReadDirectory(tif));
233 }
234
235@@ -1720,13 +1743,42 @@ TIFFSetDirectory(TIFF* tif, uint16_t dirn)
236 int
237 TIFFSetSubDirectory(TIFF* tif, uint64_t diroff)
238 {
239- tif->tif_nextdiroff = diroff;
240- /*
241- * Reset tif_dirnumber counter and start new list of seen directories.
242- * We need this to prevent IFD loops.
243+ /* Match nextdiroff and curdir for consistent IFD-loop checking.
244+ * Only with TIFFSetSubDirectory() the IFD list can be corrupted with invalid offsets
245+ * within the main IFD tree.
246+ * In the case of several subIFDs of a main image,
247+ * there are two possibilities that are not even mutually exclusive.
248+ * a.) The subIFD tag contains an array with all offsets of the subIFDs.
249+ * b.) The SubIFDs are concatenated with their NextIFD parameters.
250+ * (refer to https://www.awaresystems.be/imaging/tiff/specification/TIFFPM6.pdf.)
251 */
252- tif->tif_dirnumber = 0;
253- return (TIFFReadDirectory(tif));
254+ int retval;
255+ uint16_t curdir = 0;
256+ int8_t probablySubIFD = 0;
257+ if (diroff == 0) {
258+ /* Special case to invalidate the tif_lastdiroff member. */
259+ tif->tif_curdir = 65535;
260+ } else {
261+ if (!_TIFFGetDirNumberFromOffset(tif, diroff, &curdir)) {
262+ /* Non-existing offsets might point to a SubIFD or invalid IFD.*/
263+ probablySubIFD = 1;
264+ }
265+ /* -1 because TIFFReadDirectory() will increment tif_curdir. */
266+ tif->tif_curdir = curdir - 1;
267+ }
268+
269+ tif->tif_nextdiroff = diroff;
270+ retval = TIFFReadDirectory(tif);
271+ /* If failed, curdir was not incremented in TIFFReadDirectory(), so set it back. */
272+ if (!retval )tif->tif_curdir++;
273+ if (retval && probablySubIFD) {
274+ /* Reset IFD list to start new one for SubIFD chain and also start SubIFD chain with tif_curdir=0. */
275+ tif->tif_dirnumber = 0;
276+ tif->tif_curdir = 0; /* first directory of new chain */
277+ /* add this offset to new IFD list */
278+ _TIFFCheckDirNumberAndOffset(tif, tif->tif_curdir, diroff);
279+ }
280+ return (retval);
281 }
282
283 /*
284@@ -1750,12 +1802,15 @@ TIFFLastDirectory(TIFF* tif)
285
286 /*
287 * Unlink the specified directory from the directory chain.
288+ * Note: First directory starts with number dirn=1.
289+ * This is different to TIFFSetDirectory() where the first directory starts with zero.
290 */
291 int
292 TIFFUnlinkDirectory(TIFF* tif, uint16_t dirn)
293 {
294 static const char module[] = "TIFFUnlinkDirectory";
295 uint64_t nextdir;
296+ uint16_t nextdirnum;
297 uint64_t off;
298 uint16_t n;
299
300@@ -1779,19 +1834,21 @@ TIFFUnlinkDirectory(TIFF* tif, uint16_t dirn)
301 nextdir = tif->tif_header.big.tiff_diroff;
302 off = 8;
303 }
304+ nextdirnum = 0; /* First directory is dirn=0 */
305+
306 for (n = dirn-1; n > 0; n--) {
307 if (nextdir == 0) {
308 TIFFErrorExt(tif->tif_clientdata, module, "Directory %"PRIu16" does not exist", dirn);
309 return (0);
310 }
311- if (!TIFFAdvanceDirectory(tif, &nextdir, &off))
312+ if (!TIFFAdvanceDirectory(tif, &nextdir, &off, &nextdirnum))
313 return (0);
314 }
315 /*
316 * Advance to the directory to be unlinked and fetch
317 * the offset of the directory that follows.
318 */
319- if (!TIFFAdvanceDirectory(tif, &nextdir, NULL))
320+ if (!TIFFAdvanceDirectory(tif, &nextdir, NULL, &nextdirnum))
321 return (0);
322 /*
323 * Go back and patch the link field of the preceding
324diff --git a/libtiff/tif_dir.h b/libtiff/tif_dir.h
325index 900dec1..f1a5125 100644
326--- a/libtiff/tif_dir.h
327+++ b/libtiff/tif_dir.h
328@@ -302,6 +302,8 @@ extern int _TIFFMergeFields(TIFF*, const TIFFField[], uint32_t);
329 extern const TIFFField* _TIFFFindOrRegisterField(TIFF *, uint32_t, TIFFDataType);
330 extern TIFFField* _TIFFCreateAnonField(TIFF *, uint32_t, TIFFDataType);
331 extern int _TIFFCheckFieldIsValidForCodec(TIFF *tif, ttag_t tag);
332+extern int _TIFFCheckDirNumberAndOffset(TIFF *tif, uint16_t dirn, uint64_t diroff);
333+extern int _TIFFGetDirNumberFromOffset(TIFF *tif, uint64_t diroff, uint16_t *dirn);
334
335 #if defined(__cplusplus)
336 }
337diff --git a/libtiff/tif_dirread.c b/libtiff/tif_dirread.c
338index d7cccbe..f07de60 100644
339--- a/libtiff/tif_dirread.c
340+++ b/libtiff/tif_dirread.c
341@@ -154,7 +154,6 @@ static void TIFFReadDirectoryFindFieldInfo(TIFF* tif, uint16_t tagid, uint32_t*
342
343 static int EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16_t dircount);
344 static void MissingRequired(TIFF*, const char*);
345-static int TIFFCheckDirOffset(TIFF* tif, uint64_t diroff);
346 static int CheckDirCount(TIFF*, TIFFDirEntry*, uint32_t);
347 static uint16_t TIFFFetchDirectory(TIFF* tif, uint64_t diroff, TIFFDirEntry** pdir, uint64_t* nextdiroff);
348 static int TIFFFetchNormalTag(TIFF*, TIFFDirEntry*, int recover);
349@@ -3590,12 +3589,19 @@ TIFFReadDirectory(TIFF* tif)
350 int bitspersample_read = FALSE;
351 int color_channels;
352
353- tif->tif_diroff=tif->tif_nextdiroff;
354- if (!TIFFCheckDirOffset(tif,tif->tif_nextdiroff))
355- return 0; /* last offset or bad offset (IFD looping) */
356- (*tif->tif_cleanup)(tif); /* cleanup any previous compression state */
357- tif->tif_curdir++;
358- nextdiroff = tif->tif_nextdiroff;
359+ if (tif->tif_nextdiroff == 0) {
360+ /* In this special case, tif_diroff needs also to be set to 0. */
361+ tif->tif_diroff = tif->tif_nextdiroff;
362+ return 0; /* last offset, thus no checking necessary */
363+ }
364+
365+ nextdiroff = tif->tif_nextdiroff;
366+ /* tif_curdir++ and tif_nextdiroff should only be updated after SUCCESSFUL reading of the directory. Otherwise, invalid IFD offsets could corrupt the IFD list. */
367+ if (!_TIFFCheckDirNumberAndOffset(tif, tif->tif_curdir + 1, nextdiroff)) {
368+ TIFFWarningExt(tif->tif_clientdata, module,
369+ "Didn't read next directory due to IFD looping at offset 0x%"PRIx64" (%"PRIu64") to offset 0x%"PRIx64" (%"PRIu64")", tif->tif_diroff, tif->tif_diroff, nextdiroff, nextdiroff);
370+ return 0; /* bad offset (IFD looping) */
371+ }
372 dircount=TIFFFetchDirectory(tif,nextdiroff,&dir,&tif->tif_nextdiroff);
373 if (!dircount)
374 {
375@@ -3603,6 +3609,11 @@ TIFFReadDirectory(TIFF* tif)
376 "Failed to read directory at offset %" PRIu64, nextdiroff);
377 return 0;
378 }
379+ /* Set global values after a valid directory has been fetched.
380+ * tif_diroff is already set to nextdiroff in TIFFFetchDirectory() in the beginning. */
381+ tif->tif_curdir++;
382+ (*tif->tif_cleanup)(tif); /* cleanup any previous compression state */
383+
384 TIFFReadDirectoryCheckOrder(tif,dir,dircount);
385
386 /*
387@@ -4687,53 +4698,127 @@ MissingRequired(TIFF* tif, const char* tagname)
388 }
389
390 /*
391- * Check the directory offset against the list of already seen directory
392- * offsets. This is a trick to prevent IFD looping. The one can create TIFF
393- * file with looped directory pointers. We will maintain a list of already
394- * seen directories and check every IFD offset against that list.
395+ * Check the directory number and offset against the list of already seen
396+ * directory numbers and offsets. This is a trick to prevent IFD looping.
397+ * The one can create TIFF file with looped directory pointers. We will
398+ * maintain a list of already seen directories and check every IFD offset
399+ * and its IFD number against that list. However, the offset of an IFD number
400+ * can change - e.g. when writing updates to file.
401+ * Returns 1 if all is ok; 0 if last directory or IFD loop is encountered,
402+ * or an error has occured.
403 */
404-static int
405-TIFFCheckDirOffset(TIFF* tif, uint64_t diroff)
406+int
407+_TIFFCheckDirNumberAndOffset(TIFF *tif, uint16_t dirn, uint64_t diroff)
408 {
409 uint16_t n;
410
411 if (diroff == 0) /* no more directories */
412 return 0;
413 if (tif->tif_dirnumber == 65535) {
414- TIFFErrorExt(tif->tif_clientdata, "TIFFCheckDirOffset",
415- "Cannot handle more than 65535 TIFF directories");
416- return 0;
417+ TIFFErrorExt(tif->tif_clientdata, "_TIFFCheckDirNumberAndOffset",
418+ "Cannot handle more than 65535 TIFF directories");
419+ return 0;
420 }
421
422- for (n = 0; n < tif->tif_dirnumber && tif->tif_dirlist; n++) {
423- if (tif->tif_dirlist[n] == diroff)
424- return 0;
425+ /* Check if offset is already in the list:
426+ * - yes: check, if offset is at the same IFD number - if not, it is an IFD loop
427+ * - no: add to list or update offset at that IFD number
428+ */
429+ for (n = 0; n < tif->tif_dirnumber && tif->tif_dirlistdirn && tif->tif_dirlistoff; n++) {
430+ if (tif->tif_dirlistoff[n] == diroff) {
431+ if (tif->tif_dirlistdirn[n] == dirn) {
432+ return 1;
433+ } else {
434+ TIFFWarningExt(tif->tif_clientdata, "_TIFFCheckDirNumberAndOffset",
435+ "TIFF directory %"PRIu16" has IFD looping to directory %"PRIu16" at offset 0x%"PRIx64" (%"PRIu64")",
436+ dirn-1, tif->tif_dirlistdirn[n], diroff, diroff);
437+ return 0;
438+ }
439+ }
440+ }
441+ /* Check if offset of an IFD has been changed and update offset of that IFD number. */
442+ if (dirn < tif->tif_dirnumber && tif->tif_dirlistdirn && tif->tif_dirlistoff) {
443+ /* tif_dirlistdirn can have IFD numbers dirn in random order */
444+ for (n = 0; n < tif->tif_dirnumber; n++) {
445+ if (tif->tif_dirlistdirn[n] == dirn) {
446+ tif->tif_dirlistoff[n] = diroff;
447+ return 1;
448+ }
449+ }
450 }
451
452+ /* Add IFD offset and dirn to IFD directory list */
453 tif->tif_dirnumber++;
454
455- if (tif->tif_dirlist == NULL || tif->tif_dirnumber > tif->tif_dirlistsize) {
456- uint64_t* new_dirlist;
457-
458+ if (tif->tif_dirlistoff == NULL || tif->tif_dirlistdirn == NULL || tif->tif_dirnumber > tif->tif_dirlistsize) {
459+ uint64_t *new_dirlist;
460 /*
461 * XXX: Reduce memory allocation granularity of the dirlist
462 * array.
463 */
464- new_dirlist = (uint64_t*)_TIFFCheckRealloc(tif, tif->tif_dirlist,
465- tif->tif_dirnumber, 2 * sizeof(uint64_t), "for IFD list");
466+ if (tif->tif_dirnumber >= 32768)
467+ tif->tif_dirlistsize = 65535;
468+ else
469+ tif->tif_dirlistsize = 2 * tif->tif_dirnumber;
470+
471+ new_dirlist = (uint64_t *)_TIFFCheckRealloc(tif, tif->tif_dirlistoff,
472+ tif->tif_dirlistsize, sizeof(uint64_t), "for IFD offset list");
473 if (!new_dirlist)
474 return 0;
475- if( tif->tif_dirnumber >= 32768 )
476- tif->tif_dirlistsize = 65535;
477- else
478- tif->tif_dirlistsize = 2 * tif->tif_dirnumber;
479- tif->tif_dirlist = new_dirlist;
480+ tif->tif_dirlistoff = new_dirlist;
481+ new_dirlist = (uint64_t *)_TIFFCheckRealloc(tif, tif->tif_dirlistdirn,
482+ tif->tif_dirlistsize, sizeof(uint16_t), "for IFD dirnumber list");
483+ if (!new_dirlist)
484+ return 0;
485+ tif->tif_dirlistdirn = (uint16_t *)new_dirlist;
486 }
487
488- tif->tif_dirlist[tif->tif_dirnumber - 1] = diroff;
489+ tif->tif_dirlistoff[tif->tif_dirnumber - 1] = diroff;
490+ tif->tif_dirlistdirn[tif->tif_dirnumber - 1] = dirn;
491
492 return 1;
493-}
494+} /* --- _TIFFCheckDirNumberAndOffset() ---*/
495+
496+/*
497+ * Retrieve the matching IFD directory number of a given IFD offset
498+ * from the list of directories already seen.
499+ * Returns 1 if the offset was in the list and the directory number
500+ * can be returned.
501+ * Otherwise returns 0 or if an error occured.
502+ */
503+int
504+_TIFFGetDirNumberFromOffset(TIFF *tif, uint64_t diroff, uint16_t* dirn)
505+{
506+ uint16_t n;
507+
508+ if (diroff == 0) /* no more directories */
509+ return 0;
510+ if (tif->tif_dirnumber == 65535) {
511+ TIFFErrorExt(tif->tif_clientdata, "_TIFFGetDirNumberFromOffset",
512+ "Cannot handle more than 65535 TIFF directories");
513+ return 0;
514+ }
515+
516+ /* Check if offset is already in the list and return matching directory number.
517+ * Otherwise update IFD list using TIFFNumberOfDirectories()
518+ * and search again in IFD list.
519+ */
520+ for (n = 0; n < tif->tif_dirnumber && tif->tif_dirlistoff && tif->tif_dirlistdirn; n++) {
521+ if (tif->tif_dirlistoff[n] == diroff) {
522+ *dirn = tif->tif_dirlistdirn[n];
523+ return 1;
524+ }
525+ }
526+ TIFFNumberOfDirectories(tif);
527+ for (n = 0; n < tif->tif_dirnumber && tif->tif_dirlistoff && tif->tif_dirlistdirn; n++) {
528+ if (tif->tif_dirlistoff[n] == diroff) {
529+ *dirn = tif->tif_dirlistdirn[n];
530+ return 1;
531+ }
532+ }
533+ return 0;
534+} /*--- _TIFFGetDirNumberFromOffset() ---*/
535+
536
537 /*
538 * Check the count field of a directory entry against a known value. The
539diff --git a/libtiff/tif_open.c b/libtiff/tif_open.c
540index 9724162..f047c73 100644
541--- a/libtiff/tif_open.c
542+++ b/libtiff/tif_open.c
543@@ -354,7 +354,8 @@ TIFFClientOpen(
544 if (!TIFFDefaultDirectory(tif))
545 goto bad;
546 tif->tif_diroff = 0;
547- tif->tif_dirlist = NULL;
548+ tif->tif_dirlistoff = NULL;
549+ tif->tif_dirlistdirn = NULL;
550 tif->tif_dirlistsize = 0;
551 tif->tif_dirnumber = 0;
552 return (tif);
553diff --git a/libtiff/tiffiop.h b/libtiff/tiffiop.h
554index c1d0276..9459fe8 100644
555--- a/libtiff/tiffiop.h
556+++ b/libtiff/tiffiop.h
557@@ -117,7 +117,8 @@ struct tiff {
558 #define TIFF_CHOPPEDUPARRAYS 0x4000000U /* set when allocChoppedUpStripArrays() has modified strip array */
559 uint64_t tif_diroff; /* file offset of current directory */
560 uint64_t tif_nextdiroff; /* file offset of following directory */
561- uint64_t* tif_dirlist; /* list of offsets to already seen directories to prevent IFD looping */
562+ uint64_t* tif_dirlistoff; /* list of offsets to already seen directories to prevent IFD looping */
563+ uint16_t* tif_dirlistdirn; /* list of directory numbers to already seen directories to prevent IFD looping */
564 uint16_t tif_dirlistsize; /* number of entries in offset list */
565 uint16_t tif_dirnumber; /* number of already seen directories */
566 TIFFDirectory tif_dir; /* internal rep of current directory */
567--
5682.25.1
569
diff --git a/meta/recipes-multimedia/libtiff/tiff_4.3.0.bb b/meta/recipes-multimedia/libtiff/tiff_4.3.0.bb
index 61d8142e41..9e1e6fa099 100644
--- a/meta/recipes-multimedia/libtiff/tiff_4.3.0.bb
+++ b/meta/recipes-multimedia/libtiff/tiff_4.3.0.bb
@@ -43,6 +43,7 @@ SRC_URI = "http://download.osgeo.org/libtiff/tiff-${PV}.tar.gz \
43 file://CVE-2023-3618-1.patch \ 43 file://CVE-2023-3618-1.patch \
44 file://CVE-2023-3618-2.patch \ 44 file://CVE-2023-3618-2.patch \
45 file://CVE-2023-26966.patch \ 45 file://CVE-2023-26966.patch \
46 file://CVE-2022-40090.patch \
46 " 47 "
47 48
48SRC_URI[sha256sum] = "0e46e5acb087ce7d1ac53cf4f56a09b221537fc86dfc5daaad1c2e89e1b37ac8" 49SRC_URI[sha256sum] = "0e46e5acb087ce7d1ac53cf4f56a09b221537fc86dfc5daaad1c2e89e1b37ac8"