GNU Binutils with patches for OS216
修訂 | b23dc97fe237a1d9e850d7cbeee066183a00630b (tree) |
---|---|
時間 | 2017-11-28 22:20:31 |
作者 | Nick Clifton <nickc@redh...> |
Commiter | Nick Clifton |
Fix a memory access violation when attempting to parse a corrupt COFF binary with a relocation that points beyond the end of the section to be relocated.
PR 22506
* reloc.c (reloc_offset_in_range): Rename to
bfd_reloc_offset_in_range and export.
(bfd_perform_relocation): Rename function invocation.
(bfd_install_relocation): Likewise.
(bfd_final_link_relocate): Likewise.
* bfd-in2.h: Regenerate.
* coff-arm.c (coff_arm_reloc): Use bfd_reloc_offset_in_range.
* coff-i386.c (coff_i386_reloc): Likewise.
* coff-i860.c (coff_i860_reloc): Likewise.
* coff-m68k.c (mk68kcoff_common_addend_special_fn): Likewise.
* coff-m88k.c (m88k_special_reloc): Likewise.
* coff-mips.c (mips_reflo_reloc): Likewise.
* coff-x86_64.c (coff_amd64_reloc): Likewise.
@@ -1,3 +1,20 @@ | ||
1 | +2017-11-28 Nick Clifton <nickc@redhat.com> | |
2 | + | |
3 | + PR 22506 | |
4 | + * reloc.c (reloc_offset_in_range): Rename to | |
5 | + bfd_reloc_offset_in_range and export. | |
6 | + (bfd_perform_relocation): Rename function invocation. | |
7 | + (bfd_install_relocation): Likewise. | |
8 | + (bfd_final_link_relocate): Likewise. | |
9 | + * bfd-in2.h: Regenerate. | |
10 | + * coff-arm.c (coff_arm_reloc): Use bfd_reloc_offset_in_range. | |
11 | + * coff-i386.c (coff_i386_reloc): Likewise. | |
12 | + * coff-i860.c (coff_i860_reloc): Likewise. | |
13 | + * coff-m68k.c (mk68kcoff_common_addend_special_fn): Likewise. | |
14 | + * coff-m88k.c (m88k_special_reloc): Likewise. | |
15 | + * coff-mips.c (mips_reflo_reloc): Likewise. | |
16 | + * coff-x86_64.c (coff_amd64_reloc): Likewise. | |
17 | + | |
1 | 18 | 2017-11-28 H.J. Lu <hongjiu.lu@intel.com> |
2 | 19 | |
3 | 20 | * elf-m10300.c (mn10300_elf_check_relocs): Don't set |
@@ -2662,6 +2662,12 @@ bfd_reloc_status_type bfd_check_overflow | ||
2662 | 2662 | unsigned int addrsize, |
2663 | 2663 | bfd_vma relocation); |
2664 | 2664 | |
2665 | +bfd_boolean bfd_reloc_offset_in_range | |
2666 | + (reloc_howto_type *howto, | |
2667 | + bfd *abfd, | |
2668 | + asection *section, | |
2669 | + bfd_size_type offset); | |
2670 | + | |
2665 | 2671 | bfd_reloc_status_type bfd_perform_relocation |
2666 | 2672 | (bfd *abfd, |
2667 | 2673 | arelent *reloc_entry, |
@@ -109,41 +109,46 @@ coff_arm_reloc (bfd *abfd, | ||
109 | 109 | x = ((x & ~howto->dst_mask) \ |
110 | 110 | | (((x & howto->src_mask) + diff) & howto->dst_mask)) |
111 | 111 | |
112 | - if (diff != 0) | |
113 | - { | |
114 | - reloc_howto_type *howto = reloc_entry->howto; | |
115 | - unsigned char *addr = (unsigned char *) data + reloc_entry->address; | |
112 | + if (diff != 0) | |
113 | + { | |
114 | + reloc_howto_type *howto = reloc_entry->howto; | |
115 | + unsigned char *addr = (unsigned char *) data + reloc_entry->address; | |
116 | 116 | |
117 | - switch (howto->size) | |
118 | - { | |
119 | - case 0: | |
120 | - { | |
121 | - char x = bfd_get_8 (abfd, addr); | |
122 | - DOIT (x); | |
123 | - bfd_put_8 (abfd, x, addr); | |
124 | - } | |
125 | - break; | |
117 | + if (! bfd_reloc_offset_in_range (howto, abfd, input_section, | |
118 | + reloc_entry->address | |
119 | + * bfd_octets_per_byte (abfd))) | |
120 | + return bfd_reloc_outofrange; | |
126 | 121 | |
127 | - case 1: | |
128 | - { | |
129 | - short x = bfd_get_16 (abfd, addr); | |
130 | - DOIT (x); | |
131 | - bfd_put_16 (abfd, (bfd_vma) x, addr); | |
132 | - } | |
133 | - break; | |
122 | + switch (howto->size) | |
123 | + { | |
124 | + case 0: | |
125 | + { | |
126 | + char x = bfd_get_8 (abfd, addr); | |
127 | + DOIT (x); | |
128 | + bfd_put_8 (abfd, x, addr); | |
129 | + } | |
130 | + break; | |
134 | 131 | |
135 | - case 2: | |
136 | - { | |
137 | - long x = bfd_get_32 (abfd, addr); | |
138 | - DOIT (x); | |
139 | - bfd_put_32 (abfd, (bfd_vma) x, addr); | |
140 | - } | |
141 | - break; | |
132 | + case 1: | |
133 | + { | |
134 | + short x = bfd_get_16 (abfd, addr); | |
135 | + DOIT (x); | |
136 | + bfd_put_16 (abfd, (bfd_vma) x, addr); | |
137 | + } | |
138 | + break; | |
142 | 139 | |
143 | - default: | |
144 | - abort (); | |
140 | + case 2: | |
141 | + { | |
142 | + long x = bfd_get_32 (abfd, addr); | |
143 | + DOIT (x); | |
144 | + bfd_put_32 (abfd, (bfd_vma) x, addr); | |
145 | 145 | } |
146 | - } | |
146 | + break; | |
147 | + | |
148 | + default: | |
149 | + abort (); | |
150 | + } | |
151 | + } | |
147 | 152 | |
148 | 153 | /* Now let bfd_perform_relocation finish everything up. */ |
149 | 154 | return bfd_reloc_continue; |
@@ -144,6 +144,11 @@ coff_i386_reloc (bfd *abfd, | ||
144 | 144 | reloc_howto_type *howto = reloc_entry->howto; |
145 | 145 | unsigned char *addr = (unsigned char *) data + reloc_entry->address; |
146 | 146 | |
147 | + if (! bfd_reloc_offset_in_range (howto, abfd, input_section, | |
148 | + reloc_entry->address | |
149 | + * bfd_octets_per_byte (abfd))) | |
150 | + return bfd_reloc_outofrange; | |
151 | + | |
147 | 152 | switch (howto->size) |
148 | 153 | { |
149 | 154 | case 0: |
@@ -95,6 +95,11 @@ coff_i860_reloc (bfd *abfd, | ||
95 | 95 | reloc_howto_type *howto = reloc_entry->howto; |
96 | 96 | unsigned char *addr = (unsigned char *) data + reloc_entry->address; |
97 | 97 | |
98 | + if (! bfd_reloc_offset_in_range (howto, abfd, input_section, | |
99 | + reloc_entry->address | |
100 | + * bfd_octets_per_byte (abfd))) | |
101 | + return bfd_reloc_outofrange; | |
102 | + | |
98 | 103 | switch (howto->size) |
99 | 104 | { |
100 | 105 | case 0: |
@@ -305,6 +305,11 @@ m68kcoff_common_addend_special_fn (bfd *abfd, | ||
305 | 305 | reloc_howto_type *howto = reloc_entry->howto; |
306 | 306 | unsigned char *addr = (unsigned char *) data + reloc_entry->address; |
307 | 307 | |
308 | + if (! bfd_reloc_offset_in_range (howto, abfd, input_section, | |
309 | + reloc_entry->address | |
310 | + * bfd_octets_per_byte (abfd))) | |
311 | + return bfd_reloc_outofrange; | |
312 | + | |
308 | 313 | switch (howto->size) |
309 | 314 | { |
310 | 315 | case 0: |
@@ -72,10 +72,17 @@ m88k_special_reloc (bfd *abfd, | ||
72 | 72 | { |
73 | 73 | bfd_vma output_base = 0; |
74 | 74 | bfd_vma addr = reloc_entry->address; |
75 | - bfd_vma x = bfd_get_16 (abfd, (bfd_byte *) data + addr); | |
75 | + bfd_vma x; | |
76 | 76 | asection *reloc_target_output_section; |
77 | 77 | long relocation = 0; |
78 | 78 | |
79 | + if (! bfd_reloc_offset_in_range (howto, abfd, input_section, | |
80 | + reloc_entry->address | |
81 | + * bfd_octets_per_byte (abfd))) | |
82 | + return bfd_reloc_outofrange; | |
83 | + | |
84 | + x = bfd_get_16 (abfd, (bfd_byte *) data + addr); | |
85 | + | |
79 | 86 | /* Work out which section the relocation is targeted at and the |
80 | 87 | initial relocation command value. */ |
81 | 88 |
@@ -504,6 +504,12 @@ mips_reflo_reloc (bfd *abfd ATTRIBUTE_UNUSED, | ||
504 | 504 | unsigned long vallo; |
505 | 505 | struct mips_hi *next; |
506 | 506 | |
507 | + if (! bfd_reloc_offset_in_range (reloc_entry->howto, abfd, | |
508 | + input_section, | |
509 | + reloc_entry->address | |
510 | + * bfd_octets_per_byte (abfd))) | |
511 | + return bfd_reloc_outofrange; | |
512 | + | |
507 | 513 | /* Do the REFHI relocation. Note that we actually don't |
508 | 514 | need to know anything about the REFLO itself, except |
509 | 515 | where to find the low 16 bits of the addend needed by the |
@@ -142,17 +142,11 @@ coff_amd64_reloc (bfd *abfd, | ||
142 | 142 | { |
143 | 143 | reloc_howto_type *howto = reloc_entry->howto; |
144 | 144 | unsigned char *addr = (unsigned char *) data + reloc_entry->address; |
145 | - | |
146 | - /* FIXME: We do not have an end address for data, so we cannot | |
147 | - accurately range check any addresses computed against it. | |
148 | - cf: PR binutils/17512: file: 1085-1761-0.004. | |
149 | - For now we do the best that we can. */ | |
150 | - if (addr < (unsigned char *) data | |
151 | - || addr > ((unsigned char *) data) + input_section->size) | |
152 | - { | |
153 | - bfd_set_error (bfd_error_bad_value); | |
154 | - return bfd_reloc_notsupported; | |
155 | - } | |
145 | + | |
146 | + if (! bfd_reloc_offset_in_range (howto, abfd, input_section, | |
147 | + reloc_entry->address | |
148 | + * bfd_octets_per_byte (abfd))) | |
149 | + return bfd_reloc_outofrange; | |
156 | 150 | |
157 | 151 | switch (howto->size) |
158 | 152 | { |
@@ -540,12 +540,31 @@ bfd_check_overflow (enum complain_overflow how, | ||
540 | 540 | return flag; |
541 | 541 | } |
542 | 542 | |
543 | +/* | |
544 | +FUNCTION | |
545 | + bfd_reloc_offset_in_range | |
546 | + | |
547 | +SYNOPSIS | |
548 | + bfd_boolean bfd_reloc_offset_in_range | |
549 | + (reloc_howto_type *howto, | |
550 | + bfd *abfd, | |
551 | + asection *section, | |
552 | + bfd_size_type offset); | |
553 | + | |
554 | +DESCRIPTION | |
555 | + Returns TRUE if the reloc described by @var{HOWTO} can be | |
556 | + applied at @var{OFFSET} octets in @var{SECTION}. | |
557 | + | |
558 | +*/ | |
559 | + | |
543 | 560 | /* HOWTO describes a relocation, at offset OCTET. Return whether the |
544 | 561 | relocation field is within SECTION of ABFD. */ |
545 | 562 | |
546 | -static bfd_boolean | |
547 | -reloc_offset_in_range (reloc_howto_type *howto, bfd *abfd, | |
548 | - asection *section, bfd_size_type octet) | |
563 | +bfd_boolean | |
564 | +bfd_reloc_offset_in_range (reloc_howto_type *howto, | |
565 | + bfd *abfd, | |
566 | + asection *section, | |
567 | + bfd_size_type octet) | |
549 | 568 | { |
550 | 569 | bfd_size_type octet_end = bfd_get_section_limit_octets (abfd, section); |
551 | 570 | bfd_size_type reloc_size = bfd_get_reloc_size (howto); |
@@ -619,6 +638,11 @@ bfd_perform_relocation (bfd *abfd, | ||
619 | 638 | if (howto && howto->special_function) |
620 | 639 | { |
621 | 640 | bfd_reloc_status_type cont; |
641 | + | |
642 | + /* Note - we do not call bfd_reloc_offset_in_range here as the | |
643 | + reloc_entry->address field might actually be valid for the | |
644 | + backend concerned. It is up to the special_function itself | |
645 | + to call bfd_reloc_offset_in_range if needed. */ | |
622 | 646 | cont = howto->special_function (abfd, reloc_entry, symbol, data, |
623 | 647 | input_section, output_bfd, |
624 | 648 | error_message); |
@@ -639,7 +663,7 @@ bfd_perform_relocation (bfd *abfd, | ||
639 | 663 | |
640 | 664 | /* Is the address of the relocation really within the section? */ |
641 | 665 | octets = reloc_entry->address * bfd_octets_per_byte (abfd); |
642 | - if (!reloc_offset_in_range (howto, abfd, input_section, octets)) | |
666 | + if (!bfd_reloc_offset_in_range (howto, abfd, input_section, octets)) | |
643 | 667 | return bfd_reloc_outofrange; |
644 | 668 | |
645 | 669 | /* Work out which section the relocation is targeted at and the |
@@ -1005,6 +1029,10 @@ bfd_install_relocation (bfd *abfd, | ||
1005 | 1029 | { |
1006 | 1030 | bfd_reloc_status_type cont; |
1007 | 1031 | |
1032 | + /* Note - we do not call bfd_reloc_offset_in_range here as the | |
1033 | + reloc_entry->address field might actually be valid for the | |
1034 | + backend concerned. It is up to the special_function itself | |
1035 | + to call bfd_reloc_offset_in_range if needed. */ | |
1008 | 1036 | /* XXX - The special_function calls haven't been fixed up to deal |
1009 | 1037 | with creating new relocations and section contents. */ |
1010 | 1038 | cont = howto->special_function (abfd, reloc_entry, symbol, |
@@ -1027,7 +1055,7 @@ bfd_install_relocation (bfd *abfd, | ||
1027 | 1055 | |
1028 | 1056 | /* Is the address of the relocation really within the section? */ |
1029 | 1057 | octets = reloc_entry->address * bfd_octets_per_byte (abfd); |
1030 | - if (!reloc_offset_in_range (howto, abfd, input_section, octets)) | |
1058 | + if (!bfd_reloc_offset_in_range (howto, abfd, input_section, octets)) | |
1031 | 1059 | return bfd_reloc_outofrange; |
1032 | 1060 | |
1033 | 1061 | /* Work out which section the relocation is targeted at and the |
@@ -1365,7 +1393,7 @@ _bfd_final_link_relocate (reloc_howto_type *howto, | ||
1365 | 1393 | bfd_size_type octets = address * bfd_octets_per_byte (input_bfd); |
1366 | 1394 | |
1367 | 1395 | /* Sanity check the address. */ |
1368 | - if (!reloc_offset_in_range (howto, input_bfd, input_section, octets)) | |
1396 | + if (!bfd_reloc_offset_in_range (howto, input_bfd, input_section, octets)) | |
1369 | 1397 | return bfd_reloc_outofrange; |
1370 | 1398 | |
1371 | 1399 | /* This function assumes that we are dealing with a basic relocation |