diff options
| author | Hitendra Prajapati <hprajapati@mvista.com> | 2023-10-03 18:00:56 +0530 |
|---|---|---|
| committer | Steve Sakoman <steve@sakoman.com> | 2023-10-18 05:13:24 -1000 |
| commit | de59761cbb0ce740736a381fc579530bb767704c (patch) | |
| tree | 1eeb3db4c5261fec2741c47f92bf09f4cfe2f969 | |
| parent | 3a3afebf41077e097150bc33f3e292eed929ba11 (diff) | |
| download | poky-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.patch | 569 | ||||
| -rw-r--r-- | meta/recipes-multimedia/libtiff/tiff_4.3.0.bb | 1 |
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 @@ | |||
| 1 | From c7caec9a4d8f24c17e667480d2c7d0d51c9fae41 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Su Laus <sulau@freenet.de> | ||
| 3 | Date: Thu, 6 Oct 2022 10:11:05 +0000 | ||
| 4 | Subject: [PATCH] Improved IFD-Loop Handling (fixes #455) | ||
| 5 | |||
| 6 | IFD infinite looping was not fixed by MR 20 (see #455). | ||
| 7 | An improved IFD loop handling is proposed. | ||
| 8 | |||
| 9 | Basic 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 | |||
| 17 | Rules 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 | |||
| 23 | Reference is also made to old bugzilla bug 2772 and MR 20, which did not solve the general issue. | ||
| 24 | This MR closes #455 | ||
| 25 | |||
| 26 | Upstream-Status: Backport [https://gitlab.com/libtiff/libtiff/-/commit/c7caec9a4d8f24c17e667480d2c7d0d51c9fae41] | ||
| 27 | CVE: CVE-2022-40090 | ||
| 28 | Signed-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 | |||
| 38 | diff --git a/libtiff/tif_close.c b/libtiff/tif_close.c | ||
| 39 | index 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. | ||
| 55 | diff --git a/libtiff/tif_dir.c b/libtiff/tif_dir.c | ||
| 56 | index 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 | ||
| 324 | diff --git a/libtiff/tif_dir.h b/libtiff/tif_dir.h | ||
| 325 | index 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 | } | ||
| 337 | diff --git a/libtiff/tif_dirread.c b/libtiff/tif_dirread.c | ||
| 338 | index 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 | ||
| 539 | diff --git a/libtiff/tif_open.c b/libtiff/tif_open.c | ||
| 540 | index 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); | ||
| 553 | diff --git a/libtiff/tiffiop.h b/libtiff/tiffiop.h | ||
| 554 | index 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 | -- | ||
| 568 | 2.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 | ||
| 48 | SRC_URI[sha256sum] = "0e46e5acb087ce7d1ac53cf4f56a09b221537fc86dfc5daaad1c2e89e1b37ac8" | 49 | SRC_URI[sha256sum] = "0e46e5acb087ce7d1ac53cf4f56a09b221537fc86dfc5daaad1c2e89e1b37ac8" |
