From a984f112b015b7d33c3c91230eb4c35695926539 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Fri, 30 Dec 2022 11:41:16 +1030 Subject: [PATCH] PR29948, heap-buffer-overflow in display_debug_lines_decoded 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 | 116 +++++++++++++++------------ gas/testsuite/gas/elf/dwarf-5-loc0.d | 4 +- 2 files changed, 66 insertions(+), 54 deletions(-) diff --git a/binutils/dwarf.c b/binutils/dwarf.c index a00568dd3d8..cac26ad9c25 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -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 = _(""); - else if (ix > n_directories) + else { - warn (_("directory index %u > number of directories %" PRIu64 "\n"), - ix, n_directories); - directory = _(""); + if (linfo.li_version < 5) + --ix; + if (ix >= n_directories) + { + warn (_("directory index %u " + ">= number of directories %u\n"), + ix, n_directories); + directory = _(""); + } + 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 "), 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 \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 "), 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 \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 = _(""); } else diff --git a/gas/testsuite/gas/elf/dwarf-5-loc0.d b/gas/testsuite/gas/elf/dwarf-5-loc0.d index 7e8473a486f..9439d103b1f 100644 --- a/gas/testsuite/gas/elf/dwarf-5-loc0.d +++ b/gas/testsuite/gas/elf/dwarf-5-loc0.d @@ -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 -- 2.30.2