From e453f6cd0ccdd64a3f5f156e2c5f70085e9289e7 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Sun, 16 Oct 2011 09:34:51 -0400 Subject: Fix potential problem with skipping relocations We never seem to have hit this problem but way relative relocations were skipped was wrong. There are relative relocations only in the DT_REL/DT_RELA section. The elf_dynamic_do_##reloc function skipped the entries in all calls, though. --- elf/do-rel.h | 17 ++++++----------- elf/dynamic-link.h | 31 +++++++++++++++++++++---------- 2 files changed, 27 insertions(+), 21 deletions(-) (limited to 'elf') diff --git a/elf/do-rel.h b/elf/do-rel.h index 6187b9e..69f2f0e 100644 --- a/elf/do-rel.h +++ b/elf/do-rel.h @@ -21,13 +21,10 @@ `elf_dynamic_do_rel' and `elf_dynamic_do_rela'. */ #ifdef DO_RELA -# define elf_dynamic_do_rel elf_dynamic_do_rela -# define RELCOUNT_IDX VERSYMIDX (DT_RELACOUNT) +# define elf_dynamic_do_Rel elf_dynamic_do_Rela # define Rel Rela # define elf_machine_rel elf_machine_rela # define elf_machine_rel_relative elf_machine_rela_relative -#else -# define RELCOUNT_IDX VERSYMIDX (DT_RELCOUNT) #endif #ifndef DO_ELF_MACHINE_REL_RELATIVE @@ -50,9 +47,9 @@ than fully resolved now. */ auto inline void __attribute__ ((always_inline)) -elf_dynamic_do_rel (struct link_map *map, +elf_dynamic_do_Rel (struct link_map *map, ElfW(Addr) reladdr, ElfW(Addr) relsize, - int lazy, int skip_ifunc) + ElfW(Word) nrelative, int lazy, int skip_ifunc) { const ElfW(Rel) *r = (const void *) reladdr; const ElfW(Rel) *end = (const void *) (reladdr + relsize); @@ -73,10 +70,8 @@ elf_dynamic_do_rel (struct link_map *map, { const ElfW(Sym) *const symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]); - ElfW(Word) nrelative = (map->l_info[RELCOUNT_IDX] == NULL - ? 0 : map->l_info[RELCOUNT_IDX]->d_un.d_val); const ElfW(Rel) *relative = r; - r = r + MIN (nrelative, relsize / sizeof (ElfW(Rel))); + r += nrelative; #ifndef RTLD_BOOTSTRAP /* This is defined in rtld.c, but nowhere in the static libc.a; make @@ -131,9 +126,9 @@ elf_dynamic_do_rel (struct link_map *map, } } -#undef elf_dynamic_do_rel +#undef elf_dynamic_do_Rel #undef Rel #undef elf_machine_rel #undef elf_machine_rel_relative #undef DO_ELF_MACHINE_REL_RELATIVE -#undef RELCOUNT_IDX +#undef DO_RELA diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h index 2bdab45..486408d 100644 --- a/elf/dynamic-link.h +++ b/elf/dynamic-link.h @@ -258,17 +258,23 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) # ifdef ELF_MACHINE_PLTREL_OVERLAP # define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, skip_ifunc, test_rel) \ do { \ - struct { ElfW(Addr) start, size; int lazy; } ranges[3]; \ + struct { ElfW(Addr) start, size; ElfW(Word) nrelative; int lazy; } \ + ranges[3]; \ int ranges_index; \ \ ranges[0].lazy = ranges[2].lazy = 0; \ ranges[1].lazy = 1; \ ranges[0].size = ranges[1].size = ranges[2].size = 0; \ + ranges[0].nrelative = ranges[1].nrelative = ranges[2].nrelative = 0; \ \ if ((map)->l_info[DT_##RELOC]) \ { \ ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \ ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \ + if (map->l_info[VERSYMIDX (DT_##RELOC##COUNT)] != NULL) \ + ranges[0].nrelative \ + = MIN (map->l_info[VERSYMIDX (DT_##RELOC##COUNT)]->d_un.d_val, \ + ranges[0].size / sizeof (ElfW(reloc))); \ } \ \ if ((do_lazy) \ @@ -286,21 +292,24 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) elf_dynamic_do_##reloc ((map), \ ranges[ranges_index].start, \ ranges[ranges_index].size, \ + ranges[ranges_index].nrelative, \ ranges[ranges_index].lazy, \ skip_ifunc); \ } while (0) # else # define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, skip_ifunc, test_rel) \ do { \ - struct { ElfW(Addr) start, size; int lazy; } ranges[2]; \ - ranges[0].lazy = 0; \ - ranges[0].size = ranges[1].size = 0; \ - ranges[0].start = 0; \ + struct { ElfW(Addr) start, size; ElfW(Word) nrelative; int lazy; } \ + ranges[2] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }; \ \ if ((map)->l_info[DT_##RELOC]) \ { \ ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \ ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \ + if (map->l_info[VERSYMIDX (DT_##RELOC##COUNT)] != NULL) \ + ranges[0].nrelative \ + = MIN (map->l_info[VERSYMIDX (DT_##RELOC##COUNT)]->d_un.d_val, \ + ranges[0].size / sizeof (ElfW(reloc))); \ } \ if ((map)->l_info[DT_PLTREL] \ && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \ @@ -312,7 +321,8 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) /* This test does not only detect whether the relocation \ sections are in the right order, it also checks whether \ there is a DT_REL/DT_RELA section. */ \ - || ranges[0].start + ranges[0].size != start)) \ + || __builtin_expect (ranges[0].start + ranges[0].size \ + != start, 0))) \ { \ ranges[1].start = start; \ ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \ @@ -327,8 +337,8 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) } \ \ if (ELF_DURING_STARTUP) \ - elf_dynamic_do_##reloc ((map), ranges[0].start, ranges[0].size, 0, \ - skip_ifunc); \ + elf_dynamic_do_##reloc ((map), ranges[0].start, ranges[0].size, \ + ranges[0].nrelative, 0, skip_ifunc); \ else \ { \ int ranges_index; \ @@ -336,6 +346,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) elf_dynamic_do_##reloc ((map), \ ranges[ranges_index].start, \ ranges[ranges_index].size, \ + ranges[ranges_index].nrelative, \ ranges[ranges_index].lazy, \ skip_ifunc); \ } \ @@ -351,7 +362,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) # if ! ELF_MACHINE_NO_REL # include "do-rel.h" # define ELF_DYNAMIC_DO_REL(map, lazy, skip_ifunc) \ - _ELF_DYNAMIC_DO_RELOC (REL, rel, map, lazy, skip_ifunc, _ELF_CHECK_REL) + _ELF_DYNAMIC_DO_RELOC (REL, Rel, map, lazy, skip_ifunc, _ELF_CHECK_REL) # else # define ELF_DYNAMIC_DO_REL(map, lazy, skip_ifunc) /* Nothing to do. */ # endif @@ -360,7 +371,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) # define DO_RELA # include "do-rel.h" # define ELF_DYNAMIC_DO_RELA(map, lazy, skip_ifunc) \ - _ELF_DYNAMIC_DO_RELOC (RELA, rela, map, lazy, skip_ifunc, _ELF_CHECK_REL) + _ELF_DYNAMIC_DO_RELOC (RELA, Rela, map, lazy, skip_ifunc, _ELF_CHECK_REL) # else # define ELF_DYNAMIC_DO_RELA(map, lazy, skip_ifunc) /* Nothing to do. */ # endif -- cgit v1.1