PR29948, heap-buffer-overflow in display_debug_lines_decoded
authorAlan Modra <amodra@gmail.com>
Fri, 30 Dec 2022 01:11:16 +0000 (11:41 +1030)
committerAlan Modra <amodra@gmail.com>
Fri, 30 Dec 2022 11:01:19 +0000 (21:31 +1030)
This fixes a couple of places in display_debug_lines_decoded that were
off by one in checking DWARF5 .debug_line directory indices.  It also
displays the DWARF5 entry 0 for the program current directory rather
than "." as is done for pre-DWARF5.  I decided against displaying
DW_AT_comp_dir for pre-DWARF5 since I figure it is better for readelf
to minimally interpret debug info.

binutils/
PR 29948
* dwarf.c (display_debug_lines_decoded): Display the given
directory entry 0 for DWARF5.  Properly check directory index
against number of entries in the table.  Revert to using
unsigned int for n_directories and associated variables.
Correct warning messages.
gas/
* testsuite/gas/elf/dwarf-5-loc0.d: Update.

binutils/dwarf.c
gas/testsuite/gas/elf/dwarf-5-loc0.d

index a00568d..cac26ad 100644 (file)
@@ -4899,7 +4899,7 @@ display_debug_lines_decoded (struct dwarf_section *  section,
       File_Entry *file_table = NULL;
       unsigned int n_files = 0;
       char **directory_table = NULL;
-      uint64_t n_directories = 0;
+      unsigned int n_directories = 0;
 
       if (startswith (section->name, ".debug_line.")
          /* Note: the following does not apply to .debug_line.dwo sections.
@@ -4949,8 +4949,8 @@ display_debug_lines_decoded (struct dwarf_section *  section,
 
          if (linfo.li_version >= 5)
            {
-             unsigned char *format_start, format_count, *format;
-             uint64_t formati, entryi;
+             unsigned char *format_start, *format;
+             unsigned int format_count, formati, entryi;
 
              load_debug_section_with_follow (line_str, fileptr);
 
@@ -5218,22 +5218,25 @@ display_debug_lines_decoded (struct dwarf_section *  section,
              unsigned int ix = file_table[0].directory_index;
              const char *directory;
 
-             if (ix == 0)
+             if (ix == 0 && linfo.li_version < 5)
                directory = ".";
              /* PR 20439 */
              else if (n_directories == 0)
                directory = _("<unknown>");
-             else if (ix > n_directories)
+             else
                {
-                 warn (_("directory index %u > number of directories %" PRIu64 "\n"),
-                       ix, n_directories);
-                 directory = _("<corrupt>");
+                 if (linfo.li_version < 5)
+                   --ix;
+                 if (ix >= n_directories)
+                   {
+                     warn (_("directory index %u "
+                             ">= number of directories %u\n"),
+                           ix, n_directories);
+                     directory = _("<corrupt>");
+                   }
+                 else
+                   directory = directory_table[ix];
                }
-             else if (linfo.li_version >= 5)
-               directory = directory_table[ix];
-             else
-               directory = directory_table[ix - 1];
-
              if (do_wide)
                printf (_("CU: %s/%s:\n"),
                        null_name (directory),
@@ -5397,45 +5400,53 @@ display_debug_lines_decoded (struct dwarf_section *  section,
                READ_ULEB (uladv, data, end);
                state_machine_regs.file = uladv;
 
-               {
-                 unsigned file = state_machine_regs.file;
-                 unsigned dir;
-
-                 if (linfo.li_version < 5)
-                   --file;
+               unsigned file = state_machine_regs.file;
+               if (linfo.li_version < 5)
+                 --file;
 
-                 if (file_table == NULL || n_files == 0)
-                   printf (_("\n [Use file table entry %d]\n"), file);
-                 /* PR 20439 */
-                 else if (file >= n_files)
-                   {
-                     warn (_("file index %u > number of files %u\n"), file, n_files);
-                     printf (_("\n <over large file table index %u>"), file);
-                   }
-                 else if ((dir = file_table[file].directory_index) == 0)
-                   /* If directory index is 0, that means current directory.  */
-                   printf ("\n./%s:[++]\n", null_name (file_table[file].name));
-                 else if (directory_table == NULL || n_directories == 0)
-                   printf (_("\n [Use file %s in directory table entry %d]\n"),
-                           null_name (file_table[file].name), dir);
-                 /* PR 20439 */
-                 else if (dir > n_directories)
-                   {
-                     warn (_("directory index %u > number of directories %" PRIu64 "\n"),
-                           dir, n_directories);
-                     printf (_("\n <over large directory table entry %u>\n"), dir);
-                   }
-                 else if (linfo.li_version >= 5)
-                   printf ("\n%s/%s:\n",
-                           /* The directory index starts counting at 0.  */
-                           null_name (directory_table[dir]),
-                           null_name (file_table[file].name));
-                 else
-                   printf ("\n%s/%s:\n",
-                           /* The directory index starts counting at 1.  */
-                           null_name (directory_table[dir - 1]),
-                           null_name (file_table[file].name));
-               }
+               if (file_table == NULL || n_files == 0)
+                 printf (_("\n [Use file table entry %d]\n"), file);
+               /* PR 20439 */
+               else if (file >= n_files)
+                 {
+                   warn (_("file index %u >= number of files %u\n"),
+                         file, n_files);
+                   printf (_("\n <over large file table index %u>"), file);
+                 }
+               else
+                 {
+                   unsigned dir = file_table[file].directory_index;
+                   if (dir == 0 && linfo.li_version < 5)
+                     /* If directory index is 0, that means compilation
+                        current directory.  bfd/dwarf2.c shows
+                        DW_AT_comp_dir here but in keeping with the
+                        readelf practice of minimal interpretation of
+                        file data, we show "./".  */
+                     printf ("\n./%s:[++]\n",
+                             null_name (file_table[file].name));
+                   else if (directory_table == NULL || n_directories == 0)
+                     printf (_("\n [Use file %s "
+                               "in directory table entry %d]\n"),
+                             null_name (file_table[file].name), dir);
+                   else
+                     {
+                       if (linfo.li_version < 5)
+                         --dir;
+                       /* PR 20439 */
+                       if (dir >= n_directories)
+                         {
+                           warn (_("directory index %u "
+                                   ">= number of directories %u\n"),
+                                 dir, n_directories);
+                           printf (_("\n <over large directory table entry "
+                                     "%u>\n"), dir);
+                         }
+                       else
+                         printf ("\n%s/%s:\n",
+                                 null_name (directory_table[dir]),
+                                 null_name (file_table[file].name));
+                     }
+                 }
                break;
 
              case DW_LNS_set_column:
@@ -5530,7 +5541,8 @@ display_debug_lines_decoded (struct dwarf_section *  section,
                  /* PR 20439  */
                  if (indx >= n_files)
                    {
-                     warn (_("corrupt file index %u encountered\n"), indx);
+                     warn (_("file index %u >= number of files %u\n"),
+                           indx, n_files);
                      fileName = _("<corrupt>");
                    }
                  else
index 7e8473a..9439d10 100644 (file)
@@ -7,10 +7,10 @@
 
 Contents of the \.debug_line section:
 
-CU: \./foo\.c:
+CU: .*/gas/testsuite/foo\.c:
 File name +Line number +Starting address +View +Stmt
 
-\./foo.c:\[\+\+\]
+.*/gas/testsuite/foo.c:
 foo\.c +1 +0x8 +x
 foo\.c +2 +0x10 +x
 foo\.c +- +0x10