<div dir="ltr"><div dir="ltr">Hello Kazu,<br></div><div dir="ltr"><br></div><div dir="ltr"><span class="gmail-im">RTLD_DEEPBIND is not a good way. I'd like to recall the patch.</span><br></div><div>After my research, I find making functions and global variables static within extensions can avoid such problems.</div><div dir="ltr"><br>Taking extensions/trace.so as example, trace_fini and trace_init are non-static functions, if we load trace.so first, everything works fine, but when we rename trace.so to trace2.so and load it again, we are expecting trace_init within trace2.so to be called, but since we have RTLD_GLOBAL, actually it's the trace_init within trace.so to be called. It causes problems because currently some global variables within trace.so are not in their initial status.<br><br>As I quoting dlopen manual:<br>Symbol references in the shared object are resolved using (in order): symbols in the link map of objects loaded for the main program and its dependencies; symbols in shared objects (and their dependencies) that were previously opened with dlopen() using the  RTLD_GLOBAL flag; and definitions in the shared object itself (and any dependencies that were loaded for that object).<br><br>When using readelf --dyn-syms trace.so, for non-static trace_fini and trace_init, I got:<br>Symbol table '.dynsym' contains 66 entries:<br>    ....<br>    64: 0000000000007e65    22 FUNC    GLOBAL DEFAULT   11 trace_fini<br>    65: 0000000000007e3d    40 FUNC    GLOBAL DEFAULT   11 trace_init<br></div><div dir="ltr"><br></div><div dir="ltr">Since I'm not an expert to linkers and loaders, I guess the process is:<br><br>1. when loading trace.so<br>2. ld.so sees trace_init and trace_fini in .dynsym<br>3. ld.so searches the 2 symbols in main program, RTLD_GLOBAL shared objects, and trace.so.<br>4. ld.so finds them in trace.so, resolves their address. <br>5. everything works fine.<br><br>6. when loading trace2.so<br>7. ld.so sees trace_init and trace_fini in .dynsym<br>8. ld.so searches the 2 symbols in main program, RTLD_GLOBAL shared objects, and trace2.so.<br>9. ld.so finds them in RTLD_GLOBAL shared objects(trace.so), resolves their address.<br>10. trace_init in trace.so is called again, but global variables are not in initial status, fails.<br><br>If I make trace_fini and trace_init static, readelf --dyn-syms trace.so will no longer give the 2 symbols in .dynsym, and ld.so will no longer resolve them to the wrong place, then it works fine.<br><br>I think this cannot be a code patch, but a document for future extension developers, if you don't want to export a symbol to subsequent extensions, making it static.<br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Mar 22, 2021 at 1:35 PM HAGIO KAZUHITO(萩尾 一仁) <<a href="mailto:k-hagio-ab@nec.com">k-hagio-ab@nec.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hi Tao Liu,<br>
<br>
-----Original Message-----<br>
> If a same extension(Eg: extensions/trace.so) with two different names are loaded by<br>
> "extend" command twice, it sometimes segfaults crash.<br>
> <br>
> It's because crash uses RTLD_NOW|RTLD_GLOBAL flags of dlopen to load an extension.<br>
> RTDL_GLOBAL will make symbols defined by this shared object available for<br>
> symbol resolution of subsequently loaded shared objects. So symbols with the same<br>
> name will be exported from the former to the latter. In this case, when 2 extensions<br>
> only differ from file names, the subsequently loaded extension will have unexpected<br>
> initial values for global varibles.<br>
<br>
Thanks for the report.<br>
<br>
> This patch adds RTLD_DEEPBIND flag to dlopen, making extensions using its<br>
> own symbols preference to symbols with the same name contained by others.<br>
<br>
This looks a big API change for crash extension modules.<br>
<br>
As far as I've tested, getopt() in an extension module does not work well<br>
with this patch:<br>
<br>
# make extensions<br>
<br>
crash> extend extensions/echo.so<br>
./extensions/echo.so: shared object loaded<br>
crash> echo test<br>
test <br>
crash> echo test<br>
<br>
crash> echo test test2<br>
test2 <br>
crash> echo test test2<br>
<br>
crash> echo test<br>
<br>
crash> echo test test2<br>
<br>
crash> echo test test2 test3<br>
test3<br>
<br>
Can we fix this?  And probably all other modules using getopt() imitates<br>
this echo.c, they will also need to be fixed to adopt the patch.<br>
Also I'm concerned that there might be another regression.<br>
<br>
Do we need to fix the issue at these costs?  or is there any better way?<br>
<br>
Thanks,<br>
Kazu<br>
<br>
> <br>
> Signed-off-by: Tao Liu <<a href="mailto:ltao@redhat.com" target="_blank">ltao@redhat.com</a>><br>
> ---<br>
>  extensions.c | 2 +-<br>
>  1 file changed, 1 insertion(+), 1 deletion(-)<br>
> <br>
> diff --git a/extensions.c b/extensions.c<br>
> index d23b1e3..e07f9a9 100644<br>
> --- a/extensions.c<br>
> +++ b/extensions.c<br>
> @@ -317,7 +317,7 @@ load_extension(char *lib)<br>
>          *  _init() function before dlopen() returns below.<br>
>       */<br>
>       pc->curext = ext;<br>
> -     ext->handle = dlopen(ext->filename, RTLD_NOW|RTLD_GLOBAL);<br>
> +     ext->handle = dlopen(ext->filename, RTLD_NOW|RTLD_GLOBAL|RTLD_DEEPBIND);<br>
> <br>
>       if (!ext->handle) {<br>
>               strcpy(buf, dlerror());<br>
> --<br>
> 2.29.2<br>
> <br>
> --<br>
> Crash-utility mailing list<br>
> <a href="mailto:Crash-utility@redhat.com" target="_blank">Crash-utility@redhat.com</a><br>
> <a href="https://listman.redhat.com/mailman/listinfo/crash-utility" rel="noreferrer" target="_blank">https://listman.redhat.com/mailman/listinfo/crash-utility</a><br>
<br>
<br>
--<br>
Crash-utility mailing list<br>
<a href="mailto:Crash-utility@redhat.com" target="_blank">Crash-utility@redhat.com</a><br>
<a href="https://listman.redhat.com/mailman/listinfo/crash-utility" rel="noreferrer" target="_blank">https://listman.redhat.com/mailman/listinfo/crash-utility</a><br>
<br>
</blockquote></div></div>