CVE-2019-20911 (C, published 2020-07-16T18:15Z)
Description: 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.
Severity: MEDIUM (CVSS v3 base score: 6.5)
Weakness: CWE-835 \u2014 Loop with Unreachable Exit Condition ('Infinite Loop')
The product contains an iteration or loop with an exit condition that cannot be reached, i.e., an infinite loop.
Repository: https://github.com/LibreDWG/libredwg
Files changed:
include/dwg.h
src/decode.c
src/encode.c
src/free.c
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


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)