CVE-2019-20911: Loop with Unreachable Exit Condition ('Infinite Loop') (CWE-835)
value: An issue was discovered in GNU LibreDWG through 0.9.3. Crafted input will lead to denial of service in bit_calc_CRC in bits.c, related to a for loop.
CWE description: The product contains an iteration or loop with an exit condition that cannot be reached, i.e., an infinite loop.
CVSS v3 base score: 6.5
Published: 2020-07-16T18:15Z
Repository: https://github.com/LibreDWG/libredwg
Language: C
Files changed: include/dwg.h, src/decode.c, src/encode.c, src/free.c
Commit date: 2019-12-31 21:59:38 +0100
Commit message: cleanup tio.unknown

not needed anymore, we only have UNKNOWN_OBJ or UNKNOWN_ENT with full common
entity_data.
Fixes GH #178 heap_overflow2

Diff: diff --git a/include/dwg.h b/include/dwg.h
index 4070f4ae..5fb603df 100644
--- a/include/dwg.h
+++ b/include/dwg.h
@@ -5454,11 +5454,10 @@ typedef struct _dwg_object
   Dwg_Object_Supertype supertype;
   union
   {
     Dwg_Object_Entity *entity;
     Dwg_Object_Object *object;
-    char *unknown; /* i.e. unhandled class as raw bits */
   } tio;
 
   Dwg_Handle handle;
   struct _dwg_struct *parent;
 
diff --git a/src/decode.c b/src/decode.c
index 4ed8d359..c69c57b8 100644
--- a/src/decode.c
+++ b/src/decode.c
@@ -5009,14 +5009,11 @@ dwg_decode_add_object (Dwg_Data *restrict dwg, Bit_Chain *dat,
           /* the relative offset from type after common_entity_data */
           // obj->common_size = bit_position(dat) - restartpos;
           // LOG_HANDLE("common_size: %lu\n", obj->common_size); // needed for
           // unknown
           bit_set_position (dat, restartpos);
-
-          // obj->unknown_off = obj->unknown_pos - restartpos;
-          // LOG_TRACE("Unknown pos %lu, offset %lu\n", obj->unknown_pos,
-          // obj->unknown_off);
+          obj->supertype = DWG_SUPERTYPE_UNKNOWN;
 
           if (i >= 0 && i < (int)dwg->num_classes)
             {
               klass = &dwg->dwg_class[i];
               is_entity = dwg_class_is_entity (klass);
@@ -5030,71 +5027,24 @@ dwg_decode_add_object (Dwg_Data *restrict dwg, Bit_Chain *dat,
               else
                 {
                   LOG_ERROR ("Invalid class index %d >%d", i,
                              (int)dwg->num_classes);
                 }
-              obj->supertype = DWG_SUPERTYPE_UNKNOWN;
               obj->type = 0;
               *dat = abs_dat;
               return error | DWG_ERR_VALUEOUTOFBOUNDS;
             }
           // properly dwg_decode_object/_entity for eed, reactors, xdic
-          if (klass && !is_entity)
-            {
-              int err = dwg_decode_UNKNOWN_OBJ (dat, obj);
-              error |= err;
-              obj->supertype = DWG_SUPERTYPE_UNKNOWN;
-              if (!dat)
-                return error;
-              if (err >= DWG_ERR_CRITICAL)
-                *dat = abs_dat;
-            }
-          else if (klass) // is_entity
-            {
-              int err;
-#if 0 && !defined(IS_RELEASE)
-              if (strEQc(klass->dxfname, "MULTILEADER")) { //debug CED
-                char *mleader = bit_read_TF(dat, obj->size);
-                LOG_INSANE_TF(mleader, (int)obj->size)
-                bit_set_position(dat, restartpos);
-                free (mleader);
-              }
-#endif
-              err = dwg_decode_UNKNOWN_ENT (dat, obj);
-              error |= err;
-              obj->supertype = DWG_SUPERTYPE_UNKNOWN;
-              if (!dat)
-                return error;
-              if (err >= DWG_ERR_CRITICAL)
-                *dat = abs_dat;
-            }
-          else // not a class
-            {
-              LOG_WARN ("Unknown object, skipping eed/reactors/xdic");
-              SINCE (R_2000)
-              {
-                obj->bitsize = bit_read_RL (dat);
-                LOG_TRACE ("bitsize: " FORMAT_RL " [RL] @%lu.%u\n",
-                           obj->bitsize, dat->byte-2, dat->bit);
-                if (obj->bitsize > obj->size * 8)
-                  {
-                    LOG_ERROR ("Invalid bitsize " FORMAT_RL " => " FORMAT_RL,
-                               obj->bitsize, obj->size * 8);
-                    obj->bitsize = obj->size * 8;
-                    error |= DWG_ERR_VALUEOUTOFBOUNDS;
-                  }
-              }
-              if (!bit_read_H (dat, &obj->handle))
-                {
-                  LOG_TRACE ("handle: " FORMAT_H " [H 5]\n",
-                             ARGS_H (obj->handle));
-                }
-              restartpos = dat->byte;
-              obj->supertype = DWG_SUPERTYPE_UNKNOWN;
-              obj->tio.unknown = bit_read_TF (dat, obj->size);
-              dat->byte = restartpos;
-            }
+          if (is_entity)
+              error |= dwg_decode_UNKNOWN_ENT (dat, obj);
+          else
+              error |= dwg_decode_UNKNOWN_OBJ (dat, obj);
+
+          if (!dat)
+            return error;
+          if (error >= DWG_ERR_CRITICAL)
+            *dat = abs_dat;
         }
     }
 
   if (obj->handle.value)
     { // empty only with UNKNOWN
diff --git a/src/encode.c b/src/encode.c
index 10f54b21..d29d6374 100644
--- a/src/encode.c
+++ b/src/encode.c
@@ -1968,30 +1968,14 @@ dwg_encode_add_object (Dwg_Object *restrict obj, Bit_Chain *restrict dat,
           if (klass && obj->supertype == DWG_SUPERTYPE_UNKNOWN)
             is_entity = dwg_class_is_entity (klass);
           else
             is_entity = obj->supertype == DWG_SUPERTYPE_ENTITY;
           // properly dwg_decode_object/_entity for eed, reactors, xdic
-          if (klass && !is_entity)
-            error = dwg_encode_UNKNOWN_OBJ (dat, obj);
-          else if (klass)
+          if (is_entity)
             error = dwg_encode_UNKNOWN_ENT (dat, obj);
-          else // not a class
-            {
-              LOG_WARN ("Unknown object, skipping eed/reactors/xdic");
-              error = DWG_ERR_UNHANDLEDCLASS;
-              SINCE (R_2000)
-              {
-                bit_write_RL (dat, obj->bitsize);
-                LOG_INFO ("bitsize: " FORMAT_RL " [RL] (@%lu.%u)\n", obj->bitsize,
-                          dat->byte - 4, dat->bit);
-              }
-              bit_write_H (dat, &obj->handle);
-              LOG_INFO ("handle: " FORMAT_H " [H 5]\n", ARGS_H (obj->handle));
-              // write obj->size bytes, excl. bitsize and handle.
-              // overshoot the bitsize and handle size.
-              bit_write_TF (dat, obj->tio.unknown, obj->size);
-            }
+          else
+            error = dwg_encode_UNKNOWN_OBJ (dat, obj);
         }
     }
 
   /* DXF: patchup size and bitsize */
   if (!obj->size)
diff --git a/src/free.c b/src/free.c
index cc17ace8..d9206d30 100644
--- a/src/free.c
+++ b/src/free.c
@@ -729,47 +729,15 @@ dwg_free_object (Dwg_Object *obj)
         }
 
       else if ((error = dwg_free_variable_type (obj->parent, obj))
                & DWG_ERR_UNHANDLEDCLASS)
         {
-          int is_entity;
-          int i;
-          Dwg_Class *klass;
-
         unhandled:
-          is_entity = 0;
-          i = obj->type - 500;
-          klass = NULL;
-
-          dwg = obj->parent;
-          if (dwg->dwg_class && i >= 0 && i < (int)dwg->num_classes)
-            {
-              klass = &dwg->dwg_class[i];
-              is_entity = klass ? dwg_class_is_entity (klass) : 0;
-            }
-          // indxf (and later injson) already creates some DEBUGGING classes
-          if (obj->fixedtype == DWG_TYPE_TABLE)
-            {
-              // just the preview, i.e. common. plus some colors: leak
+          if (obj->fixedtype == DWG_TYPE_UNKNOWN_ENT)
               dwg_free_UNKNOWN_ENT (dat, obj);
-            }
-          else if (obj->fixedtype == DWG_TYPE_DATATABLE)
-            {
-              dwg_free_UNKNOWN_OBJ (dat, obj);
-            }
-          else if (klass && !is_entity)
-            {
+          else if (obj->fixedtype == DWG_TYPE_UNKNOWN_OBJ)
               dwg_free_UNKNOWN_OBJ (dat, obj);
-            }
-          else if (klass && is_entity)
-            {
-              dwg_free_UNKNOWN_ENT (dat, obj);
-            }
-          else // not a class
-            {
-              FREE_IF (obj->tio.unknown);
-            }
         }
     }
   /* With this importer the dxfname is dynamic, just the name is const */
   if (dwg->opts & DWG_OPTS_INDXF)
     FREE_IF (obj->dxfname);

Vulnerable code:     char *unknown; /* i.e. unhandled class as raw bits */

          // obj->unknown_off = obj->unknown_pos - restartpos;
          // LOG_TRACE("Unknown pos %lu, offset %lu\n", obj->unknown_pos,
          // obj->unknown_off);
              obj->supertype = DWG_SUPERTYPE_UNKNOWN;
          if (klass && !is_entity)
            {
              int err = dwg_decode_UNKNOWN_OBJ (dat, obj);
              error |= err;
              obj->supertype = DWG_SUPERTYPE_UNKNOWN;
              if (!dat)
                return error;
              if (err >= DWG_ERR_CRITICAL)
                *dat = abs_dat;
            }
          else if (klass) // is_entity
            {
              int err;
#if 0 && !defined(IS_RELEASE)
              if (strEQc(klass->dxfname, "MULTILEADER")) { //debug CED
                char *mleader = bit_read_TF(dat, obj->size);
                LOG_INSANE_TF(mleader, (int)obj->size)
                bit_set_position(dat, restartpos);
                free (mleader);
              }
#endif
              err = dwg_decode_UNKNOWN_ENT (dat, obj);
              error |= err;
              obj->supertype = DWG_SUPERTYPE_UNKNOWN;
              if (!dat)
                return error;
              if (err >= DWG_ERR_CRITICAL)
                *dat = abs_dat;
            }
          else // not a class
            {
              LOG_WARN ("Unknown object, skipping eed/reactors/xdic");
              SINCE (R_2000)
              {
                obj->bitsize = bit_read_RL (dat);
                LOG_TRACE ("bitsize: " FORMAT_RL " [RL] @%lu.%u\n",
                           obj->bitsize, dat->byte-2, dat->bit);
                if (obj->bitsize > obj->size * 8)
                  {
                    LOG_ERROR ("Invalid bitsize " FORMAT_RL " => " FORMAT_RL,
                               obj->bitsize, obj->size * 8);
                    obj->bitsize = obj->size * 8;
                    error |= DWG_ERR_VALUEOUTOFBOUNDS;
                  }
              }
              if (!bit_read_H (dat, &obj->handle))
                {
                  LOG_TRACE ("handle: " FORMAT_H " [H 5]\n",
                             ARGS_H (obj->handle));
                }
              restartpos = dat->byte;
              obj->supertype = DWG_SUPERTYPE_UNKNOWN;
              obj->tio.unknown = bit_read_TF (dat, obj->size);
              dat->byte = restartpos;
            }
          if (klass && !is_entity)
            error = dwg_encode_UNKNOWN_OBJ (dat, obj);
          else if (klass)
          else // not a class
            {
              LOG_WARN ("Unknown object, skipping eed/reactors/xdic");
              error = DWG_ERR_UNHANDLEDCLASS;
              SINCE (R_2000)
              {
                bit_write_RL (dat, obj->bitsize);
                LOG_INFO ("bitsize: " FORMAT_RL " [RL] (@%lu.%u)\n", obj->bitsize,
                          dat->byte - 4, dat->bit);
              }
              bit_write_H (dat, &obj->handle);
              LOG_INFO ("handle: " FORMAT_H " [H 5]\n", ARGS_H (obj->handle));
              // write obj->size bytes, excl. bitsize and handle.
              // overshoot the bitsize and handle size.
              bit_write_TF (dat, obj->tio.unknown, obj->size);
            }
          int is_entity;
          int i;
          Dwg_Class *klass;

          is_entity = 0;
          i = obj->type - 500;
          klass = NULL;

          dwg = obj->parent;
          if (dwg->dwg_class && i >= 0 && i < (int)dwg->num_classes)
            {
              klass = &dwg->dwg_class[i];
              is_entity = klass ? dwg_class_is_entity (klass) : 0;
            }
          // indxf (and later injson) already creates some DEBUGGING classes
          if (obj->fixedtype == DWG_TYPE_TABLE)
            {
              // just the preview, i.e. common. plus some colors: leak
            }
          else if (obj->fixedtype == DWG_TYPE_DATATABLE)
            {
              dwg_free_UNKNOWN_OBJ (dat, obj);
            }
          else if (klass && !is_entity)
            {
            }
          else if (klass && is_entity)
            {
              dwg_free_UNKNOWN_ENT (dat, obj);
            }
          else // not a class
            {
              FREE_IF (obj->tio.unknown);
            }
Fixed code:           obj->supertype = DWG_SUPERTYPE_UNKNOWN;
          if (is_entity)
              error |= dwg_decode_UNKNOWN_ENT (dat, obj);
          else
              error |= dwg_decode_UNKNOWN_OBJ (dat, obj);

          if (!dat)
            return error;
          if (error >= DWG_ERR_CRITICAL)
            *dat = abs_dat;
          if (is_entity)
          else
            error = dwg_encode_UNKNOWN_OBJ (dat, obj);
          if (obj->fixedtype == DWG_TYPE_UNKNOWN_ENT)
          else if (obj->fixedtype == DWG_TYPE_UNKNOWN_OBJ)