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