aboutsummaryrefslogtreecommitdiff
path: root/elf
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2021-11-19 06:18:56 -0800
committerH.J. Lu <hjl.tools@gmail.com>2022-04-26 10:16:11 -0700
commit57292f574156f817b7cbeb33ea6278c6eab22bcc (patch)
tree07c80714e7f6aa9a74647bbe1585e1c921f27ba4 /elf
parent4610b24f5e4e6d2c4b769594efa6d460943163bb (diff)
downloadglibc-57292f574156f817b7cbeb33ea6278c6eab22bcc.zip
glibc-57292f574156f817b7cbeb33ea6278c6eab22bcc.tar.gz
glibc-57292f574156f817b7cbeb33ea6278c6eab22bcc.tar.bz2
Add GLIBC_ABI_DT_RELR for DT_RELR support
The EI_ABIVERSION field of the ELF header in executables and shared libraries can be bumped to indicate the minimum ABI requirement on the dynamic linker. However, EI_ABIVERSION in executables isn't checked by the Linux kernel ELF loader nor the existing dynamic linker. Executables will crash mysteriously if the dynamic linker doesn't support the ABI features required by the EI_ABIVERSION field. The dynamic linker should be changed to check EI_ABIVERSION in executables. Add a glibc version, GLIBC_ABI_DT_RELR, to indicate DT_RELR support so that the existing dynamic linkers will issue an error on executables with GLIBC_ABI_DT_RELR dependency. When there is a DT_VERNEED entry with libc.so on DT_NEEDED, issue an error if there is a DT_RELR entry without GLIBC_ABI_DT_RELR dependency. Support __placeholder_only_for_empty_version_map as the placeholder symbol used only for empty version map to generate GLIBC_ABI_DT_RELR without any symbols.
Diffstat (limited to 'elf')
-rw-r--r--elf/Makefile14
-rw-r--r--elf/Versions5
-rw-r--r--elf/dl-version.c35
3 files changed, 50 insertions, 4 deletions
diff --git a/elf/Makefile b/elf/Makefile
index e4907d5..073807b 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -1145,8 +1145,12 @@ $(eval $(call include_dsosort_tests,dso-sort-tests-1.def))
$(eval $(call include_dsosort_tests,dso-sort-tests-2.def))
endif
-check-abi: $(objpfx)check-abi-ld.out
-tests-special += $(objpfx)check-abi-ld.out
+check-abi: $(objpfx)check-abi-ld.out \
+ $(objpfx)check-abi-version-libc.out
+tests-special += \
+ $(objpfx)check-abi-ld.out \
+ $(objpfx)check-abi-version-libc.out \
+# tests-special
update-abi: update-abi-ld
update-all-abi: update-all-abi-ld
@@ -2779,3 +2783,9 @@ $(objpfx)tst-p_align3: $(objpfx)tst-p_alignmod3.so
$(objpfx)tst-p_align3.out: tst-p_align3.sh $(objpfx)tst-p_align3
$(SHELL) $< $(common-objpfx) '$(test-program-prefix)'; \
$(evaluate-test)
+
+$(objpfx)check-abi-version-libc.out: $(common-objpfx)libc.so
+ LC_ALL=C $(READELF) -V -W $< \
+ | sed -ne '/.gnu.version_d/, /.gnu.version_r/ p' \
+ | grep GLIBC_ABI_DT_RELR > $@; \
+ $(evaluate-test)
diff --git a/elf/Versions b/elf/Versions
index 8bed855..a9ff278 100644
--- a/elf/Versions
+++ b/elf/Versions
@@ -23,6 +23,11 @@ libc {
GLIBC_2.35 {
_dl_find_object;
}
+ GLIBC_ABI_DT_RELR {
+ # This symbol is used only for empty version map and will be removed
+ # by scripts/versions.awk.
+ __placeholder_only_for_empty_version_map;
+ }
GLIBC_PRIVATE {
# functions used in other libraries
__libc_early_init;
diff --git a/elf/dl-version.c b/elf/dl-version.c
index b47bd91..cda0889 100644
--- a/elf/dl-version.c
+++ b/elf/dl-version.c
@@ -214,12 +214,19 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
while (1)
{
/* Match the symbol. */
+ const char *string = strtab + aux->vna_name;
result |= match_symbol (DSO_FILENAME (map->l_name),
map->l_ns, aux->vna_hash,
- strtab + aux->vna_name,
- needed->l_real, verbose,
+ string, needed->l_real, verbose,
aux->vna_flags & VER_FLG_WEAK);
+ /* 0xfd0e42: _dl_elf_hash ("GLIBC_ABI_DT_RELR"). */
+ if (aux->vna_hash == 0xfd0e42
+ && __glibc_likely (strcmp (string,
+ "GLIBC_ABI_DT_RELR")
+ == 0))
+ map->l_dt_relr_ref = 1;
+
/* Compare the version index. */
if ((unsigned int) (aux->vna_other & 0x7fff) > ndx_high)
ndx_high = aux->vna_other & 0x7fff;
@@ -352,6 +359,30 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
}
}
+ /* When there is a DT_VERNEED entry with libc.so on DT_NEEDED, issue
+ an error if there is a DT_RELR entry without GLIBC_ABI_DT_RELR
+ dependency. */
+ if (dyn != NULL
+ && map->l_info[DT_NEEDED] != NULL
+ && map->l_info[DT_RELR] != NULL
+ && __glibc_unlikely (!map->l_dt_relr_ref))
+ {
+ const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
+ const ElfW(Dyn) *d;
+ for (d = map->l_ld; d->d_tag != DT_NULL; ++d)
+ if (d->d_tag == DT_NEEDED)
+ {
+ const char *name = strtab + d->d_un.d_val;
+ if (strncmp (name, "libc.so.", 8) == 0)
+ {
+ _dl_exception_create
+ (&exception, DSO_FILENAME (map->l_name),
+ N_("DT_RELR without GLIBC_ABI_DT_RELR dependency"));
+ goto call_error;
+ }
+ }
+ }
+
return result;
}