From 2636426a091bd6c6f7f02e49ab20d4cdc6bfc753 Mon Sep 17 00:00:00 2001 From: Mark Wielaard 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 Upstream-Status: Backport [https://sourceware.org/git/?p=elfutils.git;a=commit;h=2636426a091bd6c6f7f02e49ab20d4cdc6bfc753] CVE: CVE-2025-1352 Signed-off-by: Hitendra Prajapati --- 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 This file is part of elfutils. Written by Ulrich Drepper , 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