Fix seg-fault in DWARF dumper when given a corrupt binary containing illegal director...
authorNick Clifton <nickc@redhat.com>
Mon, 8 Aug 2016 08:34:32 +0000 (09:34 +0100)
committerNick Clifton <nickc@redhat.com>
Mon, 8 Aug 2016 08:34:32 +0000 (09:34 +0100)
PR binutils/20439
* dwarf.c (display_debug_lines_decoded): Check directory and file
indicies before using them to access directory and file tables.

binutils/ChangeLog
binutils/dwarf.c

index 9aef0468072e07b7fc9fd4cad79f9236db7f1b48..2ba1bbdf0e18a7968595a23f63e0f2c250e56853 100644 (file)
@@ -1,3 +1,9 @@
+2016-08-08  Nick Clifton  <nickc@redhat.com>
+
+       PR binutils/20439
+       * dwarf.c (display_debug_lines_decoded): Check directory and file
+       indicies before using them to access directory and file tables.
+
 2016-08-02  Nick Clifton  <nickc@redhat.com>
 
        PR binutils/17512
index 282e069958d1d59fd8a05a6e451d98ba62a325e7..2f2d8aea780897cdb1238aa1197feda0f82e84b5 100644 (file)
@@ -3334,7 +3334,20 @@ display_debug_lines_decoded (struct dwarf_section *section,
              else
                {
                  unsigned int ix = file_table[0].directory_index;
-                 const char *directory = ix ? (char *)directory_table[ix - 1] : ".";
+                 const char *directory;
+
+                 if (ix == 0)
+                   directory = ".";
+                 /* PR 20439 */
+                 else if (n_directories == 0)
+                   directory = _("<unknown>");
+                 else if (ix > n_directories)
+                   {
+                     warn (_("directory index %u > number of directories %u\n"), ix, n_directories);
+                     directory = _("<corrupt>");
+                   }
+                 else
+                   directory = (char *) directory_table[ix - 1];
 
                  if (do_wide || strlen (directory) < 76)
                    printf (_("CU: %s/%s:\n"), directory, file_table[0].name);
@@ -3492,20 +3505,35 @@ display_debug_lines_decoded (struct dwarf_section *section,
                   data += bytes_read;
                   state_machine_regs.file = adv;
 
-                  if (file_table == NULL)
-                    printf (_("\n [Use file table entry %d]\n"), state_machine_regs.file - 1);
-                  else if (file_table[state_machine_regs.file - 1].directory_index == 0)
-                    /* If directory index is 0, that means current directory.  */
-                    printf ("\n./%s:[++]\n",
-                            file_table[state_machine_regs.file - 1].name);
-                  else if (directory_table == NULL)
-                    printf (_("\n [Use directory table entry %d]\n"),
-                            file_table[state_machine_regs.file - 1].directory_index - 1);
-                  else
-                    /* The directory index starts counting at 1.  */
-                    printf ("\n%s/%s:\n",
-                            directory_table[file_table[state_machine_regs.file - 1].directory_index - 1],
-                            file_table[state_machine_regs.file - 1].name);
+                  {
+                    unsigned file = state_machine_regs.file - 1;
+                    unsigned dir;
+
+                    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 + 1, 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", file_table[file].name);
+                    else if (directory_table == NULL || n_directories == 0)
+                      printf (_("\n [Use file %s in directory table entry %d]\n"),
+                              file_table[file].name, dir);
+                    /* PR 20439 */
+                    else 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",
+                              /* The directory index starts counting at 1.  */
+                              directory_table[dir - 1], file_table[file].name);
+                  }
                   break;
 
                 case DW_LNS_set_column:
@@ -3587,9 +3615,19 @@ display_debug_lines_decoded (struct dwarf_section *section,
              size_t fileNameLength;
 
              if (file_table)
-               fileName = (char *) file_table[state_machine_regs.file - 1].name;
+               {
+                 unsigned indx = state_machine_regs.file - 1;
+                 /* PR 20439  */
+                 if (indx >= n_files)
+                   {
+                     warn (_("corrupt file index %u encountered\n"), indx);
+                     fileName = _("<corrupt>");
+                   }
+                 else
+                   fileName = (char *) file_table[indx].name;
+               }
              else
-               fileName = "<unknown>";
+               fileName = _("<unknown>");
 
              fileNameLength = strlen (fileName);