summaryrefslogtreecommitdiff
path: root/elf
diff options
context:
space:
mode:
Diffstat (limited to 'elf')
-rw-r--r--elf/dl-exception.c11
-rw-r--r--elf/rtld.c1
-rw-r--r--elf/tst-dlmopen-dlerror-mod.c29
-rw-r--r--elf/tst-dlmopen-dlerror.c22
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;
}