diff options
Diffstat (limited to 'elf')
-rw-r--r-- | elf/dl-exception.c | 11 | ||||
-rw-r--r-- | elf/rtld.c | 1 | ||||
-rw-r--r-- | elf/tst-dlmopen-dlerror-mod.c | 29 | ||||
-rw-r--r-- | elf/tst-dlmopen-dlerror.c | 22 |
4 files changed, 52 insertions, 11 deletions
diff --git a/elf/dl-exception.c b/elf/dl-exception.c index 30adb7d1dc..8eaad418cb 100644 --- a/elf/dl-exception.c +++ b/elf/dl-exception.c @@ -30,6 +30,17 @@ a pointer comparison. See below and in dlfcn/dlerror.c. */ static const char _dl_out_of_memory[] = "out of memory"; +/* Call free in the main libc.so. This allows other namespaces to + free pointers on the main libc heap, via GLRO (dl_error_free). It + also avoids calling free on the special, pre-allocated + out-of-memory error message. */ +void +_dl_error_free (void *ptr) +{ + if (ptr != _dl_out_of_memory) + free (ptr); +} + /* Dummy allocation object used if allocating the message buffer fails. */ static void diff --git a/elf/rtld.c b/elf/rtld.c index fd02438936..c2ca4b7ce3 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -369,6 +369,7 @@ struct rtld_global_ro _rtld_global_ro attribute_relro = ._dl_open = _dl_open, ._dl_close = _dl_close, ._dl_catch_error = _rtld_catch_error, + ._dl_error_free = _dl_error_free, ._dl_tls_get_addr_soft = _dl_tls_get_addr_soft, #ifdef HAVE_DL_DISCOVER_OSVERSION ._dl_discover_osversion = _dl_discover_osversion diff --git a/elf/tst-dlmopen-dlerror-mod.c b/elf/tst-dlmopen-dlerror-mod.c index 7e95dcdeac..051025d3fa 100644 --- a/elf/tst-dlmopen-dlerror-mod.c +++ b/elf/tst-dlmopen-dlerror-mod.c @@ -18,6 +18,8 @@ #include <dlfcn.h> #include <stddef.h> +#include <stdio.h> +#include <string.h> #include <support/check.h> /* Note: This object is not linked into the main program, so we cannot @@ -25,17 +27,32 @@ to use FAIL_EXIT1 (or something else that calls exit). */ void -call_dlsym (void) +call_dlsym (const char *name) { - void *ptr = dlsym (NULL, "does not exist"); + void *ptr = dlsym (NULL, name); if (ptr != NULL) - FAIL_EXIT1 ("dlsym did not fail as expected"); + FAIL_EXIT1 ("dlsym did not fail as expected for: %s", name); + const char *message = dlerror (); + if (strstr (message, ": undefined symbol: does not exist X") == NULL) + FAIL_EXIT1 ("invalid dlsym error message for [[%s]]: %s", name, message); + message = dlerror (); + if (message != NULL) + FAIL_EXIT1 ("second dlsym for [[%s]]: %s", name, message); } void -call_dlopen (void) +call_dlopen (const char *name) { - void *handle = dlopen ("tst-dlmopen-dlerror does not exist", RTLD_NOW); + void *handle = dlopen (name, RTLD_NOW); if (handle != NULL) - FAIL_EXIT1 ("dlopen did not fail as expected"); + FAIL_EXIT1 ("dlopen did not fail as expected for: %s", name); + const char *message = dlerror (); + if (strstr (message, "X: cannot open shared object file:" + " No such file or directory") == NULL + && strstr (message, "X: cannot open shared object file:" + " File name too long") == NULL) + FAIL_EXIT1 ("invalid dlopen error message for [[%s]]: %s", name, message); + message = dlerror (); + if (message != NULL) + FAIL_EXIT1 ("second dlopen for [[%s]]: %s", name, message); } diff --git a/elf/tst-dlmopen-dlerror.c b/elf/tst-dlmopen-dlerror.c index e864d2fe4c..aa3d6598df 100644 --- a/elf/tst-dlmopen-dlerror.c +++ b/elf/tst-dlmopen-dlerror.c @@ -17,6 +17,7 @@ <http://www.gnu.org/licenses/>. */ #include <stddef.h> +#include <string.h> #include <support/check.h> #include <support/xdlfcn.h> @@ -25,11 +26,22 @@ do_test (void) { void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-dlerror-mod.so", RTLD_NOW); - void (*call_dlsym) (void) = xdlsym (handle, "call_dlsym"); - void (*call_dlopen) (void) = xdlsym (handle, "call_dlopen"); - - call_dlsym (); - call_dlopen (); + void (*call_dlsym) (const char *name) = xdlsym (handle, "call_dlsym"); + void (*call_dlopen) (const char *name) = xdlsym (handle, "call_dlopen"); + + /* Iterate over various name lengths. This changes the size of + error messages allocated by ld.so and has been shown to trigger + detectable heap corruption if malloc/free calls in different + namespaces are mixed. */ + char buffer[2048]; + char *buffer_end = &buffer[sizeof (buffer) - 2]; + for (char *p = stpcpy (buffer, "does not exist "); p < buffer_end; ++p) + { + p[0] = 'X'; + p[1] = '\0'; + call_dlsym (buffer); + call_dlopen (buffer); + } return 0; } |