freeradius: rlm_perl has symbol lookup errors when loading additional perl modules
Hi, I've investigated this bug and found the reason why perl .so's won't load via shared rlm_perl on Debian. rlm_perl will be loaded by freeradius via lt_dlopenext() which proxies to dlopen(). rlm_perl depends on libperl. Thus, libperl will be loaded indirectly by dlopen() using the same flags specified to dlopen() by lt_dlopenext(). On debian, this means, libperl will be loaded _without_ RTDL_GLOBAL being set. On the other hand, when the embedded script tries to load a shared perl extension like Data::Dumper, perl's extension mechanisms will load Dumper.so. But Dumper.so does _not_ depend on libperl, so the dlopen() used to load Dumper.so will 1. not search for symbols in libperl explicitly and 2. not see the symbols from libperl loaded earlier indirectly by lt_dlopenext(), because RTLD_GLOBAL is disabled on debian for valid reasons (see bug #195821). I'm not sure, but I think the correct solution would be to have a shared library dependency from all perl extension modules like Dumper.so on libperl. BTW, a workaround is to start radiusd with LD_PRELOAD=...libperl... pointing to the correct libperl. Of course, this is not feasible for packaging ... Enrik
This one time, at band camp, Enrik Berkhan said:
Hi,
I've investigated this bug and found the reason why perl .so's won't load via shared rlm_perl on Debian.
rlm_perl will be loaded by freeradius via lt_dlopenext() which proxies to dlopen(). rlm_perl depends on libperl. Thus, libperl will be loaded indirectly by dlopen() using the same flags specified to dlopen() by lt_dlopenext(). On debian, this means, libperl will be loaded _without_ RTDL_GLOBAL being set.
On the other hand, when the embedded script tries to load a shared perl extension like Data::Dumper, perl's extension mechanisms will load Dumper.so. But Dumper.so does _not_ depend on libperl, so the dlopen() used to load Dumper.so will
1. not search for symbols in libperl explicitly and
2. not see the symbols from libperl loaded earlier indirectly by lt_dlopenext(), because RTLD_GLOBAL is disabled on debian for valid reasons (see bug #195821).
I'm not sure, but I think the correct solution would be to have a shared library dependency from all perl extension modules like Dumper.so on libperl.
BTW, a workaround is to start radiusd with LD_PRELOAD=...libperl... pointing to the correct libperl. Of course, this is not feasible for packaging ...
Thank you for this comprehensive review and investigation of the problem. This is roughly what we arrived at as well. Sadly, the best place for this to be fixed is in ltdl, and a request has been filed with them to add a function to call dlopen with RTDL_GLOBAL. There is not much we can do now except wait (or use the bundled copy of libltdl in the freeradius source, which feels wrong to me as a distribution choice). Thanks, and take care, -- ----------------------------------------------------------------- | ,''`. Stephen Gran | | : :' : sgran@debian.org | | `. `' Debian user, admin, and developer | | `- http://www.debian.org | -----------------------------------------------------------------
Stephen Gran schrieb:
Thank you for this comprehensive review and investigation of the problem. This is roughly what we arrived at as well. Sadly, the best place for this to be fixed is in ltdl, and a request has been filed with them to add a function to call dlopen with RTDL_GLOBAL. There is not much we can do now except wait (or use the bundled copy of libltdl in the freeradius source, which feels wrong to me as a distribution choice).
How about convincing the perl-packagers to compile their stuff to get shared library dependencies on libperl into their .so's which would be correct in my opinion (argh, maybe iff libperl.so is linked to rlm_perl and not libperl.a ... sigh) I could successfully do the following to test if such an dependency would correct the problem (for Data::Dumper only, of course):
# cd /usr/lib/perl/5.8/auto/Data/Dumper/ # mv Dumper.so Dumper.so.orig # ld -shared -o Dumper.so /usr/lib/perl/5.8/auto/Data/Dumper/Dumper.so.orig -lperl
This effectively makes a new shared library consisting of the required dependencies to load the original Dumper.so and libperl.so just for testing and it works. Maybe it would work to link libperl.a (statically) with rlm_perl to workaround the problem? I haven't tried to, yet. Enrik
Enrik Berkhan wrote:
Maybe it would work to link libperl.a (statically) with rlm_perl to workaround the problem? I haven't tried to, yet.
$ locate libperl.a $ Oops. It would be possible if there *was* a libperl.a. There's no libperl.a, and the libperl.so dependencies aren't set up correctly. I'm curious how *any* application can depend on the perl libraries, like FreeRADIUS does. My conclusion is it can't. The Perl .so's are there for amusement, not for general use. Alan DeKok.
This one time, at band camp, Alan DeKok said:
Enrik Berkhan wrote:
Maybe it would work to link libperl.a (statically) with rlm_perl to workaround the problem? I haven't tried to, yet.
$ locate libperl.a $
Oops.
It would be possible if there *was* a libperl.a. There's no libperl.a, and the libperl.so dependencies aren't set up correctly. I'm curious how *any* application can depend on the perl libraries, like FreeRADIUS does.
My conclusion is it can't. The Perl .so's are there for amusement, not for general use.
steve@gashuffer:~$ dpkg -S libperl.a libperl-dev: /usr/lib/libperl.a -- ----------------------------------------------------------------- | ,''`. Stephen Gran | | : :' : sgran@debian.org | | `. `' Debian user, admin, and developer | | `- http://www.debian.org | -----------------------------------------------------------------
Stephen Gran wrote:
steve@gashuffer:~$ dpkg -S libperl.a libperl-dev: /usr/lib/libperl.a
$ perl -MExtUtils::Embed -e ldopts Outputs "-lperl", among other things. $ perl -MExtUtils::Embed -e ccopts Prints out where the header files are installed. But, of course, you can't *use* those header files to build an application like FreeRADIUS. You can't even believe the "perl ...ldopts" output, because it tells you to use "-lperl", which doesn't work. The solution is simple: a) libperl.a should be installed with Perl, not libperl-dev or b) The output of perl -MExtUtils::Embed -e ldopts / ccopts should stop telling applications that linking will work. It won't. It's lying to you. If the libperl-dev package isn't installed, "perl ... ldopts" should return an error. Every other library FreeRADIUS uses (MySQL, etc.) installs the development library with the development headers. So if the application compiles against the headers, you're pretty sure that it will link, too. In fact, in 8 years of using FreeRADIUS, the only time that *doesn't* happen is when someone installed broken headers/libraries by hand, from a "tar" file. Except for libperl. Alan DeKok.
Alan DeKok schrieb:
b) The output of perl -MExtUtils::Embed -e ldopts / ccopts should stop telling applications that linking will work. It won't. It's lying to you. If the libperl-dev package isn't installed, "perl ... ldopts" should return an error.
That's completely right. Maybe you should reply on Debian Bug #186778 (http://bugs.debian.org/186778). But the package maintainers don't seem to be interested in it :( Enrik
Enrik Berkhan wrote:
Alan DeKok schrieb:
b) The output of perl -MExtUtils::Embed -e ldopts / ccopts should stop telling applications that linking will work. It won't. It's lying to you. If the libperl-dev package isn't installed, "perl ... ldopts" should return an error.
That's completely right. Maybe you should reply on Debian Bug #186778 (http://bugs.debian.org/186778). But the package maintainers don't seem to be interested in it :(
An alternative explanation makes it clearer that this is strictly a debian issue. RTDL_GLOBAL is disabled on Debian for a number of good reasons. This means that an application can link to libfoo.so, and it's symbols aren't exported to other libraries. This limitation prevents a number of bugs from occurring. However, there are cases where you *want* other libraries to use those symbols, as here. Since the system has shared libraries enabled, this means that an application cannot know at compile time which libraries it needs to link to. In this case, Perl supports dynamically loading of Perl modules... which includes shared libraries. If an application links to Perl, *and* the perl scripts load modules dynamically, *then* it will load modules at run-time. Which modules are to be used is not known at compile time. So the application cannot link to every shared library it needs, because it doesn't know which library it needs. Since RTLD_GLOBAL is turned off, the application knows it needs a library, links to it, but those symbols aren't exported to other shared libraries using that one. Since shared library dependencies are broken (Data/Dumper.so doesn't depend on libperl.so), the correct libraries aren't loaded, and the application breaks. Since no static library of libperl.a is supplied by the system, the application can't link to it. If it did exist, it's symbols could be exported, because it isn't a shared library. a) enable RTLD_GLOBAL b) supply libperl.a along with the Perl headers, so "perl -MExtUtils::Embed -e ldopts" stops lying to the application developer that linking works c) fix the inter-library dependencies so that loading Data/Dumper.so (etc) will cause libperl.so to be loaded, too. I understand (a) is undesired. It turns out that linking to libperl.a is almost unworkable, too. FreeRADIUS uses libtool to do cross-platform linking. This means it's very difficult to control which "libperl" is used for linking. The appropriate solution is (c). If there's no RTDL_GLOBAL, then the ONLY way applications can link to shared libraries at run time is if the shared library dependencies are correct. If this isn't done, then Debian systems are the *only* systems where FreeRADIUS can't use libperl. All other systems have working libraries. On top of everything else, 'perl -MExtUtils::Embed -e ldopts' outputs -lperl, but there is NO "libperl.so" on the system. Instead, there's only "libperl.so.5.8". So using Perl to link to the Perl libraries doesn't work. Alan DeKok.
Enrik Berkhan wrote:
Maybe it would work to link libperl.a (statically) with rlm_perl to workaround the problem? I haven't tried to, yet.
No, this won't help. The symbols from the static libperl.a are present in rlm_perl and exported, too, but the dlopen(Dumper.so) from DynaLoader still can't resolve the symbols because rlm_perl had been loaded by lt_dlopenext() without RTLD_GLOBAL, of course. So, no solution for a working standalone freeradius-perl Debian/GNU Linux package, yet :( Enrik
participants (3)
-
Alan DeKok -
Enrik Berkhan -
Stephen Gran