]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdw: check that DWARF strings are null-terminated
authorAleksei Vetrov <vvvvvv@google.com>
Tue, 14 Feb 2023 20:30:02 +0000 (20:30 +0000)
committerMark Wielaard <mark@klomp.org>
Thu, 16 Feb 2023 23:18:53 +0000 (00:18 +0100)
It is expected from libdw to return strings that are null-terminated to
avoid overflowing ELF data.

* Add calculation of a safe prefix inside string sections, where any
  string will be null-terminated.

* Check if offset overflows the safe prefix in dwarf_formstring.

Signed-off-by: Aleksei Vetrov <vvvvvv@google.com>
libdw/dwarf_begin_elf.c
libdw/dwarf_formstring.c
libdw/libdwP.h

index 8fcef335efbb45feb158571f51f941b4a596dbc5..1d4bb33337b73c1925d26bf6cd5480ee0b5ff757 100644 (file)
@@ -70,6 +70,30 @@ static const char dwarf_scnnames[IDX_last][19] =
 };
 #define ndwarf_scnnames (sizeof (dwarf_scnnames) / sizeof (dwarf_scnnames[0]))
 
+/* Map from section index to string section index.
+   Non-string sections should have STR_SCN_IDX_last.  */
+static const enum string_section_index scn_to_string_section_idx[IDX_last] =
+{
+  [IDX_debug_info] = STR_SCN_IDX_last,
+  [IDX_debug_types] = STR_SCN_IDX_last,
+  [IDX_debug_abbrev] = STR_SCN_IDX_last,
+  [IDX_debug_addr] = STR_SCN_IDX_last,
+  [IDX_debug_aranges] = STR_SCN_IDX_last,
+  [IDX_debug_line] = STR_SCN_IDX_last,
+  [IDX_debug_line_str] = STR_SCN_IDX_debug_line_str,
+  [IDX_debug_frame] = STR_SCN_IDX_last,
+  [IDX_debug_loc] = STR_SCN_IDX_last,
+  [IDX_debug_loclists] = STR_SCN_IDX_last,
+  [IDX_debug_pubnames] = STR_SCN_IDX_last,
+  [IDX_debug_str] = STR_SCN_IDX_debug_str,
+  [IDX_debug_str_offsets] = STR_SCN_IDX_last,
+  [IDX_debug_macinfo] = STR_SCN_IDX_last,
+  [IDX_debug_macro] = STR_SCN_IDX_last,
+  [IDX_debug_ranges] = STR_SCN_IDX_last,
+  [IDX_debug_rnglists] = STR_SCN_IDX_last,
+  [IDX_gnu_debugaltlink] = STR_SCN_IDX_last
+};
+
 static enum dwarf_type
 scn_dwarf_type (Dwarf *result, size_t shstrndx, Elf_Scn *scn)
 {
@@ -230,6 +254,19 @@ check_section (Dwarf *result, size_t shstrndx, Elf_Scn *scn, bool inscngrp)
   /* We can now read the section data into results. */
   result->sectiondata[cnt] = data;
 
+  /* If the section contains string data, we want to know a size of a prefix
+     where any string will be null-terminated. */
+  enum string_section_index string_section_idx = scn_to_string_section_idx[cnt];
+  if (string_section_idx < STR_SCN_IDX_last)
+    {
+      size_t size = data->d_size;
+      /* Reduce the size by the number of non-zero bytes at the end of the
+        section.  */
+      while (size > 0 && *((const char *) data->d_buf + size - 1) != '\0')
+       --size;
+      result->string_section_size[string_section_idx] = size;
+    }
+
   return result;
 }
 
index c3e892a82f6abc90274eb19e76a7d0504920daf7..0ee42411b44ee0d24cacda789c2dbdd5d37f9c70 100644 (file)
@@ -61,6 +61,9 @@ dwarf_formstring (Dwarf_Attribute *attrp)
   Elf_Data *data = ((attrp->form == DW_FORM_line_strp)
                    ? dbg_ret->sectiondata[IDX_debug_line_str]
                    : dbg_ret->sectiondata[IDX_debug_str]);
+  size_t data_size = ((attrp->form == DW_FORM_line_strp)
+                     ? dbg_ret->string_section_size[STR_SCN_IDX_debug_line_str]
+                     : dbg_ret->string_section_size[STR_SCN_IDX_debug_str]);
   if (data == NULL)
     {
       __libdw_seterrno ((attrp->form == DW_FORM_line_strp)
@@ -171,7 +174,7 @@ dwarf_formstring (Dwarf_Attribute *attrp)
       else
        off = read_8ubyte_unaligned (dbg, datap);
 
-      if (off > dbg->sectiondata[IDX_debug_str]->d_size)
+      if (off >= data_size)
        goto invalid_offset;
     }
 
index 961fa4e7f917370530ff58aadc47fbf9bb5efcbd..5cbdc27922943c1b1b7e679ae1cc800583d1271e 100644 (file)
@@ -86,6 +86,13 @@ enum
     IDX_last
   };
 
+/* Valid indices for the string section's information.  */
+enum string_section_index
+  {
+    STR_SCN_IDX_debug_line_str,
+    STR_SCN_IDX_debug_str,
+    STR_SCN_IDX_last
+  };
 
 /* Error values.  */
 enum
@@ -169,6 +176,10 @@ struct Dwarf
   /* The section data.  */
   Elf_Data *sectiondata[IDX_last];
 
+  /* Size of a prefix of string sections, where any string will be
+     null-terminated. */
+  size_t string_section_size[STR_SCN_IDX_last];
+
   /* True if the file has a byte order different from the host.  */
   bool other_byte_order;