Loading glibc in a new namespace fails vtable check
Moshe Rubin
moshe.rubin@gmail.com
Sun Sep 29 09:53:49 GMT 2024
Hi Florian,
It is a pleasure discussing glibc with a knowledgeable maintainer as
yourself - thank you.
I tried to reuse your code, but do not have access to the "support" folder,
but was able to reproduce the crash:
<quote>
// To build: g++ fweimer.01.cpp -o fweimer.01 -g -ldl
// To run: ./fweimer.01
#include <gnu/lib-names.h>
#include <stdio.h>
#include <dlfcn.h>
static int
do_test (void)
{
void *handle = dlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW);
FILE* inner_stderr = reinterpret_cast<FILE*>(dlsym (handle, "stderr"));
fputs ("crash?\n", inner_stderr);
return 0;
}
int main(int argc, char*argv[])
{
return do_test();
}
</quote>
Sure enough, the code cause a fatal error:
<backtrace>
(gdb) bt
#0 0x00007ffff7e159fc in pthread_kill () from
/lib/x86_64-linux-gnu/libc.so.6
#1 0x00007ffff7dc1476 in raise () from /lib/x86_64-linux-gnu/libc.so.6
#2 0x00007ffff7da77f3 in abort () from /lib/x86_64-linux-gnu/libc.so.6
#3 0x00007ffff7e083dc in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#4 0x00007ffff7e086f0 in __libc_fatal () from
/lib/x86_64-linux-gnu/libc.so.6
#5 0x00007ffff7e08f79 in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#6 0x00007ffff7dff085 in fwrite () from /lib/x86_64-linux-gnu/libc.so.6
#7 0x00005555555551ee in do_test () at
/homes/mosheru/work/test/use-dlmopen/fweimer.01.cpp:12
#8 0x000055555555520d in main (argc=1, argv=0x7fffffffdd08) at
/homes/mosheru/work/test/use-dlmopen/fweimer.01.cpp:18
</backtrace>
Three questions, if I may:
1. When you refer to inner and initial libc, is the default namespace the
"initial libc", while the second namespace (via dlmopen) is the "inner
libc"? Is there a concept of inner and output libcs when dlmopen is
called? Aren't the namespaces independent of each other, acting in
parallel to each other?
2. Why does my original test program *not* throw a fatal error? It is also
cross-mixing the libc with an inner fwrite() with an initial "stderr"? Is
this what you said is a bug?
3. If LIBC_SO is passed to dlmopen, is the function smart enough to find
the absolute path? In my test code, I read "/proc/self/maps", parsed it,
etc. Is such code unnecessary?
Best regards,
Moshe
On Thu, Sep 26, 2024 at 6:58 PM Florian Weimer <fweimer@redhat.com> wrote:
> * Moshe Rubin:
>
> > libc_fwrite = reinterpret_cast<decltype(libc_fwrite)>(dlsym(handle,
> "fwrite"));
> > size_t ret = libc_fwrite("Hello, world!\n", 1, 14, stderr);
> > printf("ret = %lu\n", ret);
> > </code>
> >
> > Here is the run's output:
> >
> > <output>
> > $ ./minimal_example /usr/lib/x86_64-linux-gnu/libc.so.6
> > glibc path: /usr/lib/x86_64-linux-gnu/libc.so.6
> > fd = 2
> > Hello, world!
> > ret = 14
> > </output>
> >
> > Still no fatal error. I really want to reproduce the fatal error.
>
> The stderr stream should be unbuffered, so fwrite should trigger a
> vtable call.
>
> Maybe what the application does is in the other direction, though: using
> stderr from the inner libc with the initial libc?
>
> That crashes for me:
>
> #include <gnu/lib-names.h>
> #include <stdio.h>
> #include <support/xdlfcn.h>
>
> static int
> do_test (void)
> {
> void *handle = xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW);
> FILE **inner_stderr = xdlsym (handle, "stderr");
> fputs ("crash?\n", *inner_stderr);
> return 0;
> }
>
> #include <support/test-driver.c>
>
> And this is arguably a bug. My original plan was to disable vtable
> hardening when dlmopen is called, but we currently do not do that.
>
> Thanks,
> Florian
>
>
More information about the Libc-help
mailing list