diff options
author | Nick Clifton <nickc@redhat.com> | 2014-12-01 11:19:39 +0000 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2014-12-01 11:19:39 +0000 |
commit | 591f7597d447d8d038d6d8e24a706d1d5e32eba1 (patch) | |
tree | b15865685398ad63e89487842d9b896a421c7105 /binutils/elfcomm.c | |
parent | 9e8cd6df3ca295986b2c295b6cfa5ceadd410bb4 (diff) | |
download | gdb-591f7597d447d8d038d6d8e24a706d1d5e32eba1.zip gdb-591f7597d447d8d038d6d8e24a706d1d5e32eba1.tar.gz gdb-591f7597d447d8d038d6d8e24a706d1d5e32eba1.tar.bz2 |
Add checks for memory access violations exposed by fuzzed archives.
PR binutils/17531
* dwarf.c (process_cu_tu_index): Check for an out of range row
index.
* elfcomm.c (adjust_relative_path): Change name_len parameter to
an unsigned long. Check for path length overflow.
(process_archive_index_and_symbols): Check for invalid header
size.
(setup_archive): Add checks for invalid archives.
(get_archive_member_name): Add range checks.
* elfcomm.h (adjust_relative_path): Update prototyoe.
* readelf.c (process_archive): Add range checks.
Diffstat (limited to 'binutils/elfcomm.c')
-rw-r--r-- | binutils/elfcomm.c | 55 |
1 files changed, 50 insertions, 5 deletions
diff --git a/binutils/elfcomm.c b/binutils/elfcomm.c index f1502b9..bbf1955 100644 --- a/binutils/elfcomm.c +++ b/binutils/elfcomm.c @@ -386,10 +386,11 @@ byte_get_64 (unsigned char *field, elf_vma *high, elf_vma *low) char * adjust_relative_path (const char *file_name, const char *name, - int name_len) + unsigned long name_len) { char * member_file_name; const char * base_name = lbasename (file_name); + size_t amt; /* This is a proxy entry for a thin archive member. If the extended name table contains an absolute path @@ -399,7 +400,10 @@ adjust_relative_path (const char *file_name, const char *name, archive is located. */ if (IS_ABSOLUTE_PATH (name) || base_name == file_name) { - member_file_name = (char *) malloc (name_len + 1); + amt = name_len + 1; + if (amt == 0) + return NULL; + member_file_name = (char *) malloc (amt); if (member_file_name == NULL) { error (_("Out of memory\n")); @@ -413,7 +417,18 @@ adjust_relative_path (const char *file_name, const char *name, /* Concatenate the path components of the archive file name to the relative path name from the extended name table. */ size_t prefix_len = base_name - file_name; - member_file_name = (char *) malloc (prefix_len + name_len + 1); + + amt = prefix_len + name_len + 1; + /* PR 17531: file: 2896dc8b + Catch wraparound. */ + if (amt < prefix_len || amt < name_len) + { + error (_("Abnormal length of thin archive member name: %lx\n"), + name_len); + return NULL; + } + + member_file_name = (char *) malloc (amt); if (member_file_name == NULL) { error (_("Out of memory\n")); @@ -445,6 +460,14 @@ process_archive_index_and_symbols (struct archive_info * arch, unsigned long size; size = strtoul (arch->arhdr.ar_size, NULL, 10); + /* PR 17531: file: 912bd7de. */ + if ((signed long) size < 0) + { + error (_("%s: invalid archive header size: %ld\n"), + arch->file_name, size); + return FALSE; + } + size = size + (size & 1); arch->next_arhdr_offset += sizeof arch->arhdr + size; @@ -623,9 +646,17 @@ setup_archive (struct archive_info *arch, const char *file_name, { /* This is the archive string table holding long member names. */ arch->longnames_size = strtoul (arch->arhdr.ar_size, NULL, 10); + /* PR 17531: file: 01068045. */ + if (arch->longnames_size < 8) + { + error (_("%s: long name table is too small, (size = %ld)\n"), + file_name, arch->longnames_size); + return 1; + } arch->next_arhdr_offset += sizeof arch->arhdr + arch->longnames_size; - arch->longnames = (char *) malloc (arch->longnames_size); + /* Plus one to allow for a string terminator. */ + arch->longnames = (char *) malloc (arch->longnames_size + 1); if (arch->longnames == NULL) { error (_("Out of memory reading long symbol names in archive\n")); @@ -719,17 +750,31 @@ get_archive_member_name (struct archive_info *arch, if (arch->is_thin_archive && endp != NULL && * endp == ':') arch->nested_member_origin = strtoul (endp + 1, NULL, 10); + if (j > arch->longnames_size) + { + error (_("Found long name index (%ld) beyond end of long name table\n"),j); + return NULL; + } while ((j < arch->longnames_size) && (arch->longnames[j] != '\n') && (arch->longnames[j] != '\0')) j++; - if (arch->longnames[j-1] == '/') + if (j > 0 && arch->longnames[j-1] == '/') j--; + if (j > arch->longnames_size) + j = arch->longnames_size; arch->longnames[j] = '\0'; if (!arch->is_thin_archive || arch->nested_member_origin == 0) return arch->longnames + k; + /* PR 17531: file: 2896dc8b. */ + if (k >= j) + { + error (_("Invalid Thin archive member name\n")); + return NULL; + } + /* This is a proxy for a member of a nested archive. Find the name of the member in that archive. */ member_file_name = adjust_relative_path (arch->file_name, |