From 58abdf887821a5da09ba184c6e400a3bc5cccd5a Mon Sep 17 00:00:00 2001
From: Keith Seitz <keiths@redhat.com>
Date: Wed, 2 Aug 2023 08:35:11 -0700
Subject: [PATCH] Verify COFF symbol stringtab offset

This patch addresses an issue with malformed/fuzzed debug information that
was recently reported in gdb/30639. That bug specifically deals with
an ASAN issue, but the reproducer provided by the reporter causes a
another failure outside of ASAN:

$ ./gdb --data-directory data-directory -nx -q UAF_2
Reading symbols from /home/keiths/UAF_2...


Fatal signal: Segmentation fault
----- Backtrace -----
0x59a53a gdb_internal_backtrace_1
	../../src/gdb/bt-utils.c:122
0x59a5dd _Z22gdb_internal_backtracev
	../../src/gdb/bt-utils.c:168
0x786380 handle_fatal_signal
	../../src/gdb/event-top.c:889
0x7864ec handle_sigsegv
	../../src/gdb/event-top.c:962
0x7ff354c5fb6f ???
0x611f9a process_coff_symbol
	../../src/gdb/coffread.c:1556
0x611025 coff_symtab_read
	../../src/gdb/coffread.c:1172
0x60f8ff coff_read_minsyms
	../../src/gdb/coffread.c:549
0x60fe4b coff_symfile_read
	../../src/gdb/coffread.c:698
0xbde0f6 read_symbols
	../../src/gdb/symfile.c:772
0xbde7a3 syms_from_objfile_1
	../../src/gdb/symfile.c:966
0xbde867 syms_from_objfile
	../../src/gdb/symfile.c:983
0xbded42 symbol_file_add_with_addrs
	../../src/gdb/symfile.c:1086
0xbdf083 _Z24symbol_file_add_from_bfdRKN3gdb7ref_ptrI3bfd18gdb_bfd_ref_policyEEPKc10enum_flagsI16symfile_add_flagEPSt6vectorI14other_sectionsSaISC_EES8_I12objfile_flagEP7objfile
	../../src/gdb/symfile.c:1166
0xbdf0d2 _Z15symbol_file_addPKc10enum_flagsI16symfile_add_flagEPSt6vectorI14other_sectionsSaIS5_EES1_I12objfile_flagE
	../../src/gdb/symfile.c:1179
0xbdf197 symbol_file_add_main_1
	../../src/gdb/symfile.c:1203
0xbdf13e _Z20symbol_file_add_mainPKc10enum_flagsI16symfile_add_flagE
	../../src/gdb/symfile.c:1194
0x90f97f symbol_file_add_main_adapter
	../../src/gdb/main.c:549
0x90f895 catch_command_errors
	../../src/gdb/main.c:518
0x9109b6 captured_main_1
	../../src/gdb/main.c:1203
0x910fc8 captured_main
	../../src/gdb/main.c:1310
0x911067 _Z8gdb_mainP18captured_main_args
	../../src/gdb/main.c:1339
0x418c71 main
	../../src/gdb/gdb.c:39
---------------------
A fatal error internal to GDB has been detected, further
debugging is not possible.  GDB will now terminate.

This is a bug, please report it.  For instructions, see:
<https://www.gnu.org/software/gdb/bugs/>.

Segmentation fault (core dumped)

The issue here is that the COFF offset for the fuzzed symbol's
name is outside the string table. That is, the offset is greater
than the actual string table size.

coffread.c:getsymname actually contains a FIXME about this, and that's
what I've chosen to address to fix this issue, following what is done
in the DWARF reader:

$ ./gdb --data-directory data-directory -nx -q UAF_2
Reading symbols from /home/keiths/UAF_2...
COFF Error: string table offset (256) outside string table (length 0)
(gdb)

Unfortunately, I haven't any idea how else to test this patch since
COFF is not very common anymore. GCC removed support for it five
years ago with GCC 8.
---
 gdb/coffread.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/gdb/coffread.c b/gdb/coffread.c
index f8e14d8ad93..ae7632d49cb 100644
--- a/gdb/coffread.c
+++ b/gdb/coffread.c
@@ -159,6 +159,7 @@ static file_ptr linetab_offset;
 static file_ptr linetab_size;
 
 static char *stringtab = NULL;
+static long stringtab_length = 0;
 
 extern void stabsread_clear_cache (void);
 
@@ -1303,6 +1304,7 @@ init_stringtab (bfd *abfd, file_ptr offset, gdb::unique_xmalloc_ptr<char> *stora
   /* This is in target format (probably not very useful, and not
      currently used), not host format.  */
   memcpy (stringtab, lengthbuf, sizeof lengthbuf);
+  stringtab_length = length;
   if (length == sizeof length)	/* Empty table -- just the count.  */
     return 0;
 
@@ -1322,8 +1324,9 @@ getsymname (struct internal_syment *symbol_entry)
 
   if (symbol_entry->_n._n_n._n_zeroes == 0)
     {
-      /* FIXME: Probably should be detecting corrupt symbol files by
-	 seeing whether offset points to within the stringtab.  */
+      if (symbol_entry->_n._n_n._n_offset > stringtab_length)
+	error (_("COFF Error: string table offset (%ld) outside string table (length %ld)"),
+	       symbol_entry->_n._n_n._n_offset, stringtab_length);
       result = stringtab + symbol_entry->_n._n_n._n_offset;
     }
   else
-- 
2.41.0.windows.3

