diff options
author | Campbell Barton <ideasman42@gmail.com> | 2020-11-11 08:14:09 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2020-11-11 08:14:09 +0300 |
commit | 15ffda3bcd697e6f3a0cc13e141da865f36f3b53 (patch) | |
tree | f98d9fc831f18a9194818f5428466884654e802b /source/blender/imbuf | |
parent | 2d60845786aeab099c61ffa42b7f72cccc68bff1 (diff) |
Fix T82602: checking image header reads past buffer bounds
Use the size argument to ensure checking the header doesn't read
past the buffer bounds when reading corrupt/truncated headers
from image files.
Diffstat (limited to 'source/blender/imbuf')
-rw-r--r-- | source/blender/imbuf/intern/bmp.c | 14 | ||||
-rw-r--r-- | source/blender/imbuf/intern/cineon/cineon_dpx.c | 8 | ||||
-rw-r--r-- | source/blender/imbuf/intern/cineon/logImageCore.c | 26 | ||||
-rw-r--r-- | source/blender/imbuf/intern/cineon/logImageCore.h | 4 | ||||
-rw-r--r-- | source/blender/imbuf/intern/dds/dds_api.cpp | 5 | ||||
-rw-r--r-- | source/blender/imbuf/intern/iris.c | 5 | ||||
-rw-r--r-- | source/blender/imbuf/intern/jp2.c | 25 | ||||
-rw-r--r-- | source/blender/imbuf/intern/jpeg.c | 9 | ||||
-rw-r--r-- | source/blender/imbuf/intern/oiio/openimageio_api.cpp | 5 | ||||
-rw-r--r-- | source/blender/imbuf/intern/openexr/openexr_api.cpp | 6 | ||||
-rw-r--r-- | source/blender/imbuf/intern/png.c | 15 | ||||
-rw-r--r-- | source/blender/imbuf/intern/radiance_hdr.c | 5 | ||||
-rw-r--r-- | source/blender/imbuf/intern/targa.c | 12 | ||||
-rw-r--r-- | source/blender/imbuf/intern/tiff.c | 5 |
14 files changed, 95 insertions, 49 deletions
diff --git a/source/blender/imbuf/intern/bmp.c b/source/blender/imbuf/intern/bmp.c index 9358b67b3ed..58ce02f28ae 100644 --- a/source/blender/imbuf/intern/bmp.c +++ b/source/blender/imbuf/intern/bmp.c @@ -72,10 +72,14 @@ typedef struct BMPHEADER { CHECK_HEADER_FIELD(_mem, "CI") || CHECK_HEADER_FIELD(_mem, "CP") || \ CHECK_HEADER_FIELD(_mem, "IC") || CHECK_HEADER_FIELD(_mem, "PT")) -static bool checkbmp(const uchar *mem) +static bool checkbmp(const uchar *mem, const size_t size) { + if (size < BMP_FILEHEADER_SIZE) { + return false; + } + if (!CHECK_HEADER_FIELD_BMP(mem)) { - return 0; + return false; } bool ok = false; @@ -102,9 +106,9 @@ static bool checkbmp(const uchar *mem) return ok; } -bool imb_is_a_bmp(const uchar *buf, size_t UNUSED(size)) +bool imb_is_a_bmp(const uchar *buf, size_t size) { - return checkbmp(buf); + return checkbmp(buf, size); } ImBuf *imb_bmp_decode(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE]) @@ -120,7 +124,7 @@ ImBuf *imb_bmp_decode(const uchar *mem, size_t size, int flags, char colorspace[ (void)size; /* unused */ - if (checkbmp(mem) == 0) { + if (checkbmp(mem, size) == 0) { return NULL; } diff --git a/source/blender/imbuf/intern/cineon/cineon_dpx.c b/source/blender/imbuf/intern/cineon/cineon_dpx.c index 8bbd9fbb285..de54e6dab9d 100644 --- a/source/blender/imbuf/intern/cineon/cineon_dpx.c +++ b/source/blender/imbuf/intern/cineon/cineon_dpx.c @@ -188,9 +188,9 @@ bool imb_save_cineon(struct ImBuf *buf, const char *filepath, int flags) return imb_save_dpx_cineon(buf, filepath, 1, flags); } -bool imb_is_a_cineon(const unsigned char *buf, size_t UNUSED(size)) +bool imb_is_a_cineon(const unsigned char *buf, size_t size) { - return logImageIsCineon(buf); + return logImageIsCineon(buf, size); } ImBuf *imb_load_cineon(const unsigned char *mem, @@ -209,9 +209,9 @@ bool imb_save_dpx(struct ImBuf *buf, const char *filepath, int flags) return imb_save_dpx_cineon(buf, filepath, 0, flags); } -bool imb_is_a_dpx(const unsigned char *buf, size_t UNUSED(size)) +bool imb_is_a_dpx(const unsigned char *buf, size_t size) { - return logImageIsDpx(buf); + return logImageIsDpx(buf, size); } ImBuf *imb_load_dpx(const unsigned char *mem, diff --git a/source/blender/imbuf/intern/cineon/logImageCore.c b/source/blender/imbuf/intern/cineon/logImageCore.c index d5f5691c5f0..2d42609fdf5 100644 --- a/source/blender/imbuf/intern/cineon/logImageCore.c +++ b/source/blender/imbuf/intern/cineon/logImageCore.c @@ -96,15 +96,23 @@ void logImageSetVerbose(int verbosity) * IO stuff */ -int logImageIsDpx(const void *buffer) +int logImageIsDpx(const void *buffer, const unsigned int size) { - unsigned int magicNum = *(unsigned int *)buffer; + unsigned int magicNum; + if (size < sizeof(magicNum)) { + return 0; + } + magicNum = *(unsigned int *)buffer; return (magicNum == DPX_FILE_MAGIC || magicNum == swap_uint(DPX_FILE_MAGIC, 1)); } -int logImageIsCineon(const void *buffer) +int logImageIsCineon(const void *buffer, const unsigned int size) { - unsigned int magicNum = *(unsigned int *)buffer; + unsigned int magicNum; + if (size < sizeof(magicNum)) { + return 0; + } + magicNum = *(unsigned int *)buffer; return (magicNum == CINEON_FILE_MAGIC || magicNum == swap_uint(CINEON_FILE_MAGIC, 1)); } @@ -119,17 +127,17 @@ LogImageFile *logImageOpenFromFile(const char *filename, int cineon) return NULL; } - if (fread(&magicNum, sizeof(unsigned int), 1, f) != 1) { + if (fread(&magicNum, sizeof(magicNum), 1, f) != 1) { fclose(f); return NULL; } fclose(f); - if (logImageIsDpx(&magicNum)) { + if (logImageIsDpx(&magicNum, sizeof(magicNum))) { return dpxOpen((const unsigned char *)filename, 0, 0); } - if (logImageIsCineon(&magicNum)) { + if (logImageIsCineon(&magicNum, sizeof(magicNum))) { return cineonOpen((const unsigned char *)filename, 0, 0); } @@ -138,10 +146,10 @@ LogImageFile *logImageOpenFromFile(const char *filename, int cineon) LogImageFile *logImageOpenFromMemory(const unsigned char *buffer, unsigned int size) { - if (logImageIsDpx(buffer)) { + if (logImageIsDpx(buffer, size)) { return dpxOpen(buffer, 1, size); } - if (logImageIsCineon(buffer)) { + if (logImageIsCineon(buffer, size)) { return cineonOpen(buffer, 1, size); } diff --git a/source/blender/imbuf/intern/cineon/logImageCore.h b/source/blender/imbuf/intern/cineon/logImageCore.h index a2d50f21a98..c2704a086b6 100644 --- a/source/blender/imbuf/intern/cineon/logImageCore.h +++ b/source/blender/imbuf/intern/cineon/logImageCore.h @@ -181,8 +181,8 @@ enum descriptor { /* int functions return 0 for OK */ void logImageSetVerbose(int verbosity); -int logImageIsDpx(const void *buffer); -int logImageIsCineon(const void *buffer); +int logImageIsDpx(const void *buffer, unsigned int size); +int logImageIsCineon(const void *buffer, unsigned int size); LogImageFile *logImageOpenFromMemory(const unsigned char *buffer, unsigned int size); LogImageFile *logImageOpenFromFile(const char *filename, int cineon); void logImageGetSize(LogImageFile *logImage, int *width, int *height, int *depth); diff --git a/source/blender/imbuf/intern/dds/dds_api.cpp b/source/blender/imbuf/intern/dds/dds_api.cpp index 78ce8b5ee9b..5687824f9fd 100644 --- a/source/blender/imbuf/intern/dds/dds_api.cpp +++ b/source/blender/imbuf/intern/dds/dds_api.cpp @@ -73,8 +73,11 @@ bool imb_save_dds(struct ImBuf *ibuf, const char *name, int /*flags*/) } /* note: use at most first 32 bytes */ -bool imb_is_a_dds(const unsigned char *mem, size_t UNUSED(size)) +bool imb_is_a_dds(const unsigned char *mem, const size_t size) { + if (size < 8) { + return false; + } /* heuristic check to see if mem contains a DDS file */ /* header.fourcc == FOURCC_DDS */ if ((mem[0] != 'D') || (mem[1] != 'D') || (mem[2] != 'S') || (mem[3] != ' ')) { diff --git a/source/blender/imbuf/intern/iris.c b/source/blender/imbuf/intern/iris.c index c27ac5754c7..112b95bf1a1 100644 --- a/source/blender/imbuf/intern/iris.c +++ b/source/blender/imbuf/intern/iris.c @@ -243,8 +243,11 @@ static void test_endian_zbuf(struct ImBuf *ibuf) /* this one is only def-ed once, strangely... */ #define GSS(x) (((uchar *)(x))[1] << 8 | ((uchar *)(x))[0]) -bool imb_is_a_iris(const uchar *mem, size_t UNUSED(size)) +bool imb_is_a_iris(const uchar *mem, size_t size) { + if (size < 2) { + return false; + } return ((GS(mem) == IMAGIC) || (GSS(mem) == IMAGIC)); } diff --git a/source/blender/imbuf/intern/jp2.c b/source/blender/imbuf/intern/jp2.c index b964510b8db..e19589317d7 100644 --- a/source/blender/imbuf/intern/jp2.c +++ b/source/blender/imbuf/intern/jp2.c @@ -58,31 +58,38 @@ enum { DCP_CINEMA4K = 4, }; -static bool check_jp2(const unsigned char *mem) /* J2K_CFMT */ +static bool check_jp2(const unsigned char *mem, const size_t size) /* J2K_CFMT */ { + if (size < sizeof(JP2_HEAD)) { + return false; + } return memcmp(JP2_HEAD, mem, sizeof(JP2_HEAD)) ? 0 : 1; } -static bool check_j2k(const unsigned char *mem) /* J2K_CFMT */ +static bool check_j2k(const unsigned char *mem, const size_t size) /* J2K_CFMT */ { + if (size < sizeof(J2K_HEAD)) { + return false; + } return memcmp(J2K_HEAD, mem, sizeof(J2K_HEAD)) ? 0 : 1; } -static OPJ_CODEC_FORMAT format_from_header(const unsigned char mem[JP2_FILEHEADER_SIZE]) +static OPJ_CODEC_FORMAT format_from_header(const unsigned char mem[JP2_FILEHEADER_SIZE], + const size_t size) { - if (check_jp2(mem)) { + if (check_jp2(mem, size)) { return OPJ_CODEC_JP2; } - if (check_j2k(mem)) { + if (check_j2k(mem, size)) { return OPJ_CODEC_J2K; } return OPJ_CODEC_UNKNOWN; } -bool imb_is_a_jp2(const unsigned char *buf, size_t UNUSED(size)) +bool imb_is_a_jp2(const unsigned char *buf, size_t size) { - return (check_jp2(buf) || check_j2k(buf)); + return (check_jp2(buf, size) || check_j2k(buf, size)); } /** @@ -317,7 +324,7 @@ ImBuf *imb_load_jp2(const unsigned char *mem, int flags, char colorspace[IM_MAX_SPACE]) { - const OPJ_CODEC_FORMAT format = (size > JP2_FILEHEADER_SIZE) ? format_from_header(mem) : + const OPJ_CODEC_FORMAT format = (size > JP2_FILEHEADER_SIZE) ? format_from_header(mem, size) : OPJ_CODEC_UNKNOWN; struct BufInfo buf_wrapper = { .buf = mem, @@ -348,7 +355,7 @@ ImBuf *imb_load_jp2_filepath(const char *filepath, int flags, char colorspace[IM fseek(p_file, 0, SEEK_SET); - const OPJ_CODEC_FORMAT format = format_from_header(mem); + const OPJ_CODEC_FORMAT format = format_from_header(mem, sizeof(mem)); ImBuf *ibuf = imb_load_jp2_stream(stream, format, flags, colorspace); opj_stream_destroy(stream); return ibuf; diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c index 4a937738b52..93cdbbb1407 100644 --- a/source/blender/imbuf/intern/jpeg.c +++ b/source/blender/imbuf/intern/jpeg.c @@ -57,12 +57,13 @@ static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int fla static const uchar jpeg_default_quality = 75; static uchar ibuf_quality; -bool imb_is_a_jpeg(const unsigned char *mem, const size_t UNUSED(size)) +bool imb_is_a_jpeg(const unsigned char *mem, const size_t size) { - if ((mem[0] == 0xFF) && (mem[1] == 0xD8)) { - return 1; + const char magic[2] = {0xFF, 0xD8}; + if (size < sizeof(magic)) { + return false; } - return 0; + return memcmp(mem, magic, sizeof(magic)) == 0; } /*---------------------------------------------------------- diff --git a/source/blender/imbuf/intern/oiio/openimageio_api.cpp b/source/blender/imbuf/intern/oiio/openimageio_api.cpp index 9f27ac96e6d..1e8c3c25778 100644 --- a/source/blender/imbuf/intern/oiio/openimageio_api.cpp +++ b/source/blender/imbuf/intern/oiio/openimageio_api.cpp @@ -163,9 +163,12 @@ static ImBuf *imb_oiio_load_image_float( extern "C" { -bool imb_is_a_photoshop(const unsigned char *mem, size_t UNUSED(size)) +bool imb_is_a_photoshop(const unsigned char *mem, size_t size) { const unsigned char magic[4] = {'8', 'B', 'P', 'S'}; + if (size < sizeof(magic)) { + return false; + } return memcmp(magic, mem, sizeof(magic)) == 0; } diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index 467454ddb7a..56188fbe98a 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -330,8 +330,12 @@ extern "C" { * Test presence of OpenEXR file. * \param mem: pointer to loaded OpenEXR bitstream */ -bool imb_is_a_openexr(const unsigned char *mem, const size_t UNUSED(size)) +bool imb_is_a_openexr(const unsigned char *mem, const size_t size) { + /* No define is exposed for this size. */ + if (size < 4) { + return false; + } return Imf::isImfMagic((const char *)mem); } diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c index a4ad839c513..25fc6a1cddf 100644 --- a/source/blender/imbuf/intern/png.c +++ b/source/blender/imbuf/intern/png.c @@ -59,18 +59,21 @@ BLI_INLINE unsigned short UPSAMPLE_8_TO_16(const unsigned char _val) return (_val << 8) + _val; } -bool imb_is_a_png(const unsigned char *mem, size_t UNUSED(size)) +bool imb_is_a_png(const unsigned char *mem, size_t size) { - bool ret_val = 0; + const int num_to_check = 8; + if (size < num_to_check) { + return false; + } + bool ok = false; #if (PNG_LIBPNG_VER_MAJOR == 1) && (PNG_LIBPNG_VER_MINOR == 2) /* Older version of libpng doesn't use const pointer to memory. */ - ret_val = !png_sig_cmp((png_bytep)mem, 0, 8); + ok = !png_sig_cmp((png_bytep)mem, 0, num_to_check); #else - ret_val = !png_sig_cmp(mem, 0, 8); + ok = !png_sig_cmp(mem, 0, num_to_check); #endif - - return ret_val; + return ok; } static void Flush(png_structp png_ptr) diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c index d8b032dc5bd..285b18595f7 100644 --- a/source/blender/imbuf/intern/radiance_hdr.c +++ b/source/blender/imbuf/intern/radiance_hdr.c @@ -197,7 +197,7 @@ static void FLOAT2RGBE(const fCOLOR fcol, RGBE rgbe) /* ImBuf read */ -bool imb_is_a_hdr(const unsigned char *buf, size_t UNUSED(size)) +bool imb_is_a_hdr(const unsigned char *buf, const size_t size) { /* NOTE: `#?RADIANCE` is used by other programs such as `ImageMagik`, * Although there are some files in the wild that only use `#?` (from looking online). @@ -209,6 +209,9 @@ bool imb_is_a_hdr(const unsigned char *buf, size_t UNUSED(size)) * See: http://paulbourke.net/dataformats/pic/ */ const unsigned char magic[2] = {'#', '?'}; + if (size < sizeof(magic)) { + return false; + } return memcmp(buf, magic, sizeof(magic)) == 0; } diff --git a/source/blender/imbuf/intern/targa.c b/source/blender/imbuf/intern/targa.c index 64dbf6deb4b..a9833623250 100644 --- a/source/blender/imbuf/intern/targa.c +++ b/source/blender/imbuf/intern/targa.c @@ -361,8 +361,12 @@ bool imb_savetarga(struct ImBuf *ibuf, const char *filepath, int UNUSED(flags)) return ok; } -static bool checktarga(TARGA *tga, const unsigned char *mem) +static bool checktarga(TARGA *tga, const unsigned char *mem, const size_t size) { + if (size < TARGA_HEADER_SIZE) { + return false; + } + tga->numid = mem[0]; tga->maptyp = mem[1]; tga->imgtyp = mem[2]; @@ -409,11 +413,11 @@ static bool checktarga(TARGA *tga, const unsigned char *mem) return true; } -bool imb_is_a_targa(const unsigned char *buf, size_t UNUSED(size)) +bool imb_is_a_targa(const unsigned char *buf, size_t size) { TARGA tga; - return checktarga(&tga, buf); + return checktarga(&tga, buf, size); } static void complete_partial_load(struct ImBuf *ibuf, unsigned int *rect) @@ -633,7 +637,7 @@ ImBuf *imb_loadtarga(const unsigned char *mem, int32_t cp_data; uchar *cp = (uchar *)&cp_data; - if (checktarga(&tga, mem) == 0) { + if (checktarga(&tga, mem, mem_size) == 0) { return NULL; } diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c index 69c1c6b596c..587d6ad9e7e 100644 --- a/source/blender/imbuf/intern/tiff.c +++ b/source/blender/imbuf/intern/tiff.c @@ -316,10 +316,13 @@ static TIFF *imb_tiff_client_open(ImbTIFFMemFile *memFile, const unsigned char * * hence my manual comparison. - Jonathan Merritt (lancelet) 4th Sept 2005. */ #define IMB_TIFF_NCB 4 /* number of comparison bytes used */ -bool imb_is_a_tiff(const unsigned char *buf, size_t UNUSED(size)) +bool imb_is_a_tiff(const unsigned char *buf, size_t size) { const char big_endian[IMB_TIFF_NCB] = {0x4d, 0x4d, 0x00, 0x2a}; const char lil_endian[IMB_TIFF_NCB] = {0x49, 0x49, 0x2a, 0x00}; + if (size < IMB_TIFF_NCB) { + return false; + } return ((memcmp(big_endian, buf, IMB_TIFF_NCB) == 0) || (memcmp(lil_endian, buf, IMB_TIFF_NCB) == 0)); |