This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH] elf: Most symbol lookups cannot deal with unrelocated link maps
- From: Florian Weimer <fweimer at redhat dot com>
- To: libc-alpha at sourceware dot org
- Date: Wed, 11 Sep 2019 13:19:55 +0200
- Subject: [PATCH] elf: Most symbol lookups cannot deal with unrelocated link maps
Lazy binding and dlsym should never pick up not-yet-relocated
objects in the global scope. Especially during lazy binding,
the subsequent call to the symbol will likely result in a
hard-to-diagnose crash.
2019-09-11 Florian Weimer <fweimer@redhat.com>
* sysdeps/generic/ldsodefs.h (DL_LOOKUP_NEED_RELOCATED): Define.
* elf/dl-lookup.c (_dl_lookup_symbol_x): Check for
DL_LOOKUP_NEED_RELOCATED.
* elf/dl-runtime.c (_dl_fixup): Pass DL_LOOKUP_NEED_RELOCATED to
_dl_lookup_symbol_x.
* elf/dl-sym.c (do_sym): Likewise.
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index fd44cd4101..8933dbccb2 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -792,11 +792,13 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
bump_num_relocations ();
- /* No other flag than DL_LOOKUP_ADD_DEPENDENCY or DL_LOOKUP_GSCOPE_LOCK
- is allowed if we look up a versioned symbol. */
+ /* No other flag than DL_LOOKUP_ADD_DEPENDENCY,
+ DL_LOOKUP_GSCOPE_LOCK, DL_LOOKUP_NEED_RELOCATED is allowed if we
+ look up a versioned symbol. */
assert (version == NULL
- || (flags & ~(DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK))
- == 0);
+ || ((flags & ~(DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK
+ | DL_LOOKUP_NEED_RELOCATED))
+ == 0));
size_t i = 0;
if (__glibc_unlikely (skip_map != NULL))
@@ -834,6 +836,32 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
return 0;
}
+ /* Lazy binding and dlsym can only reference relocated objects. */
+ if (flags & DL_LOOKUP_NEED_RELOCATED
+ && !(current_value.m->l_relocated
+ || current_value.m->l_type == lt_executable))
+ {
+ const char *reference_name = undef_map ? undef_map->l_name : "";
+ const char *versionstr = version ? ", version " : "";
+ const char *versionname = (version && version->name
+ ? version->name : "");
+ const char *space = "";
+ const char *target_name = "";
+ if (current_value.m->l_name != NULL
+ && current_value.m->l_name[0] != '\0')
+ {
+ space = " ";
+ target_name = current_value.m->l_name;
+ }
+ struct dl_exception exception;
+ _dl_exception_create_format
+ (&exception, DSO_FILENAME (reference_name),
+ "attempt to bind symbol %s%s%s to unrelocated object%s%s",
+ undef_name, versionstr, versionname, space, target_name);
+ _dl_signal_cexception (0, &exception, N_("symbol lookup error"));
+ _dl_exception_free (&exception);
+ }
+
int protected = (*ref
&& ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED);
if (__glibc_unlikely (protected != 0))
diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c
index 342b794f54..e9612e3f11 100644
--- a/elf/dl-runtime.c
+++ b/elf/dl-runtime.c
@@ -98,7 +98,7 @@ _dl_fixup (
/* We need to keep the scope around so do some locking. This is
not necessary for objects which cannot be unloaded or when
we are not using any threads (yet). */
- int flags = DL_LOOKUP_ADD_DEPENDENCY;
+ int flags = DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_NEED_RELOCATED;
if (!RTLD_SINGLE_THREAD_P)
{
THREAD_GSCOPE_SET_FLAG ();
diff --git a/elf/dl-sym.c b/elf/dl-sym.c
index 8209342b13..78d87ca463 100644
--- a/elf/dl-sym.c
+++ b/elf/dl-sym.c
@@ -104,7 +104,8 @@ do_sym (void *handle, const char *name, void *who,
if (RTLD_SINGLE_THREAD_P)
result = GLRO(dl_lookup_symbol_x) (name, match, &ref,
match->l_scope, vers, 0,
- flags | DL_LOOKUP_ADD_DEPENDENCY,
+ flags | DL_LOOKUP_ADD_DEPENDENCY
+ | DL_LOOKUP_NEED_RELOCATED,
NULL);
else
{
@@ -113,7 +114,8 @@ do_sym (void *handle, const char *name, void *who,
args.map = match;
args.vers = vers;
args.flags
- = flags | DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK;
+ = (flags | DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK
+ | DL_LOOKUP_NEED_RELOCATED);
args.refp = &ref;
THREAD_GSCOPE_SET_FLAG ();
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index f3ba13ee68..6201955b54 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -914,6 +914,8 @@ enum
DL_LOOKUP_RETURN_NEWEST = 2,
/* Set if dl_lookup* called with GSCOPE lock held. */
DL_LOOKUP_GSCOPE_LOCK = 4,
+ /* Require a result in a relocated object. */
+ DL_LOOKUP_NEED_RELOCATED = 8,
};
/* Lookup versioned symbol. */