Skip to content

Commit a49feea

Browse files
committed
Fix double-free in gdImageWebPtr()
The issue is that gdImageWebpCtx() (which is called by gdImageWebpPtr() and the other WebP output functions to do the real work) does not return whether it succeeded or failed, so this is not checked in gdImageWebpPtr() and the function wrongly assumes everything is okay, which is not, in this case, because there is a size limitation for WebP, namely that the width and height must by less than 16383. We can't change the signature of gdImageWebpCtx() for API compatibility reasons, so we introduce the static helper _gdImageWebpCtx() which returns success respective failure, so gdImageWebpPtr() and gdImageWebpPtrEx() can check the return value. We leave it solely to libwebp for now to report warnings regarding the failing write. This issue had been reported by Ibrahim El-Sayed to security@libgd.org. CVE-2016-6912
1 parent 4859d69 commit a49feea

File tree

6 files changed

+81
-30
lines changed

6 files changed

+81
-30
lines changed

Diff for: src/gd_webp.c

+46-28
Original file line numberDiff line numberDiff line change
@@ -162,54 +162,41 @@ BGD_DECLARE(gdImagePtr) gdImageCreateFromWebpCtx (gdIOCtx * infile)
162162
return im;
163163
}
164164

165-
/*
166-
Function: gdImageWebpCtx
167-
168-
Write the image as WebP data via a <gdIOCtx>. See <gdImageWebpEx>
169-
for more details.
170-
171-
Parameters:
172-
173-
im - The image to write.
174-
outfile - The output sink.
175-
quality - Image quality.
176165

177-
Returns:
178-
179-
Nothing.
180-
*/
181-
BGD_DECLARE(void) gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quality)
166+
/* returns 0 on success, 1 on failure */
167+
static int _gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quality)
182168
{
183169
uint8_t *argb;
184170
int x, y;
185171
uint8_t *p;
186172
uint8_t *out;
187173
size_t out_size;
174+
int ret = 0;
188175

189176
if (im == NULL) {
190-
return;
177+
return 1;
191178
}
192179

193180
if (!gdImageTrueColor(im)) {
194-
gd_error("Paletter image not supported by webp");
195-
return;
181+
gd_error("Palette image not supported by webp");
182+
return 1;
196183
}
197184

198185
if (quality == -1) {
199186
quality = 80;
200187
}
201188

202189
if (overflow2(gdImageSX(im), 4)) {
203-
return;
190+
return 1;
204191
}
205192

206193
if (overflow2(gdImageSX(im) * 4, gdImageSY(im))) {
207-
return;
194+
return 1;
208195
}
209196

210197
argb = (uint8_t *)gdMalloc(gdImageSX(im) * 4 * gdImageSY(im));
211198
if (!argb) {
212-
return;
199+
return 1;
213200
}
214201
p = argb;
215202
for (y = 0; y < gdImageSY(im); y++) {
@@ -232,13 +219,38 @@ BGD_DECLARE(void) gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quality)
232219
out_size = WebPEncodeRGBA(argb, gdImageSX(im), gdImageSY(im), gdImageSX(im) * 4, quality, &out);
233220
if (out_size == 0) {
234221
gd_error("gd-webp encoding failed");
222+
ret = 1;
235223
goto freeargb;
236224
}
237225
gdPutBuf(out, out_size, outfile);
238226
free(out);
239227

240228
freeargb:
241229
gdFree(argb);
230+
231+
return ret;
232+
}
233+
234+
235+
/*
236+
Function: gdImageWebpCtx
237+
238+
Write the image as WebP data via a <gdIOCtx>. See <gdImageWebpEx>
239+
for more details.
240+
241+
Parameters:
242+
243+
im - The image to write.
244+
outfile - The output sink.
245+
quality - Image quality.
246+
247+
Returns:
248+
249+
Nothing.
250+
*/
251+
BGD_DECLARE(void) gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quality)
252+
{
253+
_gdImageWebpCtx(im, outfile, quality);
242254
}
243255

244256
/*
@@ -278,7 +290,7 @@ BGD_DECLARE(void) gdImageWebpEx (gdImagePtr im, FILE * outFile, int quality)
278290
if (out == NULL) {
279291
return;
280292
}
281-
gdImageWebpCtx(im, out, quality);
293+
_gdImageWebpCtx(im, out, quality);
282294
out->gd_free(out);
283295
}
284296

@@ -302,7 +314,7 @@ BGD_DECLARE(void) gdImageWebp (gdImagePtr im, FILE * outFile)
302314
if (out == NULL) {
303315
return;
304316
}
305-
gdImageWebpCtx(im, out, -1);
317+
_gdImageWebpCtx(im, out, -1);
306318
out->gd_free(out);
307319
}
308320

@@ -318,8 +330,11 @@ BGD_DECLARE(void *) gdImageWebpPtr (gdImagePtr im, int *size)
318330
if (out == NULL) {
319331
return NULL;
320332
}
321-
gdImageWebpCtx(im, out, -1);
322-
rv = gdDPExtractData(out, size);
333+
if (_gdImageWebpCtx(im, out, -1)) {
334+
rv = NULL;
335+
} else {
336+
rv = gdDPExtractData(out, size);
337+
}
323338
out->gd_free(out);
324339

325340
return rv;
@@ -337,8 +352,11 @@ BGD_DECLARE(void *) gdImageWebpPtrEx (gdImagePtr im, int *size, int quality)
337352
if (out == NULL) {
338353
return NULL;
339354
}
340-
gdImageWebpCtx(im, out, quality);
341-
rv = gdDPExtractData(out, size);
355+
if (_gdImageWebpCtx(im, out, quality)) {
356+
rv = NULL;
357+
} else {
358+
rv = gdDPExtractData(out, size);
359+
}
342360
out->gd_free(out);
343361
return rv;
344362
}

Diff for: tests/webp/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
/bug00111
2+
/bug_double_free

Diff for: tests/webp/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
IF(WEBP_FOUND)
22
LIST(APPEND TESTS_FILES
33
bug00111
4+
bug_double_free
45
)
56
ENDIF(WEBP_FOUND)
67

Diff for: tests/webp/Makemodule.am

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
if HAVE_LIBWEBP
22
libgd_test_programs += \
3-
webp/bug00111
3+
webp/bug00111 \
4+
webp/bug_double_free
45
endif
56

67
EXTRA_DIST += \
7-
webp/CMakeLists.txt
8+
webp/CMakeLists.txt \
9+
webp/bug_double_free.jpg

Diff for: tests/webp/bug_double_free.c

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/**
2+
* Test that a too large image doesn't trigger an double-free when written
3+
* to memory.
4+
*/
5+
6+
7+
#include "gd.h"
8+
#include "gdtest.h"
9+
10+
11+
int main()
12+
{
13+
gdImagePtr im1, im2;
14+
FILE *fp;
15+
int size;
16+
17+
fp = gdTestFileOpen2("webp", "bug_double_free.jpg");
18+
gdTestAssert(fp != NULL);
19+
im1 = gdImageCreateFromJpeg(fp);
20+
gdTestAssert(im1 != NULL);
21+
fclose(fp);
22+
23+
im2 = gdImageWebpPtr(im1, &size);
24+
gdTestAssert(im2 == NULL);
25+
26+
gdImageDestroy(im1);
27+
28+
return gdNumFailures();
29+
}

Diff for: tests/webp/bug_double_free.jpg

576 Bytes
Loading

0 commit comments

Comments
 (0)