CVE-2020-19498: Insufficient Information (NVD-CWE-noinfo)
value: Floating point exception in function Fraction in libheif 1.4.0, allows attackers to cause a Denial of Service or possibly other unspecified impacts.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
CVSS v3 base score: 8.8
Published: 2021-07-21T18:15Z
Repository: https://github.com/strukturag/libheif
Language: C++
Files changed: libheif/box.cc, libheif/heif_limits.h
Commit date: 2019-08-02 17:39:36 +0200
Commit message: force fraction to a limited resolution to finally solve those pesky numerical edge cases

Diff: diff --git a/libheif/box.cc b/libheif/box.cc
index 4a456e4..350e2c0 100644
--- a/libheif/box.cc
+++ b/libheif/box.cc
@@ -38,58 +38,24 @@ using namespace heif;
 
 heif::Error heif::Error::Ok(heif_error_Ok);
 
 
 
-static int32_t gcd(int a, int b)
-{
-  if (a == 0 && b == 0) {
-    return 1;
-  }
-
-  if (a == 0) return b;
-  if (b == 0) return a;
-
-  int32_t h;
-
-  do {
-    h = a % b;
-    a = b;
-    b = h;
-  } while (b != 0);
-
-  return a;
-}
-
-
 Fraction::Fraction(int32_t num,int32_t den)
 {
-  int32_t g = gcd(num, den);
-
-  // these strange tests are for catching the case that we divide -2147483648 by -1,
-  // which would exceed the maximum positive value by one.
-
-  if (num == std::numeric_limits<int32_t>::min() && g == -1) {
-    num++;
-  }
-
-  if (den == std::numeric_limits<int32_t>::min() && g == -1) {
-    den++;
-  }
-
-
-  numerator = num / g;
-  denominator = den / g;
-
-
   // Reduce resolution of fraction until we are in a safe range.
   // We need this as adding fractions may lead to very large denominators
   // (e.g. 0x10000 * 0x10000 > 0x100000000 -> overflow, leading to integer 0)
 
-  while (denominator > MAX_FRACTION_DENOMINATOR) {
-    numerator >>= 1;
-    denominator >>= 1;
+  while (denominator > MAX_FRACTION_VALUE || denominator < -MAX_FRACTION_VALUE) {
+    numerator /= 2;
+    denominator /= 2;
+  }
+
+  while (numerator > MAX_FRACTION_VALUE || numerator < -MAX_FRACTION_VALUE) {
+    numerator /= 2;
+    denominator /= 2;
   }
 }
 
 Fraction Fraction::operator+(const Fraction& b) const
 {
diff --git a/libheif/heif_limits.h b/libheif/heif_limits.h
index 8a05e9e..129562e 100644
--- a/libheif/heif_limits.h
+++ b/libheif/heif_limits.h
@@ -45,8 +45,8 @@ static const int MAX_IMAGE_HEIGHT = 16384;
 static const int MAX_BOX_NESTING_LEVEL = 20;
 
 static const int MAX_BOX_SIZE = 0x7FFFFFFF; // 2 GB
 static const int64_t MAX_LARGE_BOX_SIZE = 0x0FFFFFFFFFFFFFFF;
 static const int64_t MAX_FILE_POS = 0x007FFFFFFFFFFFFFLL; // maximum file position
-static const int MAX_FRACTION_DENOMINATOR = 0x10000;
+static const int MAX_FRACTION_VALUE = 0x10000;
 
 #endif  // LIBHEIF_HEIF_LIMITS_H

Vulnerable code: static int32_t gcd(int a, int b)
{
  if (a == 0 && b == 0) {
    return 1;
  }

  if (a == 0) return b;
  if (b == 0) return a;

  int32_t h;

  do {
    h = a % b;
    a = b;
    b = h;
  } while (b != 0);

  return a;
}


  int32_t g = gcd(num, den);

  // these strange tests are for catching the case that we divide -2147483648 by -1,
  // which would exceed the maximum positive value by one.

  if (num == std::numeric_limits<int32_t>::min() && g == -1) {
    num++;
  }

  if (den == std::numeric_limits<int32_t>::min() && g == -1) {
    den++;
  }


  numerator = num / g;
  denominator = den / g;


  while (denominator > MAX_FRACTION_DENOMINATOR) {
    numerator >>= 1;
    denominator >>= 1;
static const int MAX_FRACTION_DENOMINATOR = 0x10000;
Fixed code:   while (denominator > MAX_FRACTION_VALUE || denominator < -MAX_FRACTION_VALUE) {
    numerator /= 2;
    denominator /= 2;
  }

  while (numerator > MAX_FRACTION_VALUE || numerator < -MAX_FRACTION_VALUE) {
    numerator /= 2;
    denominator /= 2;
static const int MAX_FRACTION_VALUE = 0x10000;