diff --git a/rtengine/libraw/Changelog.txt b/rtengine/libraw/Changelog.txt index 7534563b6..42c2bb2b5 100644 --- a/rtengine/libraw/Changelog.txt +++ b/rtengine/libraw/Changelog.txt @@ -1,3 +1,25 @@ +2023-12-19 Alex Tutubalin + + LibRaw 0.21.2-Release + + * New compile-defined limit LIBRAW_MAX_PROFILE_SIZE_MB: + limits allocation/read size for embedded color profile (default: 256Mb) + + * Embedded color profile allocation/read size: limited by input file size. + + * Multiple fixes (mostly inspired by oss-fuzz) to improve library stability and/or input checks. + + * raw-identify: use fallback if PATH_MAX not available + + * Disabled color conversion for Canon 16-bit thumbnails + + * docs/changelog: explained the case when no thumbnail is found in specific file + + * swapXX renamed to libraw_swapXX to avoid name conflict + + * better striped thumbnails handling + + 2023-01-05 Alex Tutubalin LibRaw 0.21.1-Release * fixed typo in panasonic metadata parser @@ -52,7 +74,11 @@ Notes: - Only TIFF-based and CR3 files are parsed for thumbnail list, other formats will have - thumbcount = 1 (or 0 if no thumbnail found in file). + thumbcount = 1. + + - If no thumbnails are found in file: thumbcount will be set to 1 and + thumblist[0] will be initialized with data from thumbnail fields, + so LibRaw::unpack_thumb_ex(0) will do the same as LibRaw::unpack_thumb() - Thumbnail image size may be unknown (not recorded in metadata), in this case twidth and theight are zero. Usually small(er) thumbnails will always have twidth/theight filled, while largest one may have these fields set to zero. diff --git a/rtengine/libraw/doc/API-datastruct.html b/rtengine/libraw/doc/API-datastruct.html index 09c05ac76..5c2ddb3bf 100644 --- a/rtengine/libraw/doc/API-datastruct.html +++ b/rtengine/libraw/doc/API-datastruct.html @@ -427,6 +427,12 @@ +

+ Note: even if no thumbnails were found in TIFF/CR3 structure, the + thumbcount field will be initialized to 1 and thumblist[0] will be + initialized to thumbnail data from the thumbnail data, so + LibRaw::unpack_thumb_ex(0) will do the same as LibRaw::unpack_thumb(). +

Structure libraw_lensinfo_t: parsed lens data

The following parameters are extracted from Makernotes and EXIF, to help diff --git a/rtengine/libraw/libraw/libraw_const.h b/rtengine/libraw/libraw/libraw_const.h index 599306b6f..61f8028b2 100644 --- a/rtengine/libraw/libraw/libraw_const.h +++ b/rtengine/libraw/libraw/libraw_const.h @@ -24,6 +24,10 @@ it under the terms of the one of two licenses as you choose: #define LIBRAW_MAX_ALLOC_MB_DEFAULT 2048L #endif +#ifndef LIBRAW_MAX_PROFILE_SIZE_MB +#define LIBRAW_MAX_PROFILE_SIZE_MB 256LL +#endif + #ifndef LIBRAW_MAX_NONDNG_RAW_FILE_SIZE #define LIBRAW_MAX_NONDNG_RAW_FILE_SIZE 2147483647ULL #endif diff --git a/rtengine/libraw/libraw/libraw_version.h b/rtengine/libraw/libraw/libraw_version.h index 3845a5e46..c6f5c72a3 100644 --- a/rtengine/libraw/libraw/libraw_version.h +++ b/rtengine/libraw/libraw/libraw_version.h @@ -22,7 +22,7 @@ it under the terms of the one of two licenses as you choose: #define LIBRAW_MAJOR_VERSION 0 #define LIBRAW_MINOR_VERSION 21 -#define LIBRAW_PATCH_VERSION 1 +#define LIBRAW_PATCH_VERSION 2 #define LIBRAW_VERSION_TAIL Release #define LIBRAW_SHLIB_CURRENT 23 diff --git a/rtengine/libraw/samples/raw-identify.cpp b/rtengine/libraw/samples/raw-identify.cpp index ced518175..31c770d34 100644 --- a/rtengine/libraw/samples/raw-identify.cpp +++ b/rtengine/libraw/samples/raw-identify.cpp @@ -40,7 +40,11 @@ it under the terms of the one of two licenses as you choose: #include #include #ifndef MAX_PATH +#ifdef PATH_MAX #define MAX_PATH PATH_MAX +#else +#define MAX_PATH 4096 +#endif #endif #endif diff --git a/rtengine/libraw/src/decoders/decoders_dcraw.cpp b/rtengine/libraw/src/decoders/decoders_dcraw.cpp index 721d38577..090a6b726 100644 --- a/rtengine/libraw/src/decoders/decoders_dcraw.cpp +++ b/rtengine/libraw/src/decoders/decoders_dcraw.cpp @@ -577,6 +577,9 @@ void LibRaw::lossless_jpeg_load_raw() i = jidx / (cr2_slice[1] * raw_height); if ((j = i >= cr2_slice[0])) i = cr2_slice[0]; + if(!cr2_slice[1+j]) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + jidx -= i * (cr2_slice[1] * raw_height); row = jidx / cr2_slice[1 + j]; col = jidx % cr2_slice[1 + j] + i * cr2_slice[1]; @@ -609,10 +612,16 @@ void LibRaw::canon_sraw_load_raw() int saved_w = width, saved_h = height; char *cp; + if(!image) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + if (!ljpeg_start(&jh, 0) || jh.clrs < 4) return; jwide = (jh.wide >>= 1) * jh.clrs; + if (jwide < 32 || jwide > 65535) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + if (load_flags & 256) { width = raw_width; @@ -1170,6 +1179,8 @@ void LibRaw::panasonic_load_raw() } else { + if (load_flags >= 0x4000) + throw LIBRAW_EXCEPTION_IO_CORRUPT; for (row = 0; row < raw_height; row++) { checkCancel(); diff --git a/rtengine/libraw/src/decoders/decoders_libraw.cpp b/rtengine/libraw/src/decoders/decoders_libraw.cpp index 332e2af21..bc62a6c2d 100644 --- a/rtengine/libraw/src/decoders/decoders_libraw.cpp +++ b/rtengine/libraw/src/decoders/decoders_libraw.cpp @@ -22,6 +22,9 @@ void LibRaw::sony_arq_load_raw() { int row, col; + if (imgdata.idata.filters || imgdata.idata.colors < 3) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + read_shorts(imgdata.rawdata.raw_image, imgdata.sizes.raw_width * imgdata.sizes.raw_height * 4); libraw_internal_data.internal_data.input->seek( diff --git a/rtengine/libraw/src/decoders/fp_dng.cpp b/rtengine/libraw/src/decoders/fp_dng.cpp index 0566ad2ca..72631dbbd 100644 --- a/rtengine/libraw/src/decoders/fp_dng.cpp +++ b/rtengine/libraw/src/decoders/fp_dng.cpp @@ -556,7 +556,7 @@ _forceinline #else inline #endif -void swap24(uchar *data, int len) +void libraw_swap24(uchar *data, int len) { for (int i = 0; i < len - 2; i += 3) { @@ -572,7 +572,7 @@ _forceinline #else inline #endif -void swap32(uchar *data, int len) +void libraw_swap32(uchar *data, int len) { unsigned *d = (unsigned*)data; for (int i = 0; i < len / 4; i++) @@ -646,9 +646,9 @@ void LibRaw::uncompressed_fp_dng_load_raw() if (bytesps == 2 && difford) libraw_swab(dst, fullrowbytes); else if (bytesps == 3 && (libraw_internal_data.unpacker_data.order == 0x4949)) // II-16bit - swap24(dst, fullrowbytes); + libraw_swap24(dst, fullrowbytes); if (bytesps == 4 && difford) - swap32(dst, fullrowbytes); + libraw_swap32(dst, fullrowbytes); float lmax = expandFloats( dst, diff --git a/rtengine/libraw/src/decoders/load_mfbacks.cpp b/rtengine/libraw/src/decoders/load_mfbacks.cpp index 493c7859f..cddc33ebc 100644 --- a/rtengine/libraw/src/decoders/load_mfbacks.cpp +++ b/rtengine/libraw/src/decoders/load_mfbacks.cpp @@ -352,10 +352,17 @@ int LibRaw::phase_one_correct() { /* Quadrant linearization */ ushort lc[2][2][16], ref[16]; int qr, qc; + bool baddiv = false; for (qr = 0; qr < 2; qr++) - for (qc = 0; qc < 2; qc++) - for (i = 0; i < 16; i++) - lc[qr][qc][i] = get4(); + for (qc = 0; qc < 2; qc++) + { + for (i = 0; i < 16; i++) + lc[qr][qc][i] = get4(); + if (lc[qr][qc][15] == 0) + baddiv = true; + } + if(baddiv) + continue; for (i = 0; i < 16; i++) { int v = 0; diff --git a/rtengine/libraw/src/decoders/unpack_thumb.cpp b/rtengine/libraw/src/decoders/unpack_thumb.cpp index 1f01ddc12..4298c3750 100644 --- a/rtengine/libraw/src/decoders/unpack_thumb.cpp +++ b/rtengine/libraw/src/decoders/unpack_thumb.cpp @@ -266,8 +266,9 @@ int LibRaw::unpack_thumb(void) tiff_ifd[pifd].strip_byte_counts_count) { // We found it, calculate final size - unsigned total_size = 0; - for (int i = 0; i < tiff_ifd[pifd].strip_byte_counts_count; i++) + INT64 total_size = 0; + for (int i = 0; i < tiff_ifd[pifd].strip_byte_counts_count + && i < tiff_ifd[pifd].strip_offsets_count; i++) total_size += tiff_ifd[pifd].strip_byte_counts[i]; if (total_size != (unsigned)t_length) // recalculate colors { @@ -284,15 +285,15 @@ int LibRaw::unpack_thumb(void) char *dest = T.thumb; INT64 pos = ID.input->tell(); + INT64 remain = T.tlength; for (int i = 0; i < tiff_ifd[pifd].strip_byte_counts_count && i < tiff_ifd[pifd].strip_offsets_count; i++) { - int remain = T.tlength; int sz = tiff_ifd[pifd].strip_byte_counts[i]; - int off = tiff_ifd[pifd].strip_offsets[i]; - if (off >= 0 && off + sz <= ID.input->size() && sz <= remain) + INT64 off = tiff_ifd[pifd].strip_offsets[i]; + if (off >= 0 && off + sz <= ID.input->size() && sz > 0 && INT64(sz) <= remain) { ID.input->seek(off, SEEK_SET); ID.input->read(dest, sz, 1); @@ -332,13 +333,13 @@ int LibRaw::unpack_thumb(void) int o_bps = (imgdata.rawparams.options & LIBRAW_RAWOPTIONS_USE_PPM16_THUMBS) ? 2 : 1; int o_length = T.twidth * T.theight * t_colors * o_bps; int i_length = T.twidth * T.theight * t_colors * 2; - if (!T.tlength) - T.tlength = o_length; - THUMB_SIZE_CHECKTNZ(o_length); + + THUMB_SIZE_CHECKTNZ(o_length); THUMB_SIZE_CHECKTNZ(i_length); - THUMB_SIZE_CHECKTNZ(T.tlength); ushort *t_thumb = (ushort *)calloc(i_length, 1); + if (!t_thumb) + throw LIBRAW_EXCEPTION_ALLOC; ID.input->read(t_thumb, 1, i_length); if ((libraw_internal_data.unpacker_data.order == 0x4949) == (ntohs(0x1234) == 0x1234)) @@ -350,14 +351,18 @@ int LibRaw::unpack_thumb(void) { T.thumb = (char *)t_thumb; T.tformat = LIBRAW_THUMBNAIL_BITMAP16; + T.tlength = i_length; } else { T.thumb = (char *)malloc(o_length); + if (!T.thumb) + throw LIBRAW_EXCEPTION_ALLOC; for (int i = 0; i < o_length; i++) T.thumb[i] = t_thumb[i] >> 8; free(t_thumb); T.tformat = LIBRAW_THUMBNAIL_BITMAP; + T.tlength = o_length; } SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); return 0; diff --git a/rtengine/libraw/src/demosaic/xtrans_demosaic.cpp b/rtengine/libraw/src/demosaic/xtrans_demosaic.cpp index 5dbc3c3f6..2d96c62ef 100644 --- a/rtengine/libraw/src/demosaic/xtrans_demosaic.cpp +++ b/rtengine/libraw/src/demosaic/xtrans_demosaic.cpp @@ -265,6 +265,10 @@ void LibRaw::xtrans_interpolate(int passes) { rix = &rgb[0][row - top][col - left]; int h = fcol(row, col + 1); + + if (h == 1) // Incorrect pattern + break; + float diff[6]; memset(diff, 0, sizeof diff); for (int i = 1, d = 0; d < 6; d++, i ^= LIBRAW_AHD_TILE ^ 1, h ^= 2) diff --git a/rtengine/libraw/src/libraw_datastream.cpp b/rtengine/libraw/src/libraw_datastream.cpp index 898761de7..60593b42f 100644 --- a/rtengine/libraw/src/libraw_datastream.cpp +++ b/rtengine/libraw/src/libraw_datastream.cpp @@ -460,7 +460,7 @@ int LibRaw_buffer_datastream::scanf_one(const char *fmt, void *val) if (scanf_res > 0) { int xcnt = 0; - while (streampos < streamsize) + while (streampos < streamsize-1) { streampos++; xcnt++; diff --git a/rtengine/libraw/src/metadata/fuji.cpp b/rtengine/libraw/src/metadata/fuji.cpp index 4c9fe5025..feb394ef6 100644 --- a/rtengine/libraw/src/metadata/fuji.cpp +++ b/rtengine/libraw/src/metadata/fuji.cpp @@ -132,7 +132,7 @@ void LibRaw::parseAdobeRAFMakernote() } #define CHECKSPACE(s) \ - if (posPrivateMknBuf + (s) > PrivateMknLength) \ + if (INT64(posPrivateMknBuf) + INT64(s) > INT64(PrivateMknLength)) \ { \ free(PrivateMknBuf); \ return; \ @@ -209,7 +209,7 @@ void LibRaw::parseAdobeRAFMakernote() PrivateOrder = sget2(PrivateMknBuf); unsigned s, l; s = ifd_start = sget4(PrivateMknBuf +2)+6; - CHECKSPACE(ifd_start+4); + CHECKSPACE(INT64(ifd_start)+4LL); l = ifd_len = sget4(PrivateMknBuf +ifd_start); CHECKSPACE_ABS3(ifd_start, ifd_len, 4); @@ -767,7 +767,7 @@ void LibRaw::parseAdobeRAFMakernote() if (wb_section_offset) { - CHECKSPACE(wb_section_offset + 12); + CHECKSPACE(INT64(wb_section_offset) + 12LL); } if (wb_section_offset && diff --git a/rtengine/libraw/src/postprocessing/postprocessing_aux.cpp b/rtengine/libraw/src/postprocessing/postprocessing_aux.cpp index 57473400d..c8c53fa66 100644 --- a/rtengine/libraw/src/postprocessing/postprocessing_aux.cpp +++ b/rtengine/libraw/src/postprocessing/postprocessing_aux.cpp @@ -39,6 +39,7 @@ void LibRaw::wavelet_denoise() static const float noise[] = {0.8002f, 0.2735f, 0.1202f, 0.0585f, 0.0291f, 0.0152f, 0.0080f, 0.0044f}; + if (iwidth < 65 || iheight < 65) return; while (maximum << scale < 0x10000) scale++; @@ -135,6 +136,9 @@ void LibRaw::wavelet_denoise() static const float noise[] = {0.8002, 0.2735, 0.1202, 0.0585, 0.0291, 0.0152, 0.0080, 0.0044}; + if (iwidth < 65 || iheight < 65) + return; + while (maximum << scale < 0x10000) scale++; maximum <<= --scale; @@ -324,6 +328,9 @@ void LibRaw::recover_highlights() grow = pow(2.0, 4 - highlight); FORC(unsigned(colors)) hsat[c] = 32000 * pre_mul[c]; + FORC(unsigned(colors)) + if(hsat[c]<1) + return; for (kc = 0, c = 1; c < (unsigned)colors; c++) if (pre_mul[kc] < pre_mul[c]) kc = c; diff --git a/rtengine/libraw/src/preprocessing/raw2image.cpp b/rtengine/libraw/src/preprocessing/raw2image.cpp index e65e2ad73..702cf2902 100644 --- a/rtengine/libraw/src/preprocessing/raw2image.cpp +++ b/rtengine/libraw/src/preprocessing/raw2image.cpp @@ -43,6 +43,8 @@ void LibRaw::raw2image_start() // adjust for half mode! IO.shrink = + !imgdata.rawdata.color4_image && !imgdata.rawdata.color3_image && + !imgdata.rawdata.float4_image && !imgdata.rawdata.float3_image && P1.filters && (O.half_size || ((O.threshold || O.aber[0] != 1 || O.aber[2] != 1))); diff --git a/rtengine/libraw/src/tables/wblists.cpp b/rtengine/libraw/src/tables/wblists.cpp index f377cd3ec..1f8ae172b 100644 --- a/rtengine/libraw/src/tables/wblists.cpp +++ b/rtengine/libraw/src/tables/wblists.cpp @@ -17,15 +17,15 @@ #define _ARR_SZ(a) (sizeof(a)/sizeof(a[0])) -static const int _tagtype_dataunit_bytes [19] = { - 1, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 4, 2, 8, 8, 8, 8 +static const int _tagtype_dataunit_bytes [20] = { + 1, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 4, 2, 8, 8, 8, 8, 8 }; libraw_static_table_t LibRaw::tagtype_dataunit_bytes(_tagtype_dataunit_bytes, _ARR_SZ(_tagtype_dataunit_bytes)); int libraw_tagtype_dataunit_bytes(int tagtype) { - return _tagtype_dataunit_bytes[((unsigned)tagtype <= _ARR_SZ(_tagtype_dataunit_bytes)) ? tagtype : 0]; + return _tagtype_dataunit_bytes[((unsigned)tagtype < _ARR_SZ(_tagtype_dataunit_bytes)) ? tagtype : 0]; } diff --git a/rtengine/libraw/src/utils/curves.cpp b/rtengine/libraw/src/utils/curves.cpp index 03b1253bb..b14f19b79 100644 --- a/rtengine/libraw/src/utils/curves.cpp +++ b/rtengine/libraw/src/utils/curves.cpp @@ -37,8 +37,11 @@ void LibRaw::cubic_spline(const int *x_, const int *y_, const int len) } for (i = len - 1; i > 0; i--) { - b[i] = (y[i] - y[i - 1]) / (x[i] - x[i - 1]); - d[i - 1] = x[i] - x[i - 1]; + float _div = x[i] - x[i - 1]; + if (fabs(_div) < 1.0e-15) + _div = 1; + b[i] = (y[i] - y[i - 1]) / _div; + d[i - 1] = _div; } for (i = 1; i < len - 1; i++) { diff --git a/rtengine/libraw/src/utils/open.cpp b/rtengine/libraw/src/utils/open.cpp index 2adca43b5..12b0cb878 100644 --- a/rtengine/libraw/src/utils/open.cpp +++ b/rtengine/libraw/src/utils/open.cpp @@ -482,7 +482,10 @@ int LibRaw::open_datastream(LibRaw_abstract_datastream *stream) // Fuji layout files: either DNG or unpacked_load_raw should be used if (libraw_internal_data.internal_output_params.fuji_width || libraw_internal_data.unpacker_data.fuji_layout) { - if (!imgdata.idata.dng_version && load_raw != &LibRaw::unpacked_load_raw) + if (!imgdata.idata.dng_version && load_raw != &LibRaw::unpacked_load_raw + && load_raw != &LibRaw::unpacked_load_raw_FujiDBP + && load_raw != &LibRaw::unpacked_load_raw_fuji_f700s20 + ) return LIBRAW_FILE_UNSUPPORTED; } @@ -1200,9 +1203,15 @@ int LibRaw::open_datastream(LibRaw_abstract_datastream *stream) { if (C.profile) free(C.profile); - C.profile = malloc(C.profile_length); - ID.input->seek(ID.profile_offset, SEEK_SET); - ID.input->read(C.profile, C.profile_length, 1); + INT64 profile_sz = MIN(INT64(C.profile_length), ID.input->size() - ID.profile_offset); + if (profile_sz > 0LL && profile_sz < LIBRAW_MAX_PROFILE_SIZE_MB * 1024LL * 1024LL) + { + C.profile = malloc(size_t(profile_sz)); + ID.input->seek(ID.profile_offset, SEEK_SET); + ID.input->read(C.profile, size_t(profile_sz), 1); + } + else + C.profile = NULL; } SET_PROC_FLAG(LIBRAW_PROGRESS_IDENTIFY); diff --git a/rtengine/libraw/src/utils/thumb_utils.cpp b/rtengine/libraw/src/utils/thumb_utils.cpp index ffdb80247..b468b0b06 100644 --- a/rtengine/libraw/src/utils/thumb_utils.cpp +++ b/rtengine/libraw/src/utils/thumb_utils.cpp @@ -127,26 +127,36 @@ void LibRaw::kodak_thumb_loader() int(*t_hist)[LIBRAW_HISTOGRAM_SIZE] = (int(*)[LIBRAW_HISTOGRAM_SIZE])calloc(sizeof(*t_hist), 4); - float out[3], out_cam[3][4] = {{2.81761312f, -1.98369181f, 0.166078627f, 0}, - {-0.111855984f, 1.73688626f, -0.625030339f, 0}, - {-0.0379119813f, -0.891268849f, 1.92918086f, 0}}; - - for (img = imgdata.image[0], row = 0; row < S.height; row++) - for (col = 0; col < S.width; col++, img += 4) - { - out[0] = out[1] = out[2] = 0; - int c; - for (c = 0; c < 3; c++) + if (imgdata.idata.maker_index == LIBRAW_CAMERAMAKER_Canon) // Skip color conversion for canon PPM tiffs + { + for (img = imgdata.image[0], row = 0; row < S.height; row++) + for (col = 0; col < S.width; col++, img += 4) + for (int c = 0; c < P1.colors; c++) + t_hist[c][img[c] >> 3]++; + } + else + { + float out[3], out_cam[3][4] = {{2.81761312f, -1.98369181f, 0.166078627f, 0}, + {-0.111855984f, 1.73688626f, -0.625030339f, 0}, + {-0.0379119813f, -0.891268849f, 1.92918086f, 0}}; + + for (img = imgdata.image[0], row = 0; row < S.height; row++) + for (col = 0; col < S.width; col++, img += 4) { - out[0] += out_cam[0][c] * img[c]; - out[1] += out_cam[1][c] * img[c]; - out[2] += out_cam[2][c] * img[c]; + out[0] = out[1] = out[2] = 0; + int c; + for (c = 0; c < 3; c++) + { + out[0] += out_cam[0][c] * img[c]; + out[1] += out_cam[1][c] * img[c]; + out[2] += out_cam[2][c] * img[c]; + } + for (c = 0; c < 3; c++) + img[c] = CLIP((int)out[c]); + for (c = 0; c < P1.colors; c++) + t_hist[c][img[c] >> 3]++; } - for (c = 0; c < 3; c++) - img[c] = CLIP((int)out[c]); - for (c = 0; c < P1.colors; c++) - t_hist[c][img[c] >> 3]++; - } + } // from gamma_lut int(*save_hist)[LIBRAW_HISTOGRAM_SIZE] =