]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
[gdb/symtab] Throw DWARF error on out-of-bounds DW_FORM_strx
authorTom de Vries <tdevries@suse.de>
Fri, 2 May 2025 20:21:36 +0000 (22:21 +0200)
committerTom de Vries <tdevries@suse.de>
Fri, 2 May 2025 20:21:36 +0000 (22:21 +0200)
With the test-case contained in the patch, and gdb build with
-fsanitize=address we get:
...
==23678==ERROR: AddressSanitizer: heap-buffer-overflow ...^M
READ of size 1 at 0x6020000c30dc thread T3^[[1m^[[0m^M
ptype global_var^M
    #0 0x2c6a40b in bfd_getl32 bfd/libbfd.c:846^M
    #1 0x168f96c in read_str_index gdb/dwarf2/read.c:15349^M
...

The executable contains an out-of-bounds DW_FORM_strx attribute:
...
$ readelf -wi $exec
<2eb>   DW_AT_name        :readelf: Warning: string index of 1 converts to \
  an offset of 0xc which is too big for section .debug_str
 (indexed string: 0x1): <string index too big>
...
and read_str_index doesn't check for this:
...
  info_ptr = (str_offsets_section->buffer
      + str_offsets_base
      + str_index * offset_size);
   if (offset_size == 4)
     str_offset = bfd_get_32 (abfd, info_ptr);
...
and consequently reads out-of-bounds.

Fix this in read_str_index by checking for the out-of-bounds condition and
throwing a DWARF error:
...
(gdb) ptype global_var
DWARF Error: Offset from DW_FORM_GNU_str_index or DW_FORM_strx pointing \
  outside of .debug_str_offsets section in CU at offset 0x2d7 \
  [in module dw-form-strx-out-of-bounds]
No symbol "global_var" in current context.
(gdb)
...

Tested on x86_64-linux.

Approved-By: Tom Tromey <tom@tromey.com>
gdb/dwarf2/read.c
gdb/testsuite/gdb.dwarf2/dw-form-strx-out-of-bounds.exp [new file with mode: 0644]

index 951f9d26e4b419b5e775deda1185bc8b421e5428..6848f63aa2e4552b293a5cf7756a95af4e335c91 100644 (file)
@@ -15333,9 +15333,16 @@ read_str_index (struct dwarf2_cu *cu,
             " in CU at offset %s [in module %s]"),
           form_name, str_section->get_name (),
           sect_offset_str (cu->header.sect_off), objf_name);
-  info_ptr = (str_offsets_section->buffer
-             + str_offsets_base
-             + str_index * offset_size);
+
+  ULONGEST str_offsets_offset = str_offsets_base + str_index * offset_size;
+  if (str_offsets_offset >= str_offsets_section->size)
+    error (_(DWARF_ERROR_PREFIX
+            "Offset from %s pointing outside of %s section in CU at offset %s"
+            " [in module %s]"),
+          form_name, str_offsets_section->get_name (),
+          sect_offset_str (cu->header.sect_off), objf_name);
+  info_ptr = str_offsets_section->buffer + str_offsets_offset;
+
   if (offset_size == 4)
     str_offset = bfd_get_32 (abfd, info_ptr);
   else
diff --git a/gdb/testsuite/gdb.dwarf2/dw-form-strx-out-of-bounds.exp b/gdb/testsuite/gdb.dwarf2/dw-form-strx-out-of-bounds.exp
new file mode 100644 (file)
index 0000000..f2123fa
--- /dev/null
@@ -0,0 +1,35 @@
+# Copyright 2025 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Check that an out-of-bounds DW_FORM_strx attribute triggers a DWARF error.
+
+# Out of bounds index.
+set int_str_idx 1
+
+source $srcdir/$subdir/dw-form-strx.exp.tcl
+
+set re_dwarf_error \
+    [string_list_to_regexp \
+        "DWARF Error: Offset from DW_FORM_GNU_str_index or DW_FORM_strx" \
+        " pointing outside of .debug_str_offsets section in CU at offset"\
+        " "]$hex
+set re_in_module \
+    {in module [^\r\n]+}
+set re_in_module [string_to_regexp {[}]$re_in_module[string_to_regexp {]}]
+set re_no_symbol [string_to_regexp {No symbol "global_var" in current context.}]
+gdb_test "ptype global_var" \
+    [multi_line \
+        "$re_dwarf_error $re_in_module"\
+        $re_no_symbol]