glibc/elf/tst-initfinilazyfail.c
Florian Weimer 79e0cd7b3c Lazy binding failures during dlopen/dlclose must be fatal [BZ #24304]
If a lazy binding failure happens during the execution of an ELF
constructor or destructor, the dynamic loader catches the error
and reports it using the dlerror mechanism.  This is undesirable
because there could be other constructors and destructors that
need processing (which are skipped), and the process is in an
inconsistent state at this point.  Therefore, we have to issue
a fatal dynamic loader error error and terminate the process.

Note that the _dl_catch_exception in _dl_open is just an inner catch,
to roll back some state locally.  If called from dlopen, there is
still an outer catch, which is why calling _dl_init via call_dl_init
and a no-exception is required and cannot be avoiding by moving the
_dl_init call directly into _dl_open.

_dl_fini does not need changes because it does not install an error
handler, so errors are already fatal there.

Change-Id: I6b1addfe2e30f50a1781595f046f44173db9491a
2019-11-27 20:55:35 +01:00

85 lines
3.0 KiB
C

/* Test that lazy binding failures in constructors and destructors are fatal.
Copyright (C) 2019 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <dlfcn.h>
#include <string.h>
#include <support/capture_subprocess.h>
#include <support/check.h>
#include <support/xdlfcn.h>
static void
test_constructor (void *closure)
{
void *handle = dlopen ("tst-initlazyfailmod.so", RTLD_LAZY);
if (handle == NULL)
FAIL_EXIT (2, "dlopen did not terminate the process: %s", dlerror ());
else
FAIL_EXIT (2, "dlopen did not terminate the process (%p)", handle);
}
static void
test_destructor (void *closure)
{
void *handle = xdlopen ("tst-finilazyfailmod.so", RTLD_LAZY);
int ret = dlclose (handle);
const char *message = dlerror ();
if (message != NULL)
FAIL_EXIT (2, "dlclose did not terminate the process: %d, %s",
ret, message);
else
FAIL_EXIT (2, "dlopen did not terminate the process: %d", ret);
}
static int
do_test (void)
{
{
struct support_capture_subprocess proc
= support_capture_subprocess (test_constructor, NULL);
support_capture_subprocess_check (&proc, "constructor", 127,
sc_allow_stderr);
printf ("info: constructor failure output: [[%s]]\n", proc.err.buffer);
TEST_VERIFY (strstr (proc.err.buffer,
"tst-initfinilazyfail: symbol lookup error: ")
!= NULL);
TEST_VERIFY (strstr (proc.err.buffer,
"tst-initlazyfailmod.so: undefined symbol:"
" undefined_function\n") != NULL);
support_capture_subprocess_free (&proc);
}
{
struct support_capture_subprocess proc
= support_capture_subprocess (test_destructor, NULL);
support_capture_subprocess_check (&proc, "destructor", 127,
sc_allow_stderr);
printf ("info: destructor failure output: [[%s]]\n", proc.err.buffer);
TEST_VERIFY (strstr (proc.err.buffer,
"tst-initfinilazyfail: symbol lookup error: ")
!= NULL);
TEST_VERIFY (strstr (proc.err.buffer,
"tst-finilazyfailmod.so: undefined symbol:"
" undefined_function\n") != NULL);
support_capture_subprocess_free (&proc);
}
return 0;
}
#include <support/test-driver.c>