From: Roland McGrath Date: Mon, 30 Aug 2010 11:04:37 +0000 (-0700) Subject: readelf: Fix crash in .debug_loc with garbage data. X-Git-Tag: elfutils-0.149~8 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a159915a87d83951acb9e504b9cefc08ba98b8bd;p=platform%2Fupstream%2Felfutils.git readelf: Fix crash in .debug_loc with garbage data. --- diff --git a/src/ChangeLog b/src/ChangeLog index 0c9858c..3010ce5 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,9 @@ +2010-08-30 Roland McGrath + + * readelf.c (print_debug_loc_section): Check for bogus length + before calling print_ops. + (print_ops): Check harder for bogus data that would read off end. + 2010-08-11 Roland McGrath * readelf.c (for_each_section_argument): Process all sections with diff --git a/src/readelf.c b/src/readelf.c index 48f0731..fd9f9a5 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -3977,7 +3977,8 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, return; } -#define NEED(n) if (len < n) goto invalid; +#define NEED(n) if (len < (Dwarf_Word) (n)) goto invalid +#define CONSUME(n) NEED (n); else len -= (n) Dwarf_Word offset = 0; while (len-- > 0) @@ -3998,7 +3999,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, addr = read_8ubyte_unaligned (dbg, data); } data += addrsize; - len -= addrsize; + CONSUME (addrsize); char *a = format_dwarf_addr (dwflmod, 0, addr); printf ("%*s[%4" PRIuMAX "] %s %s\n", @@ -4019,7 +4020,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, addr = read_8ubyte_unaligned (dbg, data); } data += ref_size; - len -= ref_size; + CONSUME (ref_size); printf ("%*s[%4" PRIuMAX "] %s %#" PRIxMAX "\n", indent, "", (uintmax_t) offset, @@ -4047,7 +4048,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, printf ("%*s[%4" PRIuMAX "] %s %" PRIu16 "\n", indent, "", (uintmax_t) offset, known[op], read_2ubyte_unaligned (dbg, data)); - len -= 2; + CONSUME (2); data += 2; offset += 3; break; @@ -4058,7 +4059,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, printf ("%*s[%4" PRIuMAX "] %s %" PRIu32 "\n", indent, "", (uintmax_t) offset, known[op], read_4ubyte_unaligned (dbg, data)); - len -= 4; + CONSUME (4); data += 4; offset += 5; break; @@ -4069,7 +4070,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 "\n", indent, "", (uintmax_t) offset, known[op], read_8ubyte_unaligned (dbg, data)); - len -= 8; + CONSUME (8); data += 8; offset += 9; break; @@ -4091,7 +4092,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, printf ("%*s[%4" PRIuMAX "] %s %" PRId16 "\n", indent, "", (uintmax_t) offset, known[op], read_2sbyte_unaligned (dbg, data)); - len -= 2; + CONSUME (2); data += 2; offset += 3; break; @@ -4102,7 +4103,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, printf ("%*s[%4" PRIuMAX "] %s %" PRId32 "\n", indent, "", (uintmax_t) offset, known[op], read_4sbyte_unaligned (dbg, data)); - len -= 4; + CONSUME (4); data += 4; offset += 5; break; @@ -4113,7 +4114,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, printf ("%*s[%4" PRIuMAX "] %s %" PRId64 "\n", indent, "", (uintmax_t) offset, known[op], read_8sbyte_unaligned (dbg, data)); - len -= 8; + CONSUME (8); data += 8; offset += 9; break; @@ -4124,21 +4125,23 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, case DW_OP_constu:; const unsigned char *start = data; uint64_t uleb; + NEED (1); get_uleb128 (uleb, data); /* XXX check overrun */ printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 "\n", indent, "", (uintmax_t) offset, known[op], uleb); - len -= data - start; + CONSUME (data - start); offset += 1 + (data - start); break; case DW_OP_bit_piece: start = data; uint64_t uleb2; + NEED (2); get_uleb128 (uleb, data); /* XXX check overrun */ get_uleb128 (uleb2, data); /* XXX check overrun */ printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 ", %" PRIu64 "\n", indent, "", (uintmax_t) offset, known[op], uleb, uleb2); - len -= data - start; + CONSUME (data - start); offset += 1 + (data - start); break; @@ -4147,20 +4150,22 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, case DW_OP_consts: start = data; int64_t sleb; + NEED (1); get_sleb128 (sleb, data); /* XXX check overrun */ printf ("%*s[%4" PRIuMAX "] %s %" PRId64 "\n", indent, "", (uintmax_t) offset, known[op], sleb); - len -= data - start; + CONSUME (data - start); offset += 1 + (data - start); break; case DW_OP_bregx: start = data; + NEED (2); get_uleb128 (uleb, data); /* XXX check overrun */ get_sleb128 (sleb, data); /* XXX check overrun */ printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 " %" PRId64 "\n", indent, "", (uintmax_t) offset, known[op], uleb, sleb); - len -= data - start; + CONSUME (data - start); offset += 1 + (data - start); break; @@ -4169,7 +4174,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, printf ("%*s[%4" PRIuMAX "] %s %" PRIu16 "\n", indent, "", (uintmax_t) offset, known[op], read_2ubyte_unaligned (dbg, data)); - len -= 2; + CONSUME (2); offset += 3; break; @@ -4178,7 +4183,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, printf ("%*s[%4" PRIuMAX "] %s %" PRIu32 "\n", indent, "", (uintmax_t) offset, known[op], read_4ubyte_unaligned (dbg, data)); - len -= 4; + CONSUME (4); offset += 5; break; @@ -4188,20 +4193,21 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, printf ("%*s[%4" PRIuMAX "] %s %" PRIuMAX "\n", indent, "", (uintmax_t) offset, known[op], (uintmax_t) (offset + read_2sbyte_unaligned (dbg, data))); - len -= 2; + CONSUME (2); data += 2; offset += 3; break; case DW_OP_implicit_value: start = data; + NEED (1); get_uleb128 (uleb, data); /* XXX check overrun */ printf ("%*s[%4" PRIuMAX "] %s: ", indent, "", (uintmax_t) offset, known[op]); NEED (uleb); print_block (uleb, data); data += uleb; - len -= data - start; + CONSUME (data - start); offset += 1 + (data - start); break; @@ -6097,7 +6103,8 @@ print_debug_loc_section (Dwfl_Module *dwflmod, bool first = true; unsigned char *readp = data->d_buf; - while (readp < (unsigned char *) data->d_buf + data->d_size) + unsigned char *const endp = (unsigned char *) data->d_buf + data->d_size; + while (readp < endp) { ptrdiff_t offset = readp - (unsigned char *) data->d_buf; @@ -6146,6 +6153,12 @@ print_debug_loc_section (Dwfl_Module *dwflmod, free (b); free (e); + if (endp - readp <= (ptrdiff_t) len) + { + fputs (gettext (" \n"), stdout); + break; + } + print_ops (dwflmod, dbg, 1, 18 + (address_size * 4), 3 /*XXX*/, address_size, offset_size, len, readp);