From 404e6b1b14f60c81388d50b4239f81d461b3c3ad Mon Sep 17 00:00:00 2001
From: David Anderson <davea42@linuxmail.org>
Date: Sat, 17 Feb 2024 13:33:39 -0800
Subject: [PATCH] Fixing DW202402-002, corrupt object caused various libdwarf
 crashes with some tailored/fuzzed object files. 	modified:  
 src/lib/libdwarf/dwarf_alloc.c 	modified:  
 src/lib/libdwarf/dwarf_error.c

Origin: https://github.com/davea42/libdwarf-code/commit/404e6b1b14f60c81388d50b4239f81d461b3c3ad

---
 src/lib/libdwarf/dwarf_alloc.c | 56 ++++++++++++++++++++++++++++++++--
 src/lib/libdwarf/dwarf_error.c |  5 +--
 2 files changed, 57 insertions(+), 4 deletions(-)

diff --git a/src/lib/libdwarf/dwarf_alloc.c b/src/lib/libdwarf/dwarf_alloc.c
index 9ef9b16f4..a73b8abf9 100644
--- a/src/lib/libdwarf/dwarf_alloc.c
+++ b/src/lib/libdwarf/dwarf_alloc.c
@@ -143,6 +143,7 @@ _dwarf_error_destructor(void *m)
 #if DEBUG_ALLOC
     printf("libdwarfdetector DEALLOC Now destruct error "
         "string %s\n",dwarfstring_string(erm));
+    fflush(stdout);
 #endif /* DEBUG_ALLOC */
     dwarfstring_destructor(erm);
     free(erm);
@@ -182,6 +183,8 @@ struct reserve_data_s {
 
 #define STATIC_ALLOWED 10 /* arbitrary, must be > 2, see below*/
 static unsigned static_used = 0;
+/*  entries in this list point to allocations of
+    type DW_DLA_ERROR. */
 static Dwarf_Error staticerrlist[STATIC_ALLOWED];
 
 /*  Clean this out if found */
@@ -215,7 +218,7 @@ dw_empty_errlist_item(Dwarf_Error e_in)
     }
 }
 
-/*  If the userr calls dwarf_dealloc on an error
+/*  If the user calls dwarf_dealloc on an error
     out of a dwarf_init*() call, this will find
     it in the static err list. Here dbg is NULL
     so not mentioned.  */
@@ -226,11 +229,21 @@ _dwarf_add_to_static_err_list(Dwarf_Error error)
     if (!error) {
         return;
     }
+#ifdef DEBUG_ALLOC
+    printf("\nlibdwarfdetector add to static err list "
+        " 0x%lx\n",(unsigned long)(uintptr_t)error);
+    fflush(stdout);
+#endif /* DEBUG_ALLOC */
     for ( ; i <static_used; ++i) {
         Dwarf_Error e = staticerrlist[i];
         if (e) {
             continue;
         }
+#ifdef DEBUG_ALLOC
+        printf("libdwarfdetector add to static err list at %u\n",
+            i);
+        fflush(stdout);
+#endif /* DEBUG_ALLOC */
         staticerrlist[i] = error;
         return;
     }
@@ -239,6 +252,38 @@ _dwarf_add_to_static_err_list(Dwarf_Error error)
         ++static_used;
     }
 }
+/*  See libdwarf vulnerability DW202402-002
+    for the motivation.
+*/
+static void
+_dwarf_remove_from_staticerrlist(Dwarf_Ptr *space)
+{
+    unsigned i = 0;
+    if (!space) {
+        return;
+    }
+#ifdef DEBUG_ALLOC
+    printf("\nlibdwarfdetector remove from static err list "
+        " 0x%lx\n",(unsigned long)(uintptr_t)space);
+    fflush(stdout);
+#endif /* DEBUG_ALLOC */
+    for ( ; i <static_used; ++i) {
+        Dwarf_Error e = staticerrlist[i];
+        if (!e) {
+            continue;
+        }
+        if ((void *)e == space) {
+#ifdef DEBUG_ALLOC
+            printf("libdwarfdetector rm from static err list at %u\n",
+            i);
+            fflush(stdout);
+#endif /* DEBUG_ALLOC */ 
+            staticerrlist[i] = 0;
+            return;
+        }
+    }
+}
+
 /*  This will free everything in the staticerrlist,
     but that is ok */
 void
@@ -671,7 +716,7 @@ _dwarf_get_alloc(Dwarf_Debug dbg,
             }
         }
 #if DEBUG_ALLOC
-        printf("libdwarfdetector ALLOC ret 0x%lx type 0x%x "
+        printf("\nlibdwarfdetector ALLOC ret 0x%lx type 0x%x "
             "size %lu line %d %s\n",
             (unsigned long)ret_mem,(unsigned)alloc_type,
             (unsigned long)size,__LINE__,__FILE__);
@@ -804,6 +849,9 @@ dwarf_dealloc(Dwarf_Debug dbg,
     unsigned int type = 0;
     char * malloc_addr = 0;
     struct reserve_data_s * r = 0;
+#if 0
+    Dwarf_Bool check_errmsg_list = FALSE;
+#endif
 
     if (!space) {
 #ifdef DEBUG_ALLOC
@@ -921,11 +969,15 @@ dwarf_dealloc(Dwarf_Debug dbg,
         if (ep->er_static_alloc == DE_MALLOC) {
             /*  This is special, we had no arena
                 but have a full special area as normal. */
+#if 0
+            check_errmsg_list = TRUE;
+#endif
 #ifdef DEBUG_ALLOC
             printf("DEALLOC does free, DE_MALLOC line %d %s\n",
                 __LINE__,__FILE__);
             fflush(stdout);
 #endif /* DEBUG_ALLOC*/
+            _dwarf_remove_from_staticerrlist(space);
         }
         /* Was normal alloc, use normal dealloc. */
         /* DW_DLA_ERROR has a specialdestructor */
diff --git a/src/lib/libdwarf/dwarf_error.c b/src/lib/libdwarf/dwarf_error.c
index e49706693..73f60f2b3 100644
--- a/src/lib/libdwarf/dwarf_error.c
+++ b/src/lib/libdwarf/dwarf_error.c
@@ -140,7 +140,8 @@ _dwarf_error_string(Dwarf_Debug dbg, Dwarf_Error * error,
                 errptr = &_dwarf_failsafe_error;
                 errptr->er_static_alloc = DE_STATIC;
 #ifdef DEBUG
-                printf("libdwarf no dbg, fullystatic, "
+                printf("libdwarf no dbg to dwarf_error_string,"
+                    " fullystatic, "
                     "using DE_STATIC alloc, addr"
                     " 0x%lx line %d %s\n",
                     (unsigned long)errptr,
@@ -150,7 +151,7 @@ _dwarf_error_string(Dwarf_Debug dbg, Dwarf_Error * error,
                 errptr->er_static_alloc = DE_MALLOC;
 
 #ifdef DEBUG
-                printf("libdwarf no dbg,leaks, "
+                printf("libdwarf no dbg, add to static_err_list "
                     "static DE_MALLOC alloc, addr"
                     " 0x%lx line %d %s\n",
                     (unsigned long)errptr,
