From 27a750ecf545f379f3cafd0a056599108dc1093f Mon Sep 17 00:00:00 2001 From: cDc Date: Mon, 17 Nov 2025 18:47:27 +0200 Subject: [PATCH] Robust parsing if missing offset --- .gitignore | 1 + TinyEXIF.cpp | 16 +++++++++------- TinyEXIF.h | 4 ++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index d9cc1b7..d609422 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,4 @@ CMakeSettings.json .vscode/ bin/ binaries/ +make/ diff --git a/TinyEXIF.cpp b/TinyEXIF.cpp index 54bafd2..f39695a 100644 --- a/TinyEXIF.cpp +++ b/TinyEXIF.cpp @@ -945,15 +945,17 @@ int EXIFInfo::parseFromEXIFSegment(const uint8_t* buf, unsigned len) { // entries in the section. The last 4 bytes of the IFD contain an offset // to the next IFD, which means this IFD must contain exactly 6 + 12 * num // bytes of data. + // Note that it's possible that the next IFD offset doesn't exist, + // so here the last 4 bytes are considered optional. if (offs + 2 > len) return PARSE_CORRUPT_DATA; - int num_entries = EntryParser::parse16(buf + offs, alignIntel); - if (offs + 6 + 12 * num_entries > len) + unsigned num_entries = EntryParser::parse16(buf + offs, alignIntel); + if (offs + 2 + 12 * num_entries > len) return PARSE_CORRUPT_DATA; unsigned exif_sub_ifd_offset = len; unsigned gps_sub_ifd_offset = len; parser.Init(offs+2); - while (--num_entries >= 0) { + while (num_entries-- > 0) { parser.ParseTag(); parseIFDImage(parser, exif_sub_ifd_offset, gps_sub_ifd_offset); } @@ -965,10 +967,10 @@ int EXIFInfo::parseFromEXIFSegment(const uint8_t* buf, unsigned len) { if (exif_sub_ifd_offset + 4 <= len) { offs = exif_sub_ifd_offset; num_entries = EntryParser::parse16(buf + offs, alignIntel); - if (offs + 6 + 12 * num_entries > len) + if (offs + 2 + 12 * num_entries > len) return PARSE_CORRUPT_DATA; parser.Init(offs+2); - while (--num_entries >= 0) { + while (num_entries-- > 0) { parser.ParseTag(); parseIFDExif(parser); } @@ -979,10 +981,10 @@ int EXIFInfo::parseFromEXIFSegment(const uint8_t* buf, unsigned len) { if (gps_sub_ifd_offset + 4 <= len) { offs = gps_sub_ifd_offset; num_entries = EntryParser::parse16(buf + offs, alignIntel); - if (offs + 6 + 12 * num_entries > len) + if (offs + 2 + 12 * num_entries > len) return PARSE_CORRUPT_DATA; parser.Init(offs+2); - while (--num_entries >= 0) { + while (num_entries-- > 0) { parser.ParseTag(); parseIFDGPS(parser); } diff --git a/TinyEXIF.h b/TinyEXIF.h index 798a656..8b07877 100644 --- a/TinyEXIF.h +++ b/TinyEXIF.h @@ -294,13 +294,13 @@ public: bool hasSpeed() const; // Return true if (speedX,speedY,speedZ) is available bool hasAccuracy() const; // Return true if (accuracyXY,accuracyZ) is available } GeoLocation; - struct TINYEXIF_LIB GPano_t { // Spherical metadata. https://developers.google.com/streetview/spherical-metadata + struct TINYEXIF_LIB GPano_t { // Spherical metadata. https://developers.google.com/streetview/spherical-metadata double PosePitchDegrees; // Pitch, measured in degrees above the horizon, for the center in the image. Value must be >= -90 and <= 90. double PoseRollDegrees; // Roll, measured in degrees, of the image where level with the horizon is 0. As roll increases, the horizon rotates counterclockwise in the image. Value must be > -180 and <= 180. bool hasPosePitchDegrees() const; // Return true if PosePitchDegrees is available bool hasPoseRollDegrees() const; // Return true if PoseRollDegrees is available } GPano; - struct TINYEXIF_LIB MicroVideo_t { // Google camera video file in metadata + struct TINYEXIF_LIB MicroVideo_t { // Google camera video file in metadata uint32_t HasMicroVideo; // not zero if exists uint32_t MicroVideoVersion; // just regularinfo uint32_t MicroVideoOffset; // offset from end of file