You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

295 lines
11 KiB

  1. From 1077fad562e03d1cad591dd10163dd80ad63ab0e Mon Sep 17 00:00:00 2001
  2. From: Even Rouault <even.rouault@spatialys.com>
  3. Date: Fri, 30 Jun 2017 13:11:18 +0000
  4. Subject: [PATCH] * libtiff/tif_read.c, tiffiop.h: add a
  5. _TIFFReadEncodedStripAndAllocBuffer() function, variant of
  6. TIFFReadEncodedStrip() that allocates the decoded buffer only after a first
  7. successful TIFFFillStrip(). This avoids excessive memory allocation on
  8. corrupted files. * libtiff/tif_getimage.c: use
  9. _TIFFReadEncodedStripAndAllocBuffer(). Fixes
  10. http://bugzilla.maptools.org/show_bug.cgi?id=2708 and
  11. https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2433 . Credit to OSS
  12. Fuzz
  13. ---
  14. ChangeLog | 11 +++++++
  15. libtiff/tif_getimage.c | 59 ++++++++++++++++++++++----------------
  16. libtiff/tif_read.c | 78 +++++++++++++++++++++++++++++++++++++++++++-------
  17. libtiff/tiffiop.h | 5 ++++
  18. 4 files changed, 118 insertions(+), 35 deletions(-)
  19. diff --git a/ChangeLog b/ChangeLog
  20. index c969f9e2..6f085e09 100644
  21. --- a/ChangeLog
  22. +++ b/ChangeLog
  23. @@ -1,3 +1,14 @@
  24. +2017-06-30 Even Rouault <even.rouault at spatialys.com>
  25. +
  26. + * libtiff/tif_read.c, tiffiop.h: add a _TIFFReadEncodedStripAndAllocBuffer()
  27. + function, variant of TIFFReadEncodedStrip() that allocates the
  28. + decoded buffer only after a first successful TIFFFillStrip(). This avoids
  29. + excessive memory allocation on corrupted files.
  30. + * libtiff/tif_getimage.c: use _TIFFReadEncodedStripAndAllocBuffer().
  31. + Fixes http://bugzilla.maptools.org/show_bug.cgi?id=2708 and
  32. + https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2433 .
  33. + Credit to OSS Fuzz
  34. +
  35. 2017-06-26 Even Rouault <even.rouault at spatialys.com>
  36. * libtiff/tif_jbig.c: fix memory leak in error code path of JBIGDecode()
  37. diff --git a/libtiff/tif_getimage.c b/libtiff/tif_getimage.c
  38. index cee8e930..cc6e8f30 100644
  39. --- a/libtiff/tif_getimage.c
  40. +++ b/libtiff/tif_getimage.c
  41. @@ -905,26 +905,22 @@ gtStripContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
  42. tileContigRoutine put = img->put.contig;
  43. uint32 row, y, nrow, nrowsub, rowstoread;
  44. tmsize_t pos;
  45. - unsigned char* buf;
  46. + unsigned char* buf = NULL;
  47. uint32 rowsperstrip;
  48. uint16 subsamplinghor,subsamplingver;
  49. uint32 imagewidth = img->width;
  50. tmsize_t scanline;
  51. int32 fromskew, toskew;
  52. int ret = 1, flip;
  53. + tmsize_t maxstripsize;
  54. TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING, &subsamplinghor, &subsamplingver);
  55. if( subsamplingver == 0 ) {
  56. TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "Invalid vertical YCbCr subsampling");
  57. return (0);
  58. }
  59. -
  60. - buf = (unsigned char*) _TIFFmalloc(TIFFStripSize(tif));
  61. - if (buf == 0) {
  62. - TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for strip buffer");
  63. - return (0);
  64. - }
  65. - _TIFFmemset(buf, 0, TIFFStripSize(tif));
  66. +
  67. + maxstripsize = TIFFStripSize(tif);
  68. flip = setorientation(img);
  69. if (flip & FLIP_VERTICALLY) {
  70. @@ -946,11 +942,12 @@ gtStripContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
  71. nrowsub = nrow;
  72. if ((nrowsub%subsamplingver)!=0)
  73. nrowsub+=subsamplingver-nrowsub%subsamplingver;
  74. - if (TIFFReadEncodedStrip(tif,
  75. + if (_TIFFReadEncodedStripAndAllocBuffer(tif,
  76. TIFFComputeStrip(tif,row+img->row_offset, 0),
  77. - buf,
  78. + (void**)(&buf),
  79. + maxstripsize,
  80. ((row + img->row_offset)%rowsperstrip + nrowsub) * scanline)==(tmsize_t)(-1)
  81. - && img->stoponerr)
  82. + && (buf == NULL || img->stoponerr))
  83. {
  84. ret = 0;
  85. break;
  86. @@ -994,8 +991,8 @@ gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
  87. {
  88. TIFF* tif = img->tif;
  89. tileSeparateRoutine put = img->put.separate;
  90. - unsigned char *buf;
  91. - unsigned char *p0, *p1, *p2, *pa;
  92. + unsigned char *buf = NULL;
  93. + unsigned char *p0 = NULL, *p1 = NULL, *p2 = NULL, *pa = NULL;
  94. uint32 row, y, nrow, rowstoread;
  95. tmsize_t pos;
  96. tmsize_t scanline;
  97. @@ -1014,15 +1011,6 @@ gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
  98. TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "Integer overflow in %s", "gtStripSeparate");
  99. return (0);
  100. }
  101. - p0 = buf = (unsigned char *)_TIFFmalloc(bufsize);
  102. - if (buf == 0) {
  103. - TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer");
  104. - return (0);
  105. - }
  106. - _TIFFmemset(buf, 0, bufsize);
  107. - p1 = p0 + stripsize;
  108. - p2 = p1 + stripsize;
  109. - pa = (alpha?(p2+stripsize):NULL);
  110. flip = setorientation(img);
  111. if (flip & FLIP_VERTICALLY) {
  112. @@ -1040,7 +1028,6 @@ gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
  113. case PHOTOMETRIC_MINISBLACK:
  114. case PHOTOMETRIC_PALETTE:
  115. colorchannels = 1;
  116. - p2 = p1 = p0;
  117. break;
  118. default:
  119. @@ -1056,7 +1043,31 @@ gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
  120. rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip;
  121. nrow = (row + rowstoread > h ? h - row : rowstoread);
  122. offset_row = row + img->row_offset;
  123. - if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 0),
  124. + if( buf == NULL )
  125. + {
  126. + if (_TIFFReadEncodedStripAndAllocBuffer(
  127. + tif, TIFFComputeStrip(tif, offset_row, 0),
  128. + (void**) &buf, bufsize,
  129. + ((row + img->row_offset)%rowsperstrip + nrow) * scanline)==(tmsize_t)(-1)
  130. + && (buf == NULL || img->stoponerr))
  131. + {
  132. + ret = 0;
  133. + break;
  134. + }
  135. + p0 = buf;
  136. + if( colorchannels == 1 )
  137. + {
  138. + p2 = p1 = p0;
  139. + pa = (alpha?(p0+3*stripsize):NULL);
  140. + }
  141. + else
  142. + {
  143. + p1 = p0 + stripsize;
  144. + p2 = p1 + stripsize;
  145. + pa = (alpha?(p2+stripsize):NULL);
  146. + }
  147. + }
  148. + else if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 0),
  149. p0, ((row + img->row_offset)%rowsperstrip + nrow) * scanline)==(tmsize_t)(-1)
  150. && img->stoponerr)
  151. {
  152. diff --git a/libtiff/tif_read.c b/libtiff/tif_read.c
  153. index fc0072e7..047305ab 100644
  154. --- a/libtiff/tif_read.c
  155. +++ b/libtiff/tif_read.c
  156. @@ -442,18 +442,17 @@ TIFFReadScanline(TIFF* tif, void* buf, uint32 row, uint16 sample)
  157. }
  158. /*
  159. - * Read a strip of data and decompress the specified
  160. - * amount into the user-supplied buffer.
  161. + * Calculate the strip size according to the number of
  162. + * rows in the strip (check for truncated last strip on any
  163. + * of the separations).
  164. */
  165. -tmsize_t
  166. -TIFFReadEncodedStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size)
  167. +static tmsize_t TIFFReadEncodedStripGetStripSize(TIFF* tif, uint32 strip, uint16* pplane)
  168. {
  169. static const char module[] = "TIFFReadEncodedStrip";
  170. TIFFDirectory *td = &tif->tif_dir;
  171. uint32 rowsperstrip;
  172. uint32 stripsperplane;
  173. uint32 stripinplane;
  174. - uint16 plane;
  175. uint32 rows;
  176. tmsize_t stripsize;
  177. if (!TIFFCheckRead(tif,0))
  178. @@ -465,23 +464,37 @@ TIFFReadEncodedStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size)
  179. (unsigned long)td->td_nstrips);
  180. return((tmsize_t)(-1));
  181. }
  182. - /*
  183. - * Calculate the strip size according to the number of
  184. - * rows in the strip (check for truncated last strip on any
  185. - * of the separations).
  186. - */
  187. +
  188. rowsperstrip=td->td_rowsperstrip;
  189. if (rowsperstrip>td->td_imagelength)
  190. rowsperstrip=td->td_imagelength;
  191. stripsperplane= TIFFhowmany_32_maxuint_compat(td->td_imagelength, rowsperstrip);
  192. stripinplane=(strip%stripsperplane);
  193. - plane=(uint16)(strip/stripsperplane);
  194. + if( pplane ) *pplane=(uint16)(strip/stripsperplane);
  195. rows=td->td_imagelength-stripinplane*rowsperstrip;
  196. if (rows>rowsperstrip)
  197. rows=rowsperstrip;
  198. stripsize=TIFFVStripSize(tif,rows);
  199. if (stripsize==0)
  200. return((tmsize_t)(-1));
  201. + return stripsize;
  202. +}
  203. +
  204. +/*
  205. + * Read a strip of data and decompress the specified
  206. + * amount into the user-supplied buffer.
  207. + */
  208. +tmsize_t
  209. +TIFFReadEncodedStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size)
  210. +{
  211. + static const char module[] = "TIFFReadEncodedStrip";
  212. + TIFFDirectory *td = &tif->tif_dir;
  213. + tmsize_t stripsize;
  214. + uint16 plane;
  215. +
  216. + stripsize=TIFFReadEncodedStripGetStripSize(tif, strip, &plane);
  217. + if (stripsize==((tmsize_t)(-1)))
  218. + return((tmsize_t)(-1));
  219. /* shortcut to avoid an extra memcpy() */
  220. if( td->td_compression == COMPRESSION_NONE &&
  221. @@ -510,6 +523,49 @@ TIFFReadEncodedStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size)
  222. return(stripsize);
  223. }
  224. +/* Variant of TIFFReadEncodedStrip() that does
  225. + * * if *buf == NULL, *buf = _TIFFmalloc(bufsizetoalloc) only after TIFFFillStrip() has
  226. + * suceeded. This avoid excessive memory allocation in case of truncated
  227. + * file.
  228. + * * calls regular TIFFReadEncodedStrip() if *buf != NULL
  229. + */
  230. +tmsize_t
  231. +_TIFFReadEncodedStripAndAllocBuffer(TIFF* tif, uint32 strip,
  232. + void **buf, tmsize_t bufsizetoalloc,
  233. + tmsize_t size_to_read)
  234. +{
  235. + tmsize_t this_stripsize;
  236. + uint16 plane;
  237. +
  238. + if( *buf != NULL )
  239. + {
  240. + return TIFFReadEncodedStrip(tif, strip, *buf, size_to_read);
  241. + }
  242. +
  243. + this_stripsize=TIFFReadEncodedStripGetStripSize(tif, strip, &plane);
  244. + if (this_stripsize==((tmsize_t)(-1)))
  245. + return((tmsize_t)(-1));
  246. +
  247. + if ((size_to_read!=(tmsize_t)(-1))&&(size_to_read<this_stripsize))
  248. + this_stripsize=size_to_read;
  249. + if (!TIFFFillStrip(tif,strip))
  250. + return((tmsize_t)(-1));
  251. +
  252. + *buf = _TIFFmalloc(bufsizetoalloc);
  253. + if (*buf == NULL) {
  254. + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for strip buffer");
  255. + return((tmsize_t)(-1));
  256. + }
  257. + _TIFFmemset(*buf, 0, bufsizetoalloc);
  258. +
  259. + if ((*tif->tif_decodestrip)(tif,*buf,this_stripsize,plane)<=0)
  260. + return((tmsize_t)(-1));
  261. + (*tif->tif_postdecode)(tif,*buf,this_stripsize);
  262. + return(this_stripsize);
  263. +
  264. +
  265. +}
  266. +
  267. static tmsize_t
  268. TIFFReadRawStrip1(TIFF* tif, uint32 strip, void* buf, tmsize_t size,
  269. const char* module)
  270. diff --git a/libtiff/tiffiop.h b/libtiff/tiffiop.h
  271. index 846ade03..7f0b90f7 100644
  272. --- a/libtiff/tiffiop.h
  273. +++ b/libtiff/tiffiop.h
  274. @@ -365,6 +365,11 @@ extern void* _TIFFCheckRealloc(TIFF*, void*, tmsize_t, tmsize_t, const char*);
  275. extern double _TIFFUInt64ToDouble(uint64);
  276. extern float _TIFFUInt64ToFloat(uint64);
  277. +extern tmsize_t
  278. +_TIFFReadEncodedStripAndAllocBuffer(TIFF* tif, uint32 strip,
  279. + void **buf, tmsize_t bufsizetoalloc,
  280. + tmsize_t size_to_read);
  281. +
  282. extern int TIFFInitDumpMode(TIFF*, int);
  283. #ifdef PACKBITS_SUPPORT
  284. extern int TIFFInitPackBits(TIFF*, int);