mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-26 17:18:55 +00:00
readelf reloc range check
A fuzzed object file hit this sanitizer error. readelf.c:16764:9: runtime error: pointer index expression with base 0x6dd4491e1590 overflowed to 0xe7af96d4491e17a1 The same could occur in any of the IN_RANGE reloc checks, where the reloc address is calculated as "start + r_offset" then compared against "start" and "end". So don't do that. Compare r_offset against the memory size, first. * readelf.c (IN_RANGE): Delete. (in_range): New inline funcion. (target_specific_reloc_handling): Replace "end" param with "size". Update uses. Replace IN_RANGE with in_range. (apply_relocations): Delete "end" variable. Update target_specific_reloc_handling calls and replace IN_RANGE. Avoid pointer overflow.
This commit is contained in:
@@ -15503,12 +15503,13 @@ process_syminfo (Filedata * filedata)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* A macro which evaluates to TRUE if the region ADDR .. ADDR + NELEM
|
||||
is contained by the region START .. END. The types of ADDR, START
|
||||
and END should all be the same. Note both ADDR + NELEM and END
|
||||
point to just beyond the end of the regions that are being tested. */
|
||||
#define IN_RANGE(START,END,ADDR,NELEM) \
|
||||
(((ADDR) >= (START)) && ((ADDR) < (END)) && ((ADDR) + (NELEM) <= (END)))
|
||||
/* Check that reloc at R_OFFSET of size R_SIZE can apply to LEN bytes. */
|
||||
|
||||
static inline bool
|
||||
in_range (size_t len, bfd_vma r_offset, unsigned int r_size)
|
||||
{
|
||||
return r_offset <= len && r_size <= len - r_offset;
|
||||
}
|
||||
|
||||
/* Check to see if the given reloc needs to be handled in a target specific
|
||||
manner. If so then process the reloc and return TRUE otherwise return
|
||||
@@ -15522,7 +15523,7 @@ static bool
|
||||
target_specific_reloc_handling (Filedata *filedata,
|
||||
Elf_Internal_Rela *reloc,
|
||||
unsigned char *start,
|
||||
unsigned char *end,
|
||||
size_t size,
|
||||
Elf_Internal_Sym *symtab,
|
||||
uint64_t num_syms)
|
||||
{
|
||||
@@ -15550,9 +15551,9 @@ target_specific_reloc_handling (Filedata *filedata,
|
||||
unsigned int reloc_size = 0;
|
||||
int leb_ret = 0;
|
||||
|
||||
if (reloc->r_offset < (size_t) (end - start))
|
||||
value = read_leb128 (start + reloc->r_offset, end, false,
|
||||
&reloc_size, &leb_ret);
|
||||
if (reloc->r_offset < size)
|
||||
value = read_leb128 (start + reloc->r_offset, start + size,
|
||||
false, &reloc_size, &leb_ret);
|
||||
if (leb_ret != 0 || reloc_size == 0 || reloc_size > 8)
|
||||
error (_("LoongArch ULEB128 field at 0x%lx contains invalid "
|
||||
"ULEB128 value\n"),
|
||||
@@ -15650,8 +15651,8 @@ target_specific_reloc_handling (Filedata *filedata,
|
||||
break;
|
||||
case 11: /* R_MSP430_GNU_SET_ULEB128 */
|
||||
case 22: /* R_MSP430X_GNU_SET_ULEB128 */
|
||||
if (reloc->r_offset < (size_t) (end - start))
|
||||
read_leb128 (start + reloc->r_offset, end, false,
|
||||
if (reloc->r_offset < size)
|
||||
read_leb128 (start + reloc->r_offset, start + size, false,
|
||||
&reloc_size, &leb_ret);
|
||||
break;
|
||||
default:
|
||||
@@ -15671,7 +15672,7 @@ target_specific_reloc_handling (Filedata *filedata,
|
||||
value = reloc->r_addend + (symtab[sym_index].st_value
|
||||
- saved_sym->st_value);
|
||||
|
||||
if (IN_RANGE (start, end, start + reloc->r_offset, reloc_size))
|
||||
if (in_range (size, reloc->r_offset, reloc_size))
|
||||
byte_put (start + reloc->r_offset, value, reloc_size);
|
||||
else
|
||||
/* PR 21137 */
|
||||
@@ -15731,7 +15732,7 @@ target_specific_reloc_handling (Filedata *filedata,
|
||||
value = reloc->r_addend + (symtab[sym_index].st_value
|
||||
- saved_sym->st_value);
|
||||
|
||||
if (IN_RANGE (start, end, start + reloc->r_offset, reloc_size))
|
||||
if (in_range (size, reloc->r_offset, reloc_size))
|
||||
byte_put (start + reloc->r_offset, value, reloc_size);
|
||||
else
|
||||
error (_("MN10300 sym diff reloc contains invalid offset:"
|
||||
@@ -15784,7 +15785,7 @@ target_specific_reloc_handling (Filedata *filedata,
|
||||
break;
|
||||
|
||||
case 0x41: /* R_RL78_ABS32. */
|
||||
if (IN_RANGE (start, end, start + reloc->r_offset, 4))
|
||||
if (in_range (size, reloc->r_offset, 4))
|
||||
byte_put (start + reloc->r_offset, value, 4);
|
||||
else
|
||||
error (_("RL78 sym diff reloc contains invalid offset: "
|
||||
@@ -15794,7 +15795,7 @@ target_specific_reloc_handling (Filedata *filedata,
|
||||
return true;
|
||||
|
||||
case 0x43: /* R_RL78_ABS16. */
|
||||
if (IN_RANGE (start, end, start + reloc->r_offset, 2))
|
||||
if (in_range (size, reloc->r_offset, 2))
|
||||
byte_put (start + reloc->r_offset, value, 2);
|
||||
else
|
||||
error (_("RL78 sym diff reloc contains invalid offset: "
|
||||
@@ -16627,7 +16628,6 @@ apply_relocations (Filedata *filedata,
|
||||
uint64_t *num_relocs_return)
|
||||
{
|
||||
Elf_Internal_Shdr * relsec;
|
||||
unsigned char * end = start + size;
|
||||
|
||||
if (relocs_return != NULL)
|
||||
{
|
||||
@@ -16698,7 +16698,7 @@ apply_relocations (Filedata *filedata,
|
||||
|
||||
reloc_type = get_reloc_type (filedata, rp->r_info);
|
||||
|
||||
if (target_specific_reloc_handling (filedata, rp, start, end, symtab, num_syms))
|
||||
if (target_specific_reloc_handling (filedata, rp, start, size, symtab, num_syms))
|
||||
continue;
|
||||
else if (is_none_reloc (filedata, reloc_type))
|
||||
continue;
|
||||
@@ -16761,8 +16761,7 @@ apply_relocations (Filedata *filedata,
|
||||
continue;
|
||||
}
|
||||
|
||||
rloc = start + rp->r_offset;
|
||||
if (!IN_RANGE (start, end, rloc, reloc_size))
|
||||
if (!in_range (size, rp->r_offset, reloc_size))
|
||||
{
|
||||
warn (_("skipping invalid relocation offset %#" PRIx64
|
||||
" in section %s\n"),
|
||||
@@ -16770,6 +16769,7 @@ apply_relocations (Filedata *filedata,
|
||||
printable_section_name (filedata, section));
|
||||
continue;
|
||||
}
|
||||
rloc = start + rp->r_offset;
|
||||
|
||||
sym_index = get_reloc_symindex (rp->r_info);
|
||||
if (sym_index >= num_syms)
|
||||
@@ -16856,7 +16856,7 @@ apply_relocations (Filedata *filedata,
|
||||
free (symtab);
|
||||
/* Let the target specific reloc processing code know that
|
||||
we have finished with these relocs. */
|
||||
target_specific_reloc_handling (filedata, NULL, NULL, NULL, NULL, 0);
|
||||
target_specific_reloc_handling (filedata, NULL, NULL, 0, NULL, 0);
|
||||
|
||||
if (relocs_return)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user