diff options
author | Bastien Montagne <montagne29@wanadoo.fr> | 2014-11-21 14:26:13 +0300 |
---|---|---|
committer | Bastien Montagne <montagne29@wanadoo.fr> | 2014-11-21 14:28:11 +0300 |
commit | cc0623ff6c97c8bde5045f9aba1014f6dbd6bc8e (patch) | |
tree | 18529beeb4dd23e75206ab01d1ea643179fed441 | |
parent | 7b0c529fe211e4481fe8e459cbf11159857c611d (diff) |
Fix T42421: HDR reader could easily read past buffer (truncated HDR files e.g.) and segfault.
Now readers get an 'mem_eof' guard pointer, and they abort in case they try to go past it.
-rw-r--r-- | source/blender/imbuf/intern/radiance_hdr.c | 60 |
1 files changed, 45 insertions, 15 deletions
diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c index db268546480..2a4df2aff4f 100644 --- a/source/blender/imbuf/intern/radiance_hdr.c +++ b/source/blender/imbuf/intern/radiance_hdr.c @@ -72,10 +72,13 @@ typedef float fCOLOR[3]; #define COPY_RGBE(c1, c2) (c2[RED] = c1[RED], c2[GRN] = c1[GRN], c2[BLU] = c1[BLU], c2[EXP] = c1[EXP]) /* read routines */ -static unsigned char *oldreadcolrs(RGBE *scan, unsigned char *mem, int xmax) +static unsigned char *oldreadcolrs(RGBE *scan, unsigned char *mem, int xmax, unsigned char *mem_eof) { int i, rshift = 0, len = xmax; while (len > 0) { + if (mem_eof - mem < 4) { + return NULL; + } scan[0][RED] = *mem++; scan[0][GRN] = *mem++; scan[0][BLU] = *mem++; @@ -97,34 +100,62 @@ static unsigned char *oldreadcolrs(RGBE *scan, unsigned char *mem, int xmax) return mem; } -static unsigned char *freadcolrs(RGBE *scan, unsigned char *mem, int xmax) +static unsigned char *freadcolrs(RGBE *scan, unsigned char *mem, int xmax, unsigned char *mem_eof) { int i, j, code, val; - if ((xmax < MINELEN) | (xmax > MAXELEN)) return oldreadcolrs(scan, mem, xmax); + if (mem_eof - mem < 4) { + return NULL; + } + + if ((xmax < MINELEN) | (xmax > MAXELEN)) { + return oldreadcolrs(scan, mem, xmax, mem_eof); + } i = *mem++; - if (i != 2) return oldreadcolrs(scan, mem - 1, xmax); + if (i != 2) { + return oldreadcolrs(scan, mem - 1, xmax, mem_eof); + } scan[0][GRN] = *mem++; scan[0][BLU] = *mem++; i = *mem++; - if (((scan[0][BLU] << 8) | i) != xmax) return NULL; - for (i = 0; i < 4; i++) + if (scan[0][GRN] != 2 || scan[0][BLU] & 128) { + scan[0][RED] = 2; + scan[0][EXP] = i; + return oldreadcolrs(scan + 1, mem, xmax - 1, mem_eof); + } + + if (((scan[0][BLU] << 8) | i) != xmax) { + return NULL; + } + + for (i = 0; i < 4; i++) { + if (mem_eof - mem < 2) { + return NULL; + } for (j = 0; j < xmax; ) { code = *mem++; if (code > 128) { code &= 127; val = *mem++; - while (code--) + while (code--) { scan[j++][i] = (unsigned char)val; + } } - else - while (code--) + else { + if (mem_eof - mem < code) { + return NULL; + } + while (code--) { scan[j++][i] = *mem++; + } + } } + } + return mem; } @@ -182,7 +213,7 @@ struct ImBuf *imb_loadhdr(unsigned char *mem, size_t size, int flags, char color int found = 0; int width = 0, height = 0; int x, y; - unsigned char *ptr; + unsigned char *ptr, *mem_eof = mem + size; char oriY[80], oriX[80]; if (imb_is_a_hdr((void *)mem)) { @@ -218,15 +249,14 @@ struct ImBuf *imb_loadhdr(unsigned char *mem, size_t size, int flags, char color if (flags & IB_test) return ibuf; /* read in and decode the actual data */ - sline = (RGBE *)MEM_mallocN(sizeof(RGBE) * width, "radhdr_read_tmpscan"); + sline = (RGBE *)MEM_mallocN(sizeof(*sline) * width, __func__); rect_float = ibuf->rect_float; for (y = 0; y < height; y++) { - ptr = freadcolrs(sline, ptr, width); + ptr = freadcolrs(sline, ptr, width, mem_eof); if (ptr == NULL) { - printf("HDR decode error\n"); - MEM_freeN(sline); - return ibuf; + printf("WARNING! HDR decode error, image may be just truncated, or completely wrong...\n"); + break; } for (x = 0; x < width; x++) { /* convert to ldr */ |