CVE-2019-20913: Out-of-bounds Read (CWE-125)
value: An issue was discovered in GNU LibreDWG through 0.9.3. Crafted input will lead to a heap-based buffer over-read in dwg_encode_entity in common_entity_data.spec.
CWE description: The product reads data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 8.1
Published: 2020-07-16T18:15Z
Repository: https://github.com/LibreDWG/libredwg
Language: Other
Files changed: src/classes.inc, src/dec_macros.h
Commit date: 2020-01-02 10:16:26 +0100
Commit message: add DEBUGGING_CLASS_CPP

and use it for TABLECONTENT.
This is more stable than CLASS_DXF in cases when
TABLE is mixed up with TABLECONTENT. See e.g.
GH #178, where it fixes the heap_overflow2 case.

Diff: diff --git a/src/classes.inc b/src/classes.inc
index 6ac31abcc..20a3ffcb0 100644
--- a/src/classes.inc
+++ b/src/classes.inc
@@ -51,14 +51,16 @@
 
 #ifdef DEBUG_CLASSES
 # define DEBUGGING_DXF(action, name)                 ALLOW_DXF(action, name)
 # define DEBUGGING_CLASS(action, name)               UNSTABLE_CLASS(action, name)
 # define DEBUGGING_CLASS_DXF(action, name, _dxfname) UNSTABLE_CLASS_DXF(action, name, _dxfname)
+# define DEBUGGING_CLASS_CPP(action, name, _cppname) UNSTABLE_CLASS_CPP(action, name, _cppname)
 #else
 # define DEBUGGING_DXF(action, name)                 DISALLOW_DXF(action, name)
 # define DEBUGGING_CLASS(action, name)               UNHANDLED_CLASS(action, name)
 # define DEBUGGING_CLASS_DXF(action, name, _dxfname) UNHANDLED_CLASS_DXF(action, name, _dxfname)
+# define DEBUGGING_CLASS_CPP(action, name, _cppname) UNHANDLED_CLASS_CPP(action, name, _cppname)
 #endif
 
 //#define _DWG_FUNC_N(action,name) dwg_ ## action ## _ ## name
 //#define DWG_FUNC_N(action,name) _DWG_FUNC_N(action,name)
 
@@ -121,34 +123,40 @@
       if (strEQc (_STR(action), "decode") || !memcmp (_STR(action), "in", 2)) { \
         obj->name = (char*) #_name; \
         obj->dxfname = (char*) #_name; \
         obj->fixedtype = DWG_TYPE_##_name; \
       } \
-      return DEBUGGING_DXF(action, name) DWG_FUNC_N(action,_name)(dat, obj); \
+      return DEBUGGING_DXF(action, name) DWG_FUNC_N(action,_name) (dat, obj); \
     }
 #define UNHANDLED_CLASS(action, _name) \
   if (klass->dxfname && strEQc (klass->dxfname, #_name)) \
     { \
       WARN_UNHANDLED_CLASS; \
       if (strEQc (_STR(action), "decode") || !memcmp (_STR(action), "in", 2)) { \
         obj->name = (char*) #_name; \
         obj->dxfname = (char*) #_name; \
-        /*obj->fixedtype = DWG_TYPE_##_name; */ \
       } \
-      /* return dwg_##action_##_name(dat, obj); */ \
       return DWG_ERR_UNHANDLEDCLASS; \
     }
 #define UNHANDLED_CLASS_DXF(action, _name, _dxfname) \
   if (strEQc (klass->dxfname, #_dxfname)) \
     { \
       WARN_UNHANDLED_CLASS; \
       if (strEQc (_STR(action), "decode") || !memcmp (_STR(action), "in", 2)) { \
         obj->name = (char*) #_name; \
         obj->dxfname = (char*) #_dxfname; \
-        /*obj->fixedtype = DWG_TYPE_##_name; */ \
       } \
-      /* return dwg_##action_##name(dat, obj); */ \
+      return DWG_ERR_UNHANDLEDCLASS; \
+    }
+#define UNHANDLED_CLASS_CPP(action, _name, _cppname) \
+  if (klass->cppname && strEQc (klass->cppname, #_cppname)) \
+    { \
+      WARN_UNHANDLED_CLASS; \
+      if (strEQc (_STR(action), "decode") || !memcmp (_STR(action), "in", 2)) { \
+        obj->name = (char*) #_name; \
+        obj->dxfname = (char*) #_name; \
+      } \
       return DWG_ERR_UNHANDLEDCLASS; \
     }
 
   /* Entities */
   STABLE_CLASS    (ACTION, CAMERA)    /*ent, not persistent in a DWG */
@@ -168,13 +176,13 @@
   STABLE_CLASS    (ACTION, HATCH)
   STABLE_CLASS    (ACTION, IDBUFFER)
   STABLE_CLASS    (ACTION, IMAGEDEF)
   STABLE_CLASS    (ACTION, IMAGEDEF_REACTOR)
   STABLE_CLASS    (ACTION, LAYER_INDEX)
-  STABLE_CLASS    (ACTION, LAYOUT)
+  STABLE_CLASS    (ACTION, LAYOUT) // TODO bottom_margin nan
   STABLE_CLASS    (ACTION, LWPOLYLINE)
-  STABLE_CLASS    (ACTION, MLEADERSTYLE)
+  STABLE_CLASS    (ACTION, MLEADERSTYLE) // TODO block_rotation nan
   STABLE_CLASS    (ACTION, OBJECTCONTEXTDATA)
   STABLE_CLASS_CPP(ACTION, OBJECTCONTEXTDATA, AcDbObjectContextData)
   STABLE_CLASS_DXF(ACTION, PLACEHOLDER, ACDBPLACEHOLDER)
   STABLE_CLASS    (ACTION, RASTERVARIABLES)
   STABLE_CLASS    (ACTION, SCALE)
@@ -217,12 +225,12 @@
   DEBUGGING_CLASS     (ACTION, EXTRUDEDSURFACE)   /*ent */
   DEBUGGING_CLASS     (ACTION, LOFTEDSURFACE)     /*ent */
   DEBUGGING_CLASS     (ACTION, REVOLVEDSURFACE)   /*ent */
   DEBUGGING_CLASS     (ACTION, SWEPTSURFACE)      /*ent */
   DEBUGGING_CLASS_DXF (ACTION, TABLE, ACAD_TABLE) /*ent, r2010+ needs subclassing */
-  DEBUGGING_CLASS     (ACTION, ARC_DIMENSION) //ent
-  DEBUGGING_CLASS     (ACTION, TABLECONTENT) //wrong values
+  DEBUGGING_CLASS     (ACTION, ARC_DIMENSION)     /*ent */
+  DEBUGGING_CLASS_CPP (ACTION, TABLECONTENT, AcDbTableContent)
   DEBUGGING_CLASS     (ACTION, TABLEGEOMETRY) //wrong geom_data
   DEBUGGING_CLASS     (ACTION, CELLSTYLEMAP) //broken
   DEBUGGING_CLASS     (ACTION, MATERIAL)     //working on
   DEBUGGING_CLASS     (ACTION, PLOTSETTINGS) //yet unsorted
   DEBUGGING_CLASS     (ACTION, SUN)          //90%
diff --git a/src/dec_macros.h b/src/dec_macros.h
index ac00adcf3..f2814cc10 100644
--- a/src/dec_macros.h
+++ b/src/dec_macros.h
@@ -1234,12 +1234,12 @@
     {                                                                         \
       Bit_Chain obj_dat, str_dat, hdl_dat;                                    \
       obj_dat = *dat;                                                         \
       hdl_dat = *dat;                                                         \
       str_dat = *dat;                                                         \
-      error                                                                   \
-          = dwg_decode_##token##_private (&obj_dat, &hdl_dat, &str_dat, obj); \
+      error = dwg_decode_##token##_private (&obj_dat, &hdl_dat, &str_dat,     \
+                                            obj);                             \
     }                                                                         \
     else { error = dwg_decode_##token##_private (dat, dat, dat, obj); }       \
     return error;                                                             \
   }                                                                           \
                                                                               \

Vulnerable code:       return DEBUGGING_DXF(action, name) DWG_FUNC_N(action,_name)(dat, obj); \
        /*obj->fixedtype = DWG_TYPE_##_name; */ \
      /* return dwg_##action_##_name(dat, obj); */ \
        /*obj->fixedtype = DWG_TYPE_##_name; */ \
      /* return dwg_##action_##name(dat, obj); */ \
  STABLE_CLASS    (ACTION, LAYOUT)
  STABLE_CLASS    (ACTION, MLEADERSTYLE)
  DEBUGGING_CLASS     (ACTION, ARC_DIMENSION) //ent
  DEBUGGING_CLASS     (ACTION, TABLECONTENT) //wrong values
      error                                                                   \
          = dwg_decode_##token##_private (&obj_dat, &hdl_dat, &str_dat, obj); \
Fixed code: # define DEBUGGING_CLASS_CPP(action, name, _cppname) UNSTABLE_CLASS_CPP(action, name, _cppname)
# define DEBUGGING_CLASS_CPP(action, name, _cppname) UNHANDLED_CLASS_CPP(action, name, _cppname)
      return DEBUGGING_DXF(action, name) DWG_FUNC_N(action,_name) (dat, obj); \
      return DWG_ERR_UNHANDLEDCLASS; \
    }
#define UNHANDLED_CLASS_CPP(action, _name, _cppname) \
  if (klass->cppname && strEQc (klass->cppname, #_cppname)) \
    { \
      WARN_UNHANDLED_CLASS; \
      if (strEQc (_STR(action), "decode") || !memcmp (_STR(action), "in", 2)) { \
        obj->name = (char*) #_name; \
        obj->dxfname = (char*) #_name; \
      } \
  STABLE_CLASS    (ACTION, LAYOUT) // TODO bottom_margin nan
  STABLE_CLASS    (ACTION, MLEADERSTYLE) // TODO block_rotation nan
  DEBUGGING_CLASS     (ACTION, ARC_DIMENSION)     /*ent */
  DEBUGGING_CLASS_CPP (ACTION, TABLECONTENT, AcDbTableContent)
      error = dwg_decode_##token##_private (&obj_dat, &hdl_dat, &str_dat,     \
                                            obj);                             \