CVE-2021-36080 (published 2021-07-01T03:15Z)

GNU LibreDWG 0.12.3.4163 through 0.12.3.4191 has a double-free in bit_chain_free (called from dwg_encode_MTEXT and dwg_encode_add_object).

Severity: MEDIUM
CVSS v2 base score: 6.8 (AV:N/AC:M/Au:N/C:P/I:P/A:P)
CVSS v3 base score: 8.8, HIGH (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-415
cwe_name: Double Free
description: The product calls free() twice on the same memory address, potentially leading to modification of unexpected memory locations.
extended_description: When a program calls free() twice with the same argument, the program's memory management data structures become corrupted. This corruption can cause the program to crash or, in some circumstances, cause two later calls to malloc() to return the same pointer. If malloc() returns the same value twice and the program later gives the attacker control over the data that is written into this doubly-allocated memory, the program becomes vulnerable to a buffer overflow attack.
         

Fix information:
repo_url: https://github.com/LibreDWG/libredwg
commit_details: repo_url: https://github.com/LibreDWG/libredwg
author: Reini Urban
author_date: 2021-03-06 22:18:23+01:00
msg: encode: avoid hdl_dat double-free

In case of an handle overflow, such as num_reactors.
Fixes oss-fuzz issue 31724.
repository: repo_url: https://github.com/LibreDWG/libredwg
repo_name: LibreDWG/libredwg
description: Official mirror of libredwg. With CI hooks and nightly releases. PR's ok
repo_language: C
owner: LibreDWG
file_changes: filename: encode.c
change_type: ModificationType.MODIFY
diff: @@ -731,6 +731,7 @@ static bool env_var_checked_p;
         obj_flush_hdlstream (obj, dat, &dat1); /* special accumulated */      \
         bit_chain_free (&dat1);                                               \
         bit_chain_free (&dat2);                                               \
+        *hdl_dat = *dat;                                                      \
         hdl_dat = dat;                                                        \
       }                                                                       \
     else                                                                      \
@@ -830,30 +831,35 @@ EXPORT long dwg_add_##token (Dwg_Data * dwg)     \
     int error;                                                                \
     Bit_Chain _hdl_dat = { 0 };                                               \
     Bit_Chain *hdl_dat = &_hdl_dat; /* a new copy */                          \
-    Bit_Chain *str_dat = dat; /* a ref */                                     \
+    Bit_Chain *str_dat = dat;       /* a ref */                               \
     LOG_INFO ("Encode entity " #token "\n");                                  \
     bit_chain_init_dat (hdl_dat, 128, dat);                                   \
     error = dwg_encode_entity (obj, dat, hdl_dat, str_dat);                   \
     if (error)                                                                \
       {                                                                       \
-        if (hdl_dat != dat)                                                   \
+        LOG_HANDLE ("Early DWG_ENTITY exit\n");                               \
+        if (hdl_dat != dat && hdl_dat->chain != dat->chain)                   \
           bit_chain_free (hdl_dat);                                           \
         return error;                                                         \
       }                                                                       \
     error = dwg_encode_##token##_private (dat, hdl_dat, str_dat, obj);        \
-    if (error & DWG_ERR_VALUEOUTOFBOUNDS && hdl_dat != dat)                   \
-      bit_chain_free (hdl_dat);                                               \
+    if (error & DWG_ERR_VALUEOUTOFBOUNDS && hdl_dat != dat                    \
+        && hdl_dat->chain != dat->chain)                                      \
+      {                                                                       \
+        LOG_HANDLE ("VALUEOUTOFBOUNDS bypassed DWG_ENTITY_END\n");            \
+        /*bit_chain_free (hdl_dat);*/                                         \
+      }                                                                       \
     return error;                                                             \
   }                                                                           \
   static int dwg_encode_##token##_private (                                   \
-        Bit_Chain *dat, Bit_Chain *hdl_dat, Bit_Chain *str_dat,               \
-        Dwg_Object *restrict obj)                                             \
+      Bit_Chain *dat, Bit_Chain *hdl_dat, Bit_Chain *str_dat,                 \
+      Dwg_Object *restrict obj)                                               \
   {                                                                           \
     int error = 0;                                                            \
     BITCODE_BL vcount, rcount3, rcount4;                                      \
     Dwg_Data *dwg = obj->parent;                                              \
     Dwg_Object_Entity *_ent = obj->tio.entity;                                \
-    Dwg_Entity_##token *_obj = _ent->tio.token;                               \
+    Dwg_Entity_##token *_obj = _ent->tio.token;
 
 #define DWG_ENTITY_END                                                        \
     if (hdl_dat->byte > dat->byte)                                            \
@@ -861,7 +867,7 @@ EXPORT long dwg_add_##token (Dwg_Data * dwg)     \
         dat->byte = hdl_dat->byte;                                            \
         dat->bit = hdl_dat->bit;                                              \
       }                                                                       \
-    if (hdl_dat != dat)                                                       \
+    if (hdl_dat != dat && hdl_dat->chain != dat->chain)                       \
       bit_chain_free (hdl_dat);                                               \
     return error;                                                             \
   }
@@ -891,7 +897,8 @@ EXPORT long dwg_add_##token (Dwg_Data * dwg)     \
         return error;                                                         \
       }                                                                       \
     error = dwg_encode_##token##_private (dat, hdl_dat, str_dat, obj);        \
-    if (error & DWG_ERR_VALUEOUTOFBOUNDS && hdl_dat != dat)                   \
+    if (error & DWG_ERR_VALUEOUTOFBOUNDS && hdl_dat != dat                    \
+        && hdl_dat->chain != dat->chain)                                      \
       bit_chain_free (hdl_dat);                                               \
     return error;                                                             \
   }                                                                           \
@@ -915,7 +922,7 @@ EXPORT long dwg_add_##token (Dwg_Data * dwg)     \
         dat->byte = hdl_dat->byte;                                            \
         dat->bit = hdl_dat->bit;                                              \
       }                                                                       \
-    if (hdl_dat != dat)                                                       \
+    if (hdl_dat != dat && hdl_dat->chain != dat->chain)                       \
       bit_chain_free (hdl_dat);                                               \
     return error;                                                             \
   }

programming_language: C