148 lines
4.5 KiB
Diff
148 lines
4.5 KiB
Diff
From 5e5c0394d82c53e97750fe7b18023e6f84157b81 Mon Sep 17 00:00:00 2001
|
|
From: Mark Wielaard <mark@klomp.org>
|
|
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 <mark@klomp.org>
|
|
---
|
|
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 0db12d99..0698e5ff 100644
|
|
--- a/lib/system.h
|
|
+++ b/lib/system.h
|
|
@@ -34,6 +34,7 @@
|
|
#include <config.h>
|
|
|
|
#include <errno.h>
|
|
+#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
@@ -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 79a24d25..c5a94f82 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 6526db07..c43fda35 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.27.0
|
|
|