public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Tom de Vries <tdevries@suse.de>
To: gdb-patches@sourceware.org
Subject: [PATCH][gdb/symtab] Fix out-of-bounds in objfile::section_offset
Date: Tue, 12 Jul 2022 10:00:34 +0200	[thread overview]
Message-ID: <20220712080032.GA18344@delia.home> (raw)

Hi,

Using this patch in objfile::section_offset that checks that idx is within
bounds:
...
     int idx = gdb_bfd_section_index (this->obfd, section);
+    gdb_assert (idx < section_offsets.size ());
     return this->section_offsets[idx];
...
we run into the assert in test-cases:
- gdb.base/readline-ask.exp
- gdb.base/symbol-without-target_section.exp
- gdb.dwarf2/dw2-icc-opaque.exp

These were previously reported as -fsanitize-threads issues (PR25724,
PR25723).

In the case of the latter test-case the problem happens as follows.

- We start out with bfd_count_sections () == 6, so
  gdb_bfd_count_sections () == 10.  The difference of 4 is due to the
  4 'special sections' named *ABS*, *UND*, *COM* and *IND*.
- According to gdb_bfd_section_index, the *IND* has section index
  bfd_count_sections () + 3, so 9.
- default_symfile_relocate gets called, which calls
  bfd_simple_get_relocated_section_contents and eventually this results in
  bfd_make_section_old_way being called for a section named COMMON,
  meaning now we have bfd_count_sections () == 7
- consequently the next time we call objfile::section_offset for *IND*,
  gdb_bfd_section_index assigns it section index 10.
- the assert fails because idx == 10 and section_offsets.size () == 10.

Fix this in a minimal and contained way, by:
- adding a side-table orig_bfd_count_sections_map, in which we store the
  original bfd_count_sections () value, and
- using this value in gdb_bfd_count_sections and gdb_bfd_section_index,
  ensuring that the creation of the new section doesn't interfere with
  accessing the unchanged objfile::sections and objfile::section_offsets.

In case we call gdb_bfd_section_index with the new section, we assert.

However, in case gdb_bfd_section_index is not used, and the bfd section index
of the new section is used to access objfile::sections or
objfile::section_offsets, we return some unrelated element, which might fail
in some difficult to understand manner.  It's hard to check whether this can
happen or not without having distinct types for the different section indices
(bfd vs. gdb_bfd).  Anyway, if this does occur, it's a pre-existing bug.  This
patch focuses on getting things right for the original sections.

Tested on x86_64-linux, with and without -fsanitize=threads.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=29295

Any comments?

Thanks,
- Tom

[gdb/symtab] Fix out-of-bounds in objfile::section_offset

---
 gdb/gdb_bfd.c  | 32 +++++++++++++++++++++++++++-----
 gdb/objfiles.h |  2 ++
 2 files changed, 29 insertions(+), 5 deletions(-)

diff --git a/gdb/gdb_bfd.c b/gdb/gdb_bfd.c
index 22828482d5b..66b6ad1c0de 100644
--- a/gdb/gdb_bfd.c
+++ b/gdb/gdb_bfd.c
@@ -34,6 +34,10 @@
 #include "inferior.h"
 #include "cli/cli-style.h"
 
+/* The quantity bfd_count_sections can change over time.  Store
+   the original value here.  */
+static std::unordered_map<bfd *, int> orig_bfd_count_sections_map;
+
 /* An object of this type is stored in the section's user data when
    mapping a section.  */
 
@@ -730,6 +734,7 @@ gdb_bfd_unref (struct bfd *abfd)
   bfd_set_usrdata (abfd, NULL);  /* Paranoia.  */
 
   htab_remove_elt (all_bfds, abfd);
+  orig_bfd_count_sections_map.erase (abfd);
 
   gdb_bfd_close_or_warn (abfd);
 
@@ -996,21 +1001,37 @@ gdb_bfd_record_inclusion (bfd *includer, bfd *includee)
 
 gdb_static_assert (ARRAY_SIZE (_bfd_std_section) == 4);
 
+/* The quantity bfd_count_sections can change over time.  Return
+   the original value here.  */
+
+static int
+get_orig_bfd_count_sections (bfd *abfd)
+{
+  auto it = orig_bfd_count_sections_map.find (abfd);
+  if (it != orig_bfd_count_sections_map.end ())
+    return it->second;
+  int idx = bfd_count_sections (abfd);
+  orig_bfd_count_sections_map[abfd] = idx;
+  return idx;
+}
+
 /* See gdb_bfd.h.  */
 
 int
 gdb_bfd_section_index (bfd *abfd, asection *section)
 {
+  int count = get_orig_bfd_count_sections (abfd);
   if (section == NULL)
     return -1;
   else if (section == bfd_com_section_ptr)
-    return bfd_count_sections (abfd);
+    return count;
   else if (section == bfd_und_section_ptr)
-    return bfd_count_sections (abfd) + 1;
+    return count + 1;
   else if (section == bfd_abs_section_ptr)
-    return bfd_count_sections (abfd) + 2;
+    return count + 2;
   else if (section == bfd_ind_section_ptr)
-    return bfd_count_sections (abfd) + 3;
+    return count + 3;
+  gdb_assert (section->index < count);
   return section->index;
 }
 
@@ -1019,7 +1040,8 @@ gdb_bfd_section_index (bfd *abfd, asection *section)
 int
 gdb_bfd_count_sections (bfd *abfd)
 {
-  return bfd_count_sections (abfd) + 4;
+  int count = get_orig_bfd_count_sections (abfd);
+  return count + 4;
 }
 
 /* See gdb_bfd.h.  */
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
index a7098b46279..faaf97feb1f 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -598,6 +598,7 @@ struct objfile
     gdb_assert (section->owner == nullptr || section->owner == this->obfd);
 
     int idx = gdb_bfd_section_index (this->obfd, section);
+    gdb_assert (idx != -1);
     return this->section_offsets[idx];
   }
 
@@ -609,6 +610,7 @@ struct objfile
     gdb_assert (section->owner == nullptr || section->owner == this->obfd);
 
     int idx = gdb_bfd_section_index (this->obfd, section);
+    gdb_assert (idx != -1);
     this->section_offsets[idx] = offset;
   }
 

             reply	other threads:[~2022-07-12  8:00 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-07-12  8:00 Tom de Vries [this message]
2022-07-12  9:30 ` Pedro Alves
2022-07-12 10:16   ` Tom de Vries
2022-07-12 10:25     ` Pedro Alves
2022-07-12 12:09       ` Tom de Vries
2022-07-15 18:55       ` Tom Tromey
2022-07-18 14:34         ` Pedro Alves

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220712080032.GA18344@delia.home \
    --to=tdevries@suse.de \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).