diff options
author | Florian Weimer <fweimer@redhat.com> | 2016-11-30 15:59:57 +0100 |
---|---|---|
committer | Florian Weimer <fweimer@redhat.com> | 2016-11-30 15:59:57 +0100 |
commit | 9e78f6f6e7134a5f299cc8de77370218f8019237 (patch) | |
tree | 04aa339daf9901b8fc1851353c697528659e7afe /elf/dl-error.c | |
parent | 705a79f82560ff6472cebed86aa5db04cdea3bce (diff) | |
download | glibc-9e78f6f6e7134a5f299cc8de77370218f8019237.tar.gz glibc-9e78f6f6e7134a5f299cc8de77370218f8019237.tar.xz glibc-9e78f6f6e7134a5f299cc8de77370218f8019237.zip |
Implement _dl_catch_error, _dl_signal_error in libc.so [BZ #16628]
This change moves the main implementation of _dl_catch_error, _dl_signal_error to libc.so, where TLS variables can be used directly. This removes a writable function pointer from the rtld_global variable. For use during initial relocation, minimal implementations of these functions are provided in ld.so. These are eventually interposed by the libc.so implementations. This is implemented by compiling elf/dl-error-skeleton.c twice, via elf/dl-error.c and elf/dl-error-minimal.c. As a side effect of this change, the static version of dl-error.c no longer includes support for the _dl_signal_cerror/_dl_receive_error mechanism because it is only used in ld.so.
Diffstat (limited to 'elf/dl-error.c')
-rw-r--r-- | elf/dl-error.c | 210 |
1 files changed, 8 insertions, 202 deletions
diff --git a/elf/dl-error.c b/elf/dl-error.c index bd22ec6cf0..7fe36b4631 100644 --- a/elf/dl-error.c +++ b/elf/dl-error.c @@ -1,4 +1,4 @@ -/* Error handling for runtime dynamic linker. +/* Error handling for runtime dynamic linker, full version. Copyright (C) 1995-2016 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -16,206 +16,12 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ -#include <libintl.h> -#include <setjmp.h> -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <ldsodefs.h> +/* This implementation lives in libc.so because it uses thread-local + data, which is not available in ld.so. It interposes the version + in dl-error-minimal.c after ld.so bootstrap. -/* This structure communicates state between _dl_catch_error and - _dl_signal_error. */ -struct catch - { - const char **objname; /* Object/File name. */ - const char **errstring; /* Error detail filled in here. */ - bool *malloced; /* Nonzero if the string is malloced - by the libc malloc. */ - volatile int *errcode; /* Return value of _dl_signal_error. */ - jmp_buf env; /* longjmp here on error. */ - }; + The signal/catch mechanism is used by the audit framework, which + means that even in ld.so, not all errors are fatal. */ -/* Multiple threads at once can use the `_dl_catch_error' function. The - calls can come from `_dl_map_object_deps', `_dlerror_run', or from - any of the libc functionality which loads dynamic objects (NSS, iconv). - Therefore we have to be prepared to save the state in thread-local - memory. The _dl_error_catch_tsd function pointer is reset by the thread - library so that it returns the address of a thread-local variable. */ - - -/* This message we return as a last resort. We define the string in a - variable since we have to avoid freeing it and so have to enable - a pointer comparison. See below and in dlfcn/dlerror.c. */ -static const char _dl_out_of_memory[] = "out of memory"; - - -/* This points to a function which is called when an continuable error is - received. Unlike the handling of `catch' this function may return. - The arguments will be the `errstring' and `objname'. - - Since this functionality is not used in normal programs (only in ld.so) - we do not care about multi-threaded programs here. We keep this as a - global variable. */ -static receiver_fct receiver; - -#ifdef _LIBC_REENTRANT -# define CATCH_HOOK (*(struct catch **) (*GL(dl_error_catch_tsd)) ()) -#else -static struct catch *catch_hook; -# define CATCH_HOOK catch_hook -#endif - -void -internal_function -_dl_signal_error (int errcode, const char *objname, const char *occation, - const char *errstring) -{ - struct catch *lcatch; - - if (! errstring) - errstring = N_("DYNAMIC LINKER BUG!!!"); - - lcatch = CATCH_HOOK; - if (objname == NULL) - objname = ""; - if (lcatch != NULL) - { - /* We are inside _dl_catch_error. Return to it. We have to - duplicate the error string since it might be allocated on the - stack. The object name is always a string constant. */ - size_t len_objname = strlen (objname) + 1; - size_t len_errstring = strlen (errstring) + 1; - - char *errstring_copy = malloc (len_objname + len_errstring); - if (errstring_copy != NULL) - { - /* Make a copy of the object file name and the error string. */ - *lcatch->objname = memcpy (__mempcpy (errstring_copy, - errstring, len_errstring), - objname, len_objname); - *lcatch->errstring = errstring_copy; - - /* If the main executable is relocated it means the libc's malloc - is used. */ - bool malloced = true; -#ifdef SHARED - malloced = (GL(dl_ns)[LM_ID_BASE]._ns_loaded != NULL - && (GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_relocated != 0)); -#endif - *lcatch->malloced = malloced; - } - else - { - /* This is better than nothing. */ - *lcatch->objname = ""; - *lcatch->errstring = _dl_out_of_memory; - *lcatch->malloced = false; - } - - *lcatch->errcode = errcode; - - /* We do not restore the signal mask because none was saved. */ - __longjmp (lcatch->env[0].__jmpbuf, 1); - } - else - { - /* Lossage while resolving the program's own symbols is always fatal. */ - char buffer[1024]; - _dl_fatal_printf ("%s: %s: %s%s%s%s%s\n", - RTLD_PROGNAME, - occation ?: N_("error while loading shared libraries"), - objname, *objname ? ": " : "", - errstring, errcode ? ": " : "", - (errcode - ? __strerror_r (errcode, buffer, sizeof buffer) - : "")); - } -} - - -void -internal_function -_dl_signal_cerror (int errcode, const char *objname, const char *occation, - const char *errstring) -{ - if (__builtin_expect (GLRO(dl_debug_mask) - & ~(DL_DEBUG_STATISTICS|DL_DEBUG_PRELINK), 0)) - _dl_debug_printf ("%s: error: %s: %s (%s)\n", objname, occation, - errstring, receiver ? "continued" : "fatal"); - - if (receiver) - { - /* We are inside _dl_receive_error. Call the user supplied - handler and resume the work. The receiver will still be - installed. */ - (*receiver) (errcode, objname, errstring); - } - else - _dl_signal_error (errcode, objname, occation, errstring); -} - - -int -internal_function -_dl_catch_error (const char **objname, const char **errstring, - bool *mallocedp, void (*operate) (void *), void *args) -{ - /* We need not handle `receiver' since setting a `catch' is handled - before it. */ - - /* Only this needs to be marked volatile, because it is the only local - variable that gets changed between the setjmp invocation and the - longjmp call. All others are just set here (before setjmp) and read - in _dl_signal_error (before longjmp). */ - volatile int errcode; - - struct catch c; - /* Don't use an initializer since we don't need to clear C.env. */ - c.objname = objname; - c.errstring = errstring; - c.malloced = mallocedp; - c.errcode = &errcode; - - struct catch **const catchp = &CATCH_HOOK; - struct catch *const old = *catchp; - *catchp = &c; - - /* Do not save the signal mask. */ - if (__builtin_expect (__sigsetjmp (c.env, 0), 0) == 0) - { - (*operate) (args); - *catchp = old; - *objname = NULL; - *errstring = NULL; - *mallocedp = false; - return 0; - } - - /* We get here only if we longjmp'd out of OPERATE. _dl_signal_error has - already stored values into *OBJNAME, *ERRSTRING, and *MALLOCEDP. */ - *catchp = old; - return errcode; -} - - -void -internal_function -_dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args) -{ - struct catch **const catchp = &CATCH_HOOK; - struct catch *old_catch; - receiver_fct old_receiver; - - old_catch = *catchp; - old_receiver = receiver; - - /* Set the new values. */ - *catchp = NULL; - receiver = fct; - - (*operate) (args); - - *catchp = old_catch; - receiver = old_receiver; -} +#define DL_ERROR_BOOTSTRAP 0 +#include "dl-error-skeleton.c" |