1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-08-08 17:42:12 +03:00

ld.so: Do not export free/calloc/malloc/realloc functions [BZ #25486]

Exporting functions and relying on symbol interposition from libc.so
makes the choice of implementation dependent on DT_NEEDED order, which
is not what some compiler drivers expect.

This commit replaces one magic mechanism (symbol interposition) with
another one (preprocessor-/compiler-based redirection).  This makes
the hand-over from the minimal malloc to the full malloc more
explicit.

Removing the ABI symbols is backwards-compatible because libc.so is
always in scope, and the dynamic loader will find the malloc-related
symbols there since commit f0b2132b35
("ld.so: Support moving versioned symbols between sonames
[BZ #24741]").

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
This commit is contained in:
Florian Weimer
2020-02-08 19:58:43 +01:00
parent 2efa52c880
commit 3a0ecccb59
60 changed files with 202 additions and 266 deletions

View File

@@ -26,11 +26,87 @@
#include <sys/param.h>
#include <sys/types.h>
#include <ldsodefs.h>
#include <dl-irel.h>
#include <dl-hash.h>
#include <dl-sym-post.h>
#include <_itoa.h>
#include <malloc/malloc-internal.h>
#include <assert.h>
/* The rtld startup code calls __rtld_malloc_init_stubs after the
first self-relocation to adjust the pointers to the minimal
implementation below. Before the final relocation,
__rtld_malloc_init_real is called to replace the pointers with the
real implementation. */
__typeof (calloc) *__rtld_calloc;
__typeof (free) *__rtld_free;
__typeof (malloc) *__rtld_malloc;
__typeof (realloc) *__rtld_realloc;
/* Defined below. */
static __typeof (calloc) rtld_calloc attribute_relro;
static __typeof (free) rtld_free attribute_relro;
static __typeof (malloc) rtld_malloc attribute_relro;
static __typeof (realloc) rtld_realloc attribute_relro;
void
__rtld_malloc_init_stubs (void)
{
__rtld_calloc = &rtld_calloc;
__rtld_free = &rtld_free;
__rtld_malloc = &rtld_malloc;
__rtld_realloc = &rtld_realloc;
}
/* Lookup NAME at VERSION in the scope of MATCH. */
static void *
lookup_malloc_symbol (struct link_map *main_map, const char *name,
struct r_found_version *version)
{
const ElfW(Sym) *ref = NULL;
lookup_t result = _dl_lookup_symbol_x (name, main_map, &ref,
main_map->l_scope,
version, 0, 0, NULL);
assert (ELFW(ST_TYPE) (ref->st_info) != STT_TLS);
void *value = DL_SYMBOL_ADDRESS (result, ref);
return _dl_sym_post (result, ref, value, 0, main_map);
}
void
__rtld_malloc_init_real (struct link_map *main_map)
{
/* We cannot use relocations and initializers for this because the
changes made by __rtld_malloc_init_stubs break REL-style
(non-RELA) relocations that depend on the previous pointer
contents. Also avoid direct relocation depedencies for the
malloc symbols so this function can be called before the final
rtld relocation (which enables RELRO, after which the pointer
variables cannot be written to). */
struct r_found_version version;
version.name = symbol_version_string (libc, GLIBC_2_0);
version.hidden = 0;
version.hash = _dl_elf_hash (version.name);
version.filename = NULL;
void *new_calloc = lookup_malloc_symbol (main_map, "calloc", &version);
void *new_free = lookup_malloc_symbol (main_map, "free", &version);
void *new_malloc = lookup_malloc_symbol (main_map, "malloc", &version);
void *new_realloc = lookup_malloc_symbol (main_map, "realloc", &version);
/* Update the pointers in one go, so that any internal allocations
performed by lookup_malloc_symbol see a consistent
implementation. */
__rtld_calloc = new_calloc;
__rtld_free = new_free;
__rtld_malloc = new_malloc;
__rtld_realloc = new_realloc;
}
/* Minimal malloc allocator for used during initial link. After the
initial link, a full malloc implementation is interposed, either
the one in libc, or a different one supplied by the user through
@@ -38,14 +114,9 @@
static void *alloc_ptr, *alloc_end, *alloc_last_block;
/* Declarations of global functions. */
extern void weak_function free (void *ptr);
extern void * weak_function realloc (void *ptr, size_t n);
/* Allocate an aligned memory block. */
void * weak_function
malloc (size_t n)
static void *
rtld_malloc (size_t n)
{
if (alloc_end == 0)
{
@@ -87,8 +158,8 @@ malloc (size_t n)
/* We use this function occasionally since the real implementation may
be optimized when it can assume the memory it returns already is
set to NUL. */
void * weak_function
calloc (size_t nmemb, size_t size)
static void *
rtld_calloc (size_t nmemb, size_t size)
{
/* New memory from the trivial malloc above is always already cleared.
(We make sure that's true in the rare occasion it might not be,
@@ -104,8 +175,8 @@ calloc (size_t nmemb, size_t size)
}
/* This will rarely be called. */
void weak_function
free (void *ptr)
void
rtld_free (void *ptr)
{
/* We can free only the last block allocated. */
if (ptr == alloc_last_block)
@@ -118,8 +189,8 @@ free (void *ptr)
}
/* This is only called with the most recent block returned by malloc. */
void * weak_function
realloc (void *ptr, size_t n)
void *
rtld_realloc (void *ptr, size_t n)
{
if (ptr == NULL)
return malloc (n);