From 2636426a091bd6c6f7f02e49ab20d4cdc6bfc753 Mon Sep 17 00:00:00 2001
From: Mark Wielaard <mark@klomp.org>
Date: Sat, 8 Feb 2025 20:00:12 +0100
Subject: [PATCH] libdw: Simplify __libdw_getabbrev and fix dwarf_offabbrev
 issue

__libdw_getabbrev could crash on reading a bad abbrev by trying to
deallocate memory it didn't allocate itself. This could happen because
dwarf_offabbrev would supply its own memory when calling
__libdw_getabbrev. No other caller did this.

Simplify the __libdw_getabbrev common code by not taking external
memory to put the abbrev result in (this would also not work correctly
if the abbrev was already cached). And make dwarf_offabbrev explicitly
copy the result (if there was no error or end of abbrev).

     * libdw/dwarf_getabbrev.c (__libdw_getabbrev): Don't take
     Dwarf_Abbrev result argument. Always just allocate abb when
     abbrev not found in cache.
     (dwarf_getabbrev): Don't pass NULL as last argument to
     __libdw_getabbrev.
    * libdw/dwarf_tag.c (__libdw_findabbrev): Likewise.
    * libdw/dwarf_offabbrev.c (dwarf_offabbrev): Likewise. And copy
    abbrev into abbrevp on success.
    * libdw/libdw.h (dwarf_offabbrev): Document return values.
    * libdw/libdwP.h (__libdw_getabbrev): Don't take Dwarf_Abbrev
    result argument.

https://sourceware.org/bugzilla/show_bug.cgi?id=32650

Signed-off-by: Mark Wielaard <mark@klomp.org>

Upstream-Status: Backport [https://sourceware.org/git/?p=elfutils.git;a=commit;h=2636426a091bd6c6f7f02e49ab20d4cdc6bfc753]
CVE: CVE-2025-1352
Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
---
 libdw/dwarf_getabbrev.c | 12 ++++--------
 libdw/dwarf_offabbrev.c | 10 +++++++---
 libdw/dwarf_tag.c       |  3 +--
 libdw/libdw.h           |  4 +++-
 libdw/libdwP.h          |  3 +--
 5 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/libdw/dwarf_getabbrev.c b/libdw/dwarf_getabbrev.c
index 5b02333..d9a6c02 100644
--- a/libdw/dwarf_getabbrev.c
+++ b/libdw/dwarf_getabbrev.c
@@ -1,5 +1,6 @@
 /* Get abbreviation at given offset.
    Copyright (C) 2003, 2004, 2005, 2006, 2014, 2017 Red Hat, Inc.
+   Copyright (C) 2025 Mark J. Wielaard <mark@klomp.org>
    This file is part of elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2003.
 
@@ -38,7 +39,7 @@
 Dwarf_Abbrev *
 internal_function
 __libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu, Dwarf_Off offset,
-		   size_t *lengthp, Dwarf_Abbrev *result)
+		   size_t *lengthp)
 {
   /* Don't fail if there is not .debug_abbrev section.  */
   if (dbg->sectiondata[IDX_debug_abbrev] == NULL)
@@ -85,12 +86,7 @@ __libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu, Dwarf_Off offset,
   Dwarf_Abbrev *abb = NULL;
   if (cu == NULL
       || (abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code)) == NULL)
-    {
-      if (result == NULL)
-	abb = libdw_typed_alloc (dbg, Dwarf_Abbrev);
-      else
-	abb = result;
-    }
+    abb = libdw_typed_alloc (dbg, Dwarf_Abbrev);
   else
     {
       foundit = true;
@@ -183,5 +179,5 @@ dwarf_getabbrev (Dwarf_Die *die, Dwarf_Off offset, size_t *lengthp)
       return NULL;
     }
 
-  return __libdw_getabbrev (dbg, cu, abbrev_offset + offset, lengthp, NULL);
+  return __libdw_getabbrev (dbg, cu, abbrev_offset + offset, lengthp);
 }
diff --git a/libdw/dwarf_offabbrev.c b/libdw/dwarf_offabbrev.c
index 27cdad6..41df69b 100644
--- a/libdw/dwarf_offabbrev.c
+++ b/libdw/dwarf_offabbrev.c
@@ -41,11 +41,15 @@ dwarf_offabbrev (Dwarf *dbg, Dwarf_Off offset, size_t *lengthp,
   if (dbg == NULL)
     return -1;
 
-  Dwarf_Abbrev *abbrev = __libdw_getabbrev (dbg, NULL, offset, lengthp,
-					    abbrevp);
+  Dwarf_Abbrev *abbrev = __libdw_getabbrev (dbg, NULL, offset, lengthp);
 
   if (abbrev == NULL)
     return -1;
 
-  return abbrev == DWARF_END_ABBREV ? 1 : 0;
+  if (abbrev == DWARF_END_ABBREV)
+    return 1;
+
+  *abbrevp = *abbrev;
+
+  return 0;
 }
diff --git a/libdw/dwarf_tag.c b/libdw/dwarf_tag.c
index d784970..218382a 100644
--- a/libdw/dwarf_tag.c
+++ b/libdw/dwarf_tag.c
@@ -53,8 +53,7 @@ __libdw_findabbrev (struct Dwarf_CU *cu, unsigned int code)
 
 	/* Find the next entry.  It gets automatically added to the
 	   hash table.  */
-	abb = __libdw_getabbrev (cu->dbg, cu, cu->last_abbrev_offset, &length,
-				 NULL);
+	abb = __libdw_getabbrev (cu->dbg, cu, cu->last_abbrev_offset, &length);
 	if (abb == NULL || abb == DWARF_END_ABBREV)
 	  {
 	    /* Make sure we do not try to search for it again.  */
diff --git a/libdw/libdw.h b/libdw/libdw.h
index d53dc78..ec4713a 100644
--- a/libdw/libdw.h
+++ b/libdw/libdw.h
@@ -587,7 +587,9 @@ extern int dwarf_srclang (Dwarf_Die *die);
 extern Dwarf_Abbrev *dwarf_getabbrev (Dwarf_Die *die, Dwarf_Off offset,
 				      size_t *lengthp);
 
-/* Get abbreviation at given offset in .debug_abbrev section.  */
+/* Get abbreviation at given offset in .debug_abbrev section.  On
+   success return zero and fills in ABBREVP.  When there is no (more)
+   abbrev at offset returns one.  On error returns a negative value.  */
 extern int dwarf_offabbrev (Dwarf *dbg, Dwarf_Off offset, size_t *lengthp,
 			    Dwarf_Abbrev *abbrevp)
      __nonnull_attribute__ (4);
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index 8b2f06f..f0f4b78 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -783,8 +783,7 @@ extern Dwarf_Abbrev *__libdw_findabbrev (struct Dwarf_CU *cu,
 
 /* Get abbreviation at given offset.  */
 extern Dwarf_Abbrev *__libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu,
-					Dwarf_Off offset, size_t *lengthp,
-					Dwarf_Abbrev *result)
+					Dwarf_Off offset, size_t *lengthp)
      __nonnull_attribute__ (1) internal_function;
 
 /* Get abbreviation of given DIE, and optionally set *READP to the DIE memory
-- 
2.25.1

