mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-21 12:30:06 +00:00
Revert "Detect ld.so and libc.so version inconsistency during startup"
This reverts commit 6f85dbf102
.
Once this change hits the release branches, it will require relinking
of all statically linked applications before static dlopen works
again, for the majority of updates on release branches: The NEWS file
is regularly updated with bug references, so the __libc_early_init
suffix changes, and static dlopen cannot find the function anymore.
While this ABI check is still technically correct (we do require
rebuilding & relinking after glibc updates to keep static dlopen
working), it is too drastic for stable release branches.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
This commit is contained in:
parent
025a8cce63
commit
89baed0b93
10
INSTALL
10
INSTALL
@ -120,16 +120,6 @@ if 'CFLAGS' is specified it must enable optimization. For example:
|
||||
compiler flags which target a later instruction set architecture
|
||||
(ISA).
|
||||
|
||||
'--with-extra-version-id=STRING'
|
||||
Use STRING as part of the fingerprint that is used by the dynamic
|
||||
linker to detect an incompatible version of 'libc.so'. For
|
||||
example, STRING could be the full package version and release
|
||||
string used by a distribution build of the GNU C Library. This
|
||||
way, concurrent process creation during a package update will fail
|
||||
with an error message, _error while loading shared libraries:
|
||||
/lib64/libc.so.6: ld.so/libc.so mismatch detected (upgrade in
|
||||
progress?)_, rather than crashing mysteriously.
|
||||
|
||||
'--with-timeoutfactor=NUM'
|
||||
Specify an integer NUM to scale the timeout of test programs. This
|
||||
factor can be changed at run time using 'TIMEOUTFACTOR' environment
|
||||
|
14
Makerules
14
Makerules
@ -112,20 +112,6 @@ before-compile := $(common-objpfx)first-versions.h \
|
||||
$(common-objpfx)ldbl-compat-choose.h $(before-compile)
|
||||
$(common-objpfx)first-versions.h: $(common-objpfx)versions.stmp
|
||||
$(common-objpfx)ldbl-compat-choose.h: $(common-objpfx)versions.stmp
|
||||
|
||||
# libc_early_init_name.h provides the actual name of the
|
||||
# __libc_early_init function. It is used as a protocol version marker
|
||||
# between ld.so and libc.so
|
||||
before-compile := $(common-objpfx)libc_early_init_name.h $(before-compile)
|
||||
libc_early_init_name-deps = \
|
||||
$(..)NEWS $(..)sysdeps/generic/ldsodefs.h $(..)include/link.h
|
||||
$(common-objpfx)libc_early_init_name.h: $(..)scripts/libc_early_init_name.py \
|
||||
$(common-objpfx)config.make $(libc_early_init_name-deps)
|
||||
$(PYTHON) $(..)scripts/libc_early_init_name.py \
|
||||
--output=$@T \
|
||||
--extra-version-id="$(extra-version-id)" \
|
||||
$(libc_early_init_name-deps)
|
||||
$(move-if-change) $@T $@
|
||||
endif # avoid-generated
|
||||
endif # $(build-shared) = yes
|
||||
|
||||
|
7
NEWS
7
NEWS
@ -9,12 +9,7 @@ Version 2.37
|
||||
|
||||
Major new features:
|
||||
|
||||
* The dynamic loader now prints an error message, "ld.so/libc.so
|
||||
mismatch detected (upgrade in progress?)" if it detects that the
|
||||
version of libc.so it loaded comes from a different build of glibc.
|
||||
The new configure option --with-extra-version-id can be used to
|
||||
specify an arbitrary string that affects the computation of the
|
||||
version fingerprint.
|
||||
[Add new features here]
|
||||
|
||||
Deprecated and removed features, and other changes affecting compatibility:
|
||||
|
||||
|
@ -98,7 +98,6 @@ build-hardcoded-path-in-tests= @hardcoded_path_in_tests@
|
||||
build-pt-chown = @build_pt_chown@
|
||||
have-tunables = @have_tunables@
|
||||
pthread-in-libc = @pthread_in_libc@
|
||||
extra-version-id = @extra_version_id@
|
||||
|
||||
# Build tools.
|
||||
CC = @CC@
|
||||
|
11
configure
vendored
11
configure
vendored
@ -760,7 +760,6 @@ with_headers
|
||||
with_default_link
|
||||
with_nonshared_cflags
|
||||
with_rtld_early_cflags
|
||||
with_extra_version_id
|
||||
with_timeoutfactor
|
||||
enable_sanity_checks
|
||||
enable_shared
|
||||
@ -1482,9 +1481,6 @@ Optional Packages:
|
||||
build nonshared libraries with additional CFLAGS
|
||||
--with-rtld-early-cflags=CFLAGS
|
||||
build early initialization with additional CFLAGS
|
||||
--extra-version-id=STRING
|
||||
specify an extra version string to use in internal
|
||||
ABI checks
|
||||
--with-timeoutfactor=NUM
|
||||
specify an integer to scale the timeout
|
||||
--with-cpu=CPU select code for CPU variant
|
||||
@ -3401,13 +3397,6 @@ fi
|
||||
|
||||
|
||||
|
||||
# Check whether --with-extra-version-id was given.
|
||||
if test "${with_extra_version_id+set}" = set; then :
|
||||
withval=$with_extra_version_id; extra_version_id="$withval"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# Check whether --with-timeoutfactor was given.
|
||||
if test "${with_timeoutfactor+set}" = set; then :
|
||||
withval=$with_timeoutfactor; timeoutfactor=$withval
|
||||
|
@ -169,11 +169,6 @@ AC_ARG_WITH([rtld-early-cflags],
|
||||
[rtld_early_cflags=])
|
||||
AC_SUBST(rtld_early_cflags)
|
||||
|
||||
AC_ARG_WITH([extra-version-id],
|
||||
AS_HELP_STRING([--extra-version-id=STRING],
|
||||
[specify an extra version string to use in internal ABI checks]),
|
||||
[extra_version_id="$withval"])
|
||||
|
||||
AC_ARG_WITH([timeoutfactor],
|
||||
AS_HELP_STRING([--with-timeoutfactor=NUM],
|
||||
[specify an integer to scale the timeout]),
|
||||
|
@ -52,6 +52,7 @@ routines = \
|
||||
# The core dynamic linking functions are in libc for the static and
|
||||
# profiled libraries.
|
||||
dl-routines = \
|
||||
dl-call-libc-early-init \
|
||||
dl-close \
|
||||
dl-debug \
|
||||
dl-debug-symbols \
|
||||
@ -64,7 +65,6 @@ dl-routines = \
|
||||
dl-load \
|
||||
dl-lookup \
|
||||
dl-lookup-direct \
|
||||
dl-lookup_libc_early_init \
|
||||
dl-minimal-malloc \
|
||||
dl-misc \
|
||||
dl-object \
|
||||
|
@ -29,8 +29,8 @@ libc {
|
||||
__placeholder_only_for_empty_version_map;
|
||||
}
|
||||
GLIBC_PRIVATE {
|
||||
# A pattern is needed here because the suffix is dynamically generated.
|
||||
__libc_early_init_*;
|
||||
# functions used in other libraries
|
||||
__libc_early_init;
|
||||
|
||||
# Internal error handling support. Interposes the functions in ld.so.
|
||||
_dl_signal_exception; _dl_catch_exception;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Find the address of the __libc_early_init function.
|
||||
/* Invoke the early initialization function in libc.so.
|
||||
Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
@ -16,21 +16,26 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <ldsodefs.h>
|
||||
#include <libc-early-init.h>
|
||||
#include <link.h>
|
||||
#include <stddef.h>
|
||||
|
||||
__typeof (__libc_early_init) *
|
||||
_dl_lookup_libc_early_init (struct link_map *libc_map)
|
||||
void
|
||||
_dl_call_libc_early_init (struct link_map *libc_map, _Bool initial)
|
||||
{
|
||||
/* There is nothing to do if we did not actually load libc.so. */
|
||||
if (libc_map == NULL)
|
||||
return;
|
||||
|
||||
const ElfW(Sym) *sym
|
||||
= _dl_lookup_direct (libc_map, LIBC_EARLY_INIT_NAME_STRING,
|
||||
LIBC_EARLY_INIT_GNU_HASH,
|
||||
= _dl_lookup_direct (libc_map, "__libc_early_init",
|
||||
0x069682ac, /* dl_new_hash output. */
|
||||
"GLIBC_PRIVATE",
|
||||
0x0963cf85); /* _dl_elf_hash output. */
|
||||
if (sym == NULL)
|
||||
_dl_signal_error (0, libc_map->l_name, NULL, "\
|
||||
ld.so/libc.so mismatch detected (upgrade in progress?)");
|
||||
return DL_SYMBOL_ADDRESS (libc_map, sym);
|
||||
assert (sym != NULL);
|
||||
__typeof (__libc_early_init) *early_init
|
||||
= DL_SYMBOL_ADDRESS (libc_map, sym);
|
||||
early_init (initial);
|
||||
}
|
@ -31,6 +31,7 @@
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <gnu/lib-names.h>
|
||||
|
||||
/* Type for the buffer we put the ELF header and hopefully the program
|
||||
header. This buffer does not really have to be too large. In most
|
||||
@ -1465,6 +1466,14 @@ cannot enable executable stack as shared object requires");
|
||||
add_name_to_object (l, ((const char *) D_PTR (l, l_info[DT_STRTAB])
|
||||
+ l->l_info[DT_SONAME]->d_un.d_val));
|
||||
|
||||
/* If we have newly loaded libc.so, update the namespace
|
||||
description. */
|
||||
if (GL(dl_ns)[nsid].libc_map == NULL
|
||||
&& l->l_info[DT_SONAME] != NULL
|
||||
&& strcmp (((const char *) D_PTR (l, l_info[DT_STRTAB])
|
||||
+ l->l_info[DT_SONAME]->d_un.d_val), LIBC_SO) == 0)
|
||||
GL(dl_ns)[nsid].libc_map = l;
|
||||
|
||||
/* _dl_close can only eventually undo the module ID assignment (via
|
||||
remove_slotinfo) if this function returns a pointer to a link
|
||||
map. Therefore, delay this step until all possibilities for
|
||||
|
@ -760,8 +760,8 @@ dl_open_worker_begin (void *a)
|
||||
if (!args->libc_already_loaded)
|
||||
{
|
||||
/* dlopen cannot be used to load an initial libc by design. */
|
||||
if (GL(dl_ns)[args->nsid].libc_map != NULL)
|
||||
GL(dl_ns)[args->nsid].libc_map_early_init (false);
|
||||
struct link_map *libc_map = GL(dl_ns)[args->nsid].libc_map;
|
||||
_dl_call_libc_early_init (libc_map, false);
|
||||
}
|
||||
|
||||
args->worker_continue = true;
|
||||
|
@ -23,8 +23,6 @@
|
||||
#include <string.h>
|
||||
#include <ldsodefs.h>
|
||||
#include <_itoa.h>
|
||||
#include <gnu/lib-names.h>
|
||||
#include <libc-early-init.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
@ -361,22 +359,6 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
|
||||
}
|
||||
}
|
||||
|
||||
/* Detect a libc.so loaded into this namespace. The
|
||||
__libc_early_init lookup below means that we have to do this
|
||||
after parsing the version data. */
|
||||
if (GL(dl_ns)[map->l_ns].libc_map == NULL
|
||||
&& map->l_info[DT_SONAME] != NULL
|
||||
&& strcmp (((const char *) D_PTR (map, l_info[DT_STRTAB])
|
||||
+ map->l_info[DT_SONAME]->d_un.d_val), LIBC_SO) == 0)
|
||||
{
|
||||
/* Look up this symbol early to trigger a mismatch error before
|
||||
relocation (which may call IFUNC resolvers, and those can
|
||||
have an internal ABI dependency). */
|
||||
GL(dl_ns)[map->l_ns].libc_map_early_init
|
||||
= _dl_lookup_libc_early_init (map);
|
||||
GL(dl_ns)[map->l_ns].libc_map = map;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
@ -19,10 +19,13 @@
|
||||
#ifndef _LIBC_EARLY_INIT_H
|
||||
#define _LIBC_EARLY_INIT_H
|
||||
|
||||
#include <libc_early_init_name.h>
|
||||
|
||||
struct link_map;
|
||||
|
||||
/* If LIBC_MAP is not NULL, look up the __libc_early_init symbol in it
|
||||
and call this function, with INITIAL as the argument. */
|
||||
void _dl_call_libc_early_init (struct link_map *libc_map, _Bool initial)
|
||||
attribute_hidden;
|
||||
|
||||
/* In the shared case, this function is defined in libc.so and invoked
|
||||
from ld.so (or on the fist static dlopen) after complete relocation
|
||||
of a new loaded libc.so, but before user-defined ELF constructors
|
||||
@ -30,18 +33,6 @@ struct link_map;
|
||||
startup code. If INITIAL is true, the libc being initialized is
|
||||
the libc for the main program. INITIAL is false for libcs loaded
|
||||
for audit modules, dlmopen, and static dlopen. */
|
||||
void __libc_early_init (_Bool initial)
|
||||
#ifdef SHARED
|
||||
/* Redirect to the actual implementation name. */
|
||||
__asm__ (LIBC_EARLY_INIT_NAME_STRING)
|
||||
#endif
|
||||
;
|
||||
|
||||
/* Attempts to find the appropriately named __libc_early_init function
|
||||
in LIBC_MAP. On lookup failure, an exception is signaled,
|
||||
indicating an ld.so/libc.so mismatch. */
|
||||
__typeof (__libc_early_init) *_dl_lookup_libc_early_init (struct link_map *
|
||||
libc_map)
|
||||
attribute_hidden;
|
||||
void __libc_early_init (_Bool initial);
|
||||
|
||||
#endif /* _LIBC_EARLY_INIT_H */
|
||||
|
12
elf/rtld.c
12
elf/rtld.c
@ -1707,6 +1707,15 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
/* Extract the contents of the dynamic section for easy access. */
|
||||
elf_get_dynamic_info (main_map, false, false);
|
||||
|
||||
/* If the main map is libc.so, update the base namespace to
|
||||
refer to this map. If libc.so is loaded later, this happens
|
||||
in _dl_map_object_from_fd. */
|
||||
if (main_map->l_info[DT_SONAME] != NULL
|
||||
&& (strcmp (((const char *) D_PTR (main_map, l_info[DT_STRTAB])
|
||||
+ main_map->l_info[DT_SONAME]->d_un.d_val), LIBC_SO)
|
||||
== 0))
|
||||
GL(dl_ns)[LM_ID_BASE].libc_map = main_map;
|
||||
|
||||
/* Set up our cache of pointers into the hash table. */
|
||||
_dl_setup_hash (main_map);
|
||||
}
|
||||
@ -2377,8 +2386,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
/* Relocation is complete. Perform early libc initialization. This
|
||||
is the initial libc, even if audit modules have been loaded with
|
||||
other libcs. */
|
||||
if (GL(dl_ns)[LM_ID_BASE].libc_map != NULL)
|
||||
GL(dl_ns)[LM_ID_BASE].libc_map_early_init (true);
|
||||
_dl_call_libc_early_init (GL(dl_ns)[LM_ID_BASE].libc_map, true);
|
||||
|
||||
/* Do any necessary cleanups for the startup OS interface code.
|
||||
We do these now so that no calls are made after rtld re-relocation
|
||||
|
@ -144,15 +144,6 @@ dynamic linker diagnostics to run on CPUs which are not compatible with
|
||||
the rest of @theglibc{}, for example, due to compiler flags which target
|
||||
a later instruction set architecture (ISA).
|
||||
|
||||
@item --with-extra-version-id=@var{string}
|
||||
Use @var{string} as part of the fingerprint that is used by the dynamic
|
||||
linker to detect an incompatible version of @file{libc.so}. For
|
||||
example, @var{string} could be the full package version and release
|
||||
string used by a distribution build of @theglibc{}. This way,
|
||||
concurrent process creation during a package update will fail with an
|
||||
error message, @emph{ld.so/libc.so mismatch detected (upgrade in
|
||||
progress?)}, rather than crashing mysteriously.
|
||||
|
||||
@item --with-timeoutfactor=@var{NUM}
|
||||
Specify an integer @var{NUM} to scale the timeout of test programs.
|
||||
This factor can be changed at run time using @env{TIMEOUTFACTOR}
|
||||
|
@ -1,89 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
# Compute the hash-based name of the __libc_early_init function.
|
||||
# Copyright (C) 2022 Free Software Foundation, Inc.
|
||||
# This file is part of the GNU C Library.
|
||||
#
|
||||
# The GNU C Library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# The GNU C Library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with the GNU C Library; if not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
|
||||
"""Compute the name of the __libc_early_init function, which is used
|
||||
as a protocol version marker between ld.so and libc.so.
|
||||
|
||||
The name contains a hash suffix, and the hash changes if certain key
|
||||
files in the source tree change. Distributions can also configure
|
||||
with --with-extra-version-id, to make the computed hash dependent on
|
||||
the package version.
|
||||
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import os
|
||||
import string
|
||||
import sys
|
||||
|
||||
def gnu_hash(s):
|
||||
"""Computes the GNU hash of the string."""
|
||||
h = 5381
|
||||
for ch in s:
|
||||
if type(ch) is not int:
|
||||
ch = ord(ch)
|
||||
h = (h * 33 + ch) & 0xffffffff
|
||||
return h
|
||||
|
||||
# Parse the command line.
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--output', metavar='PATH',
|
||||
help='path to header file this tool generates')
|
||||
parser.add_argument('--extra-version-id', metavar='ID',
|
||||
help='extra string to influence hash computation')
|
||||
parser.add_argument('inputs', metavar='PATH', nargs='*',
|
||||
help='files whose contents influences the generated hash')
|
||||
opts = parser.parse_args()
|
||||
|
||||
# Obtain the blobs that affect the generated hash.
|
||||
blobs = [(opts.extra_version_id or '').encode('UTF-8')]
|
||||
for path in opts.inputs:
|
||||
with open(path, 'rb') as inp:
|
||||
blobs.append(inp.read())
|
||||
|
||||
# Hash the file boundaries.
|
||||
md = hashlib.sha256()
|
||||
md.update(repr([len(blob) for blob in blobs]).encode('UTF-8'))
|
||||
|
||||
# And then hash the file contents. Do not hash the paths, to avoid
|
||||
# impacting reproducibility.
|
||||
for blob in blobs:
|
||||
md.update(blob)
|
||||
|
||||
# These are the bits used to compute the suffix.
|
||||
derived_bits = int.from_bytes(md.digest(), byteorder='big', signed=False)
|
||||
|
||||
# These digits are used in the suffix (should result in base-62 encoding).
|
||||
# They must be valid in C identifiers.
|
||||
digits = string.digits + string.ascii_letters
|
||||
|
||||
# Generate eight digits as a suffix. They should provide enough
|
||||
# uniqueness (47.6 bits).
|
||||
name = '__libc_early_init_'
|
||||
for n in range(8):
|
||||
name += digits[derived_bits % len(digits)]
|
||||
derived_bits //= len(digits)
|
||||
|
||||
# Write the output file.
|
||||
with open(opts.output, 'w') if opts.output else sys.stdout as out:
|
||||
out.write('#define LIBC_EARLY_INIT_NAME {}\n'.format(name))
|
||||
out.write('#define LIBC_EARLY_INIT_NAME_STRING "{}"\n'.format(name))
|
||||
out.write('#define LIBC_EARLY_INIT_GNU_HASH {}\n'.format(
|
||||
gnu_hash(name)))
|
@ -333,10 +333,6 @@ struct rtld_global
|
||||
its link map. */
|
||||
struct link_map *libc_map;
|
||||
|
||||
/* __libc_early_init function in libc_map. Initialized at the
|
||||
same time as libc_map. */
|
||||
void (*libc_map_early_init) (_Bool);
|
||||
|
||||
/* Search table for unique objects. */
|
||||
struct unique_sym_table
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user