0004-Fix-492-Potential-double-free-in-gdImage-Ptr.patch 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. From 553702980ae89c83f2d6e254d62cf82e204956d0 Mon Sep 17 00:00:00 2001
  2. From: "Christoph M. Becker" <cmbecker69@gmx.de>
  3. Date: Thu, 17 Jan 2019 11:54:55 +0100
  4. Subject: [PATCH] Fix #492: Potential double-free in gdImage*Ptr()
  5. Whenever `gdImage*Ptr()` calls `gdImage*Ctx()` and the latter fails, we
  6. must not call `gdDPExtractData()`; otherwise a double-free would
  7. happen. Since `gdImage*Ctx()` are void functions, and we can't change
  8. that for BC reasons, we're introducing static helpers which are used
  9. internally.
  10. We're adding a regression test for `gdImageJpegPtr()`, but not for
  11. `gdImageGifPtr()` and `gdImageWbmpPtr()` since we don't know how to
  12. trigger failure of the respective `gdImage*Ctx()` calls.
  13. This potential security issue has been reported by Solmaz Salimi (aka.
  14. Rooney).
  15. CVE-2019-6978
  16. [Peter: drop tests]
  17. Signed-off-by: Peter Korsgaard <peter@korsgaard.com>
  18. ---
  19. src/gd_gif_out.c | 18 +++++++++++++++---
  20. src/gd_jpeg.c | 20 ++++++++++++++++----
  21. src/gd_wbmp.c | 21 ++++++++++++++++++---
  22. 3 files changed, 84 insertions(+), 11 deletions(-)
  23. diff --git a/src/gd_gif_out.c b/src/gd_gif_out.c
  24. index 298a581..d5a9534 100644
  25. --- a/src/gd_gif_out.c
  26. +++ b/src/gd_gif_out.c
  27. @@ -99,6 +99,7 @@ static void char_init(GifCtx *ctx);
  28. static void char_out(int c, GifCtx *ctx);
  29. static void flush_char(GifCtx *ctx);
  30. +static int _gdImageGifCtx(gdImagePtr im, gdIOCtxPtr out);
  31. @@ -131,8 +132,11 @@ BGD_DECLARE(void *) gdImageGifPtr(gdImagePtr im, int *size)
  32. void *rv;
  33. gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
  34. if (out == NULL) return NULL;
  35. - gdImageGifCtx(im, out);
  36. - rv = gdDPExtractData(out, size);
  37. + if (!_gdImageGifCtx(im, out)) {
  38. + rv = gdDPExtractData(out, size);
  39. + } else {
  40. + rv = NULL;
  41. + }
  42. out->gd_free(out);
  43. return rv;
  44. }
  45. @@ -220,6 +224,12 @@ BGD_DECLARE(void) gdImageGif(gdImagePtr im, FILE *outFile)
  46. */
  47. BGD_DECLARE(void) gdImageGifCtx(gdImagePtr im, gdIOCtxPtr out)
  48. +{
  49. + _gdImageGifCtx(im, out);
  50. +}
  51. +
  52. +/* returns 0 on success, 1 on failure */
  53. +static int _gdImageGifCtx(gdImagePtr im, gdIOCtxPtr out)
  54. {
  55. gdImagePtr pim = 0, tim = im;
  56. int interlace, BitsPerPixel;
  57. @@ -231,7 +241,7 @@ BGD_DECLARE(void) gdImageGifCtx(gdImagePtr im, gdIOCtxPtr out)
  58. based temporary image. */
  59. pim = gdImageCreatePaletteFromTrueColor(im, 1, 256);
  60. if(!pim) {
  61. - return;
  62. + return 1;
  63. }
  64. tim = pim;
  65. }
  66. @@ -247,6 +257,8 @@ BGD_DECLARE(void) gdImageGifCtx(gdImagePtr im, gdIOCtxPtr out)
  67. /* Destroy palette based temporary image. */
  68. gdImageDestroy( pim);
  69. }
  70. +
  71. + return 0;
  72. }
  73. diff --git a/src/gd_jpeg.c b/src/gd_jpeg.c
  74. index fc05842..96ef430 100644
  75. --- a/src/gd_jpeg.c
  76. +++ b/src/gd_jpeg.c
  77. @@ -117,6 +117,8 @@ static void fatal_jpeg_error(j_common_ptr cinfo)
  78. exit(99);
  79. }
  80. +static int _gdImageJpegCtx(gdImagePtr im, gdIOCtx *outfile, int quality);
  81. +
  82. /*
  83. * Write IM to OUTFILE as a JFIF-formatted JPEG image, using quality
  84. * QUALITY. If QUALITY is in the range 0-100, increasing values
  85. @@ -231,8 +233,11 @@ BGD_DECLARE(void *) gdImageJpegPtr(gdImagePtr im, int *size, int quality)
  86. void *rv;
  87. gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
  88. if (out == NULL) return NULL;
  89. - gdImageJpegCtx(im, out, quality);
  90. - rv = gdDPExtractData(out, size);
  91. + if (!_gdImageJpegCtx(im, out, quality)) {
  92. + rv = gdDPExtractData(out, size);
  93. + } else {
  94. + rv = NULL;
  95. + }
  96. out->gd_free(out);
  97. return rv;
  98. }
  99. @@ -253,6 +258,12 @@ void jpeg_gdIOCtx_dest(j_compress_ptr cinfo, gdIOCtx *outfile);
  100. */
  101. BGD_DECLARE(void) gdImageJpegCtx(gdImagePtr im, gdIOCtx *outfile, int quality)
  102. +{
  103. + _gdImageJpegCtx(im, outfile, quality);
  104. +}
  105. +
  106. +/* returns 0 on success, 1 on failure */
  107. +static int _gdImageJpegCtx(gdImagePtr im, gdIOCtx *outfile, int quality)
  108. {
  109. struct jpeg_compress_struct cinfo;
  110. struct jpeg_error_mgr jerr;
  111. @@ -287,7 +298,7 @@ BGD_DECLARE(void) gdImageJpegCtx(gdImagePtr im, gdIOCtx *outfile, int quality)
  112. if(row) {
  113. gdFree(row);
  114. }
  115. - return;
  116. + return 1;
  117. }
  118. cinfo.err->emit_message = jpeg_emit_message;
  119. @@ -328,7 +339,7 @@ BGD_DECLARE(void) gdImageJpegCtx(gdImagePtr im, gdIOCtx *outfile, int quality)
  120. if(row == 0) {
  121. gd_error("gd-jpeg: error: unable to allocate JPEG row structure: gdCalloc returns NULL\n");
  122. jpeg_destroy_compress(&cinfo);
  123. - return;
  124. + return 1;
  125. }
  126. rowptr[0] = row;
  127. @@ -405,6 +416,7 @@ BGD_DECLARE(void) gdImageJpegCtx(gdImagePtr im, gdIOCtx *outfile, int quality)
  128. jpeg_finish_compress(&cinfo);
  129. jpeg_destroy_compress(&cinfo);
  130. gdFree(row);
  131. + return 0;
  132. }
  133. diff --git a/src/gd_wbmp.c b/src/gd_wbmp.c
  134. index f19a1c9..a49bdbe 100644
  135. --- a/src/gd_wbmp.c
  136. +++ b/src/gd_wbmp.c
  137. @@ -88,6 +88,8 @@ int gd_getin(void *in)
  138. return (gdGetC((gdIOCtx *)in));
  139. }
  140. +static int _gdImageWBMPCtx(gdImagePtr image, int fg, gdIOCtx *out);
  141. +
  142. /*
  143. Function: gdImageWBMPCtx
  144. @@ -100,6 +102,12 @@ int gd_getin(void *in)
  145. out - the stream where to write
  146. */
  147. BGD_DECLARE(void) gdImageWBMPCtx(gdImagePtr image, int fg, gdIOCtx *out)
  148. +{
  149. + _gdImageWBMPCtx(image, fg, out);
  150. +}
  151. +
  152. +/* returns 0 on success, 1 on failure */
  153. +static int _gdImageWBMPCtx(gdImagePtr image, int fg, gdIOCtx *out)
  154. {
  155. int x, y, pos;
  156. Wbmp *wbmp;
  157. @@ -107,7 +115,7 @@ BGD_DECLARE(void) gdImageWBMPCtx(gdImagePtr image, int fg, gdIOCtx *out)
  158. /* create the WBMP */
  159. if((wbmp = createwbmp(gdImageSX(image), gdImageSY(image), WBMP_WHITE)) == NULL) {
  160. gd_error("Could not create WBMP\n");
  161. - return;
  162. + return 1;
  163. }
  164. /* fill up the WBMP structure */
  165. @@ -123,11 +131,15 @@ BGD_DECLARE(void) gdImageWBMPCtx(gdImagePtr image, int fg, gdIOCtx *out)
  166. /* write the WBMP to a gd file descriptor */
  167. if(writewbmp(wbmp, &gd_putout, out)) {
  168. + freewbmp(wbmp);
  169. gd_error("Could not save WBMP\n");
  170. + return 1;
  171. }
  172. /* des submitted this bugfix: gdFree the memory. */
  173. freewbmp(wbmp);
  174. +
  175. + return 0;
  176. }
  177. /*
  178. @@ -271,8 +283,11 @@ BGD_DECLARE(void *) gdImageWBMPPtr(gdImagePtr im, int *size, int fg)
  179. void *rv;
  180. gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
  181. if (out == NULL) return NULL;
  182. - gdImageWBMPCtx(im, fg, out);
  183. - rv = gdDPExtractData(out, size);
  184. + if (!_gdImageWBMPCtx(im, fg, out)) {
  185. + rv = gdDPExtractData(out, size);
  186. + } else {
  187. + rv = NULL;
  188. + }
  189. out->gd_free(out);
  190. return rv;
  191. }
  192. --
  193. 2.20.1