Reject images that are too large (as defined by the application).

The BMP loader already had this hardcoded to (1 << 24) pixels, so this seems
like a good default to apply to all formats, but many apps will want to clamp
this much much lower.

It's possible to craft malicious but valid images that are enormous, causing
stb_image to allocate tons of memory and eat a ton of CPU, so locking these
to a maximum permitted size can save a lot of headaches in the wild.
This commit is contained in:
Ryan C. Gordon 2020-04-28 11:54:22 -04:00
parent 98ca24b8c7
commit d60594847e
1 changed files with 40 additions and 3 deletions

View File

@ -318,7 +318,14 @@ RECENT REVISION HISTORY:
// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still
// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB
//
// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater
// than that size (in either width or height) without further processing.
// This is to let programs in the wild set an upper bound to prevent
// denial-of-service attacks on untrusted data, as one could generate a
// valid image of gigantic dimensions and force stb_image to allocate a
// huge block of memory and spend disproportionate time decoding it. By
// default this is set to (1 << 24), which is 16777216, but that's still
// very big.
#ifndef STBI_NO_STDIO
#include <stdio.h>
@ -734,6 +741,10 @@ static int stbi__sse2_available(void)
#define STBI_SIMD_ALIGN(type, name) type name
#endif
#ifndef STBI_MAX_DIMENSIONS
#define STBI_MAX_DIMENSIONS (1 << 24)
#endif
///////////////////////////////////////////////
//
// stbi__context struct and start_xxx functions
@ -3163,6 +3174,8 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan)
p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline
s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG
s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires
if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
c = stbi__get8(s);
if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG");
s->img_n = c;
@ -4930,8 +4943,10 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
if (!first) return stbi__err("multiple IHDR","Corrupt PNG");
first = 0;
if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG");
s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)");
s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)");
s->img_x = stbi__get32be(s);
s->img_y = stbi__get32be(s);
if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only");
color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG");
if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG");
@ -5339,6 +5354,9 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
flip_vertically = ((int) s->img_y) > 0;
s->img_y = abs((int) s->img_y);
if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
mr = info.mr;
mg = info.mg;
mb = info.mb;
@ -5675,6 +5693,9 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req
STBI_NOTUSED(tga_x_origin); // @TODO
STBI_NOTUSED(tga_y_origin); // @TODO
if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
// do a tiny bit of precessing
if ( tga_image_type >= 8 )
{
@ -5927,6 +5948,9 @@ static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req
h = stbi__get32be(s);
w = stbi__get32be(s);
if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
// Make sure the depth is 8 bits.
bitdepth = stbi__get16be(s);
if (bitdepth != 8 && bitdepth != 16)
@ -6281,6 +6305,10 @@ static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_c
x = stbi__get16be(s);
y = stbi__get16be(s);
if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)");
if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode");
@ -6389,6 +6417,9 @@ static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_in
g->ratio = stbi__get8(s);
g->transparent = -1;
if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments
if (is_info) return 1;
@ -6930,6 +6961,9 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re
token += 3;
width = (int) strtol(token, NULL, 10);
if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)");
if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)");
*x = width;
*y = height;
@ -7244,6 +7278,9 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req
if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n))
return 0;
if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
*x = s->img_x;
*y = s->img_y;
if (comp) *comp = s->img_n;