From patchwork Wed Sep 11 11:19:55 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 34498 Received: (qmail 129338 invoked by alias); 11 Sep 2019 11:20:00 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 129320 invoked by uid 89); 11 Sep 2019 11:20:00 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-18.5 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_HELO_PASS autolearn=ham version=3.3.1 spammy=vers, *who X-HELO: mx1.redhat.com From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH] elf: Most symbol lookups cannot deal with unrelocated link maps Date: Wed, 11 Sep 2019 13:19:55 +0200 Message-ID: <87mufbulk4.fsf@oldenburg2.str.redhat.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.2 (gnu/linux) MIME-Version: 1.0 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 * 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. */