File libEMF-1.0.7-SLE12-CVE-2020-13999-int-overflow-and-DOS.patch of Package libEMF.25625

diff --git a/libemf/libemf.cpp b/libemf/libemf.cpp
index 3d67d2c..8475f2a 100644
--- a/libemf/libemf.cpp
+++ b/libemf/libemf.cpp
@@ -23,6 +23,20 @@
 
 #include "libemf.h"
 
+/* GCC 4.8 (that we are using in SLE-12) does not have '__builtin_smul_overflow'.
+ * We need to roll our own.
+ * Returns TRUE if overflow occurred.
+ */
+static bool smul_overflow(int a, int b, int *res)
+{
+  *res = a * b;
+  if ((a == 0) || (b == 0))
+    return false;
+  if (*res / a == b)
+    return false;
+  return true;
+}
+
 namespace EMF {
 
   const char PADDING::padding_[4] = { 0, 0, 0, 0 };
@@ -1637,11 +1651,33 @@ extern "C" {
   BOOL ScaleViewportExtEx ( HDC context, INT x_num, INT x_den,
 			    INT y_num, INT y_den, LPSIZE size )
   {
+    // Avoid obvious nonsense results.
+    if ( x_num == 0 or x_den == 0 or y_num == 0 or y_den == 0 ) return FALSE;
+
     EMF::METAFILEDEVICECONTEXT* dc =
       dynamic_cast<EMF::METAFILEDEVICECONTEXT*>(EMF::globalObjects.find( context ));
 
     if ( dc == 0 ) return FALSE;
 
+    // Documentation says the numerator is computed first.
+    // Can we perform this operation? Numerator must not overflow and
+    // if it is negative, division must not overflow.
+    INT num{0};
+    if ( smul_overflow( dc->viewport_ext.cx, x_num, &num ) ) {
+      return FALSE;
+    }
+    if ( num == INT_MIN and x_den == -1 ) {
+      return FALSE;
+    }
+    INT x_ext{ num / x_den };
+    if ( smul_overflow( dc->viewport_ext.cy, y_num, &num ) ) {
+      return FALSE;
+    }
+    if ( num == INT_MIN and y_den == -1 ) {
+      return FALSE;
+    }
+    INT y_ext{ num / y_den };
+
     EMF::EMRSCALEVIEWPORTEXTEX* scaleviewportextex =
       new EMF::EMRSCALEVIEWPORTEXTEX( x_num, x_den, y_num, y_den );
 
@@ -1650,8 +1686,8 @@ extern "C" {
     if ( size != 0 )
       *size = dc->viewport_ext;
 
-    dc->viewport_ext.cx = dc->viewport_ext.cx * x_num / x_den;
-    dc->viewport_ext.cy = dc->viewport_ext.cy * y_num / y_den;
+    dc->viewport_ext.cx = x_ext;
+    dc->viewport_ext.cy = y_ext;
 
     return TRUE;
   }
@@ -1722,6 +1758,25 @@ extern "C" {
 
     if ( dc == 0 ) return FALSE;
 
+    // Documentation says the numerator is computed first.
+    // Can we perform this operation? Numerator must not overflow and
+    // if it is negative, division must not overflow.
+    INT num{0};
+    if ( smul_overflow( dc->window_ext.cx, x_num, &num ) ) {
+      return FALSE;
+    }
+    if ( num == INT_MIN and x_den == -1 ) {
+      return FALSE;
+    }
+    INT x_ext{ num / x_den };
+    if ( smul_overflow( dc->window_ext.cy, y_num, &num ) ) {
+      return FALSE;
+    }
+    if ( num == INT_MIN and y_den == -1 ) {
+      return FALSE;
+    }
+    INT y_ext{ num / y_den };
+
     EMF::EMRSCALEWINDOWEXTEX* scalewindowextex =
       new EMF::EMRSCALEWINDOWEXTEX( x_num, x_den, y_num, y_den );
 
@@ -1730,8 +1785,8 @@ extern "C" {
     if ( size != 0 )
       *size = dc->window_ext;
 
-    dc->window_ext.cx = dc->window_ext.cx * x_num / x_den;
-    dc->window_ext.cy = dc->window_ext.cy * y_num / y_den;
+    dc->window_ext.cx = x_ext;
+    dc->window_ext.cy = y_ext;
 
     return TRUE;
   }
openSUSE Build Service is sponsored by