From 5e5c0394d82c53e97750fe7b18023e6f84157b81 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Sat, 8 Feb 2025 21:44:56 +0100 Subject: [PATCH] libelf, readelf: Use validate_str also to check dynamic symstr data When dynsym/str was read through eu-readelf --dynamic by readelf process_symtab the string data was not validated, possibly printing unallocated memory past the end of the symstr data. Fix this by turning the elf_strptr validate_str function into a generic lib/system.h helper function and use it in readelf to validate the strings before use. * libelf/elf_strptr.c (validate_str): Remove to... * lib/system.h (validate_str): ... here. Make inline, simplify check and document. * src/readelf.c (process_symtab): Use validate_str on symstr_data. https://sourceware.org/bugzilla/show_bug.cgi?id=32654 Signed-off-by: Mark Wielaard Upstream-Status: Backport [https://sourceware.org/git/?p=elfutils.git;a=commit;h=5e5c0394d82c53e97750fe7b18023e6f84157b81] CVE: CVE-2025-1365 Signed-off-by: Hitendra Prajapati --- lib/system.h | 27 +++++++++++++++++++++++++++ libelf/elf_strptr.c | 18 ------------------ src/readelf.c | 18 +++++++++++++++--- 3 files changed, 42 insertions(+), 21 deletions(-) diff --git a/lib/system.h b/lib/system.h index 0db12d9..0698e5f 100644 --- a/lib/system.h +++ b/lib/system.h @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -117,6 +118,32 @@ startswith (const char *str, const char *prefix) return strncmp (str, prefix, strlen (prefix)) == 0; } +/* Return TRUE if STR[FROM] is a valid string with a zero terminator + at or before STR[TO - 1]. Note FROM is an index into the STR + array, while TO is the maximum size of the STR array. This + function returns FALSE when TO is zero or FROM >= TO. */ +static inline bool +validate_str (const char *str, size_t from, size_t to) +{ +#if HAVE_DECL_MEMRCHR + // Check end first, which is likely a zero terminator, + // to prevent function call + return (to > 0 + && (str[to - 1] == '\0' + || (to > from + && memrchr (&str[from], '\0', to - from - 1) != NULL))); +#else + do { + if (to <= from) + return false; + + to--; + } while (str[to]); + + return true; +#endif +} + /* A special gettext function we use if the strings are too short. */ #define sgettext(Str) \ ({ const char *__res = strrchr (_(Str), '|'); \ diff --git a/libelf/elf_strptr.c b/libelf/elf_strptr.c index 79a24d2..c5a94f8 100644 --- a/libelf/elf_strptr.c +++ b/libelf/elf_strptr.c @@ -53,24 +53,6 @@ get_zdata (Elf_Scn *strscn) return zdata; } -static bool validate_str (const char *str, size_t from, size_t to) -{ -#if HAVE_DECL_MEMRCHR - // Check end first, which is likely a zero terminator, to prevent function call - return ((to > 0 && str[to - 1] == '\0') - || (to - from > 0 && memrchr (&str[from], '\0', to - from - 1) != NULL)); -#else - do { - if (to <= from) - return false; - - to--; - } while (str[to]); - - return true; -#endif -} - char * elf_strptr (Elf *elf, size_t idx, size_t offset) { diff --git a/src/readelf.c b/src/readelf.c index 0e93118..63eb548 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -2639,6 +2639,7 @@ process_symtab (Ebl *ebl, unsigned int nsyms, Elf64_Word idx, char typebuf[64]; char bindbuf[64]; char scnbuf[64]; + const char *sym_name; Elf32_Word xndx; GElf_Sym sym_mem; GElf_Sym *sym @@ -2650,6 +2651,19 @@ process_symtab (Ebl *ebl, unsigned int nsyms, Elf64_Word idx, /* Determine the real section index. */ if (likely (sym->st_shndx != SHN_XINDEX)) xndx = sym->st_shndx; + if (use_dynamic_segment == true) + { + if (validate_str (symstr_data->d_buf, sym->st_name, + symstr_data->d_size)) + sym_name = (char *)symstr_data->d_buf + sym->st_name; + else + sym_name = NULL; + } + else + sym_name = elf_strptr (ebl->elf, idx, sym->st_name); + + if (sym_name == NULL) + sym_name = "???"; printf (_ ("\ %5u: %0*" PRIx64 " %6" PRId64 " %-7s %-6s %-9s %6s %s"), @@ -2662,9 +2676,7 @@ process_symtab (Ebl *ebl, unsigned int nsyms, Elf64_Word idx, get_visibility_type (GELF_ST_VISIBILITY (sym->st_other)), ebl_section_name (ebl, sym->st_shndx, xndx, scnbuf, sizeof (scnbuf), NULL, shnum), - use_dynamic_segment == true - ? (char *)symstr_data->d_buf + sym->st_name - : elf_strptr (ebl->elf, idx, sym->st_name)); + sym_name); if (versym_data != NULL) { -- 2.25.1