Avoiding LD_LIBRARY_PATH: The Option

Avoiding LD_LIBRARY_PATH: The Options

With the introduction of the elfedit utility into Solaris, wehave a new answer to the age old question of how to avoideveryones favorite way to get into trouble, the LD_LIBRARY_PATHenvironment variable. This seems like an appropriate time to revisit this topic.

LD_LIBRARY_PATH Seems Useful. What's the Problem?

The problem is that LD_LIBRARY_PATH is a crude tool, and cannot beeasily targeted at a problem program without also hitting otherinnocent programs. Sometimes this overspray is harmless (it costssome time, but doesn't break anything). Other times, it causes a programto link to the wrong version of something, and that program dies inmysterious ways.

Historically, inappropriate use of LD_LIBRARY_PATH might be the#1 one way to get yourself into trouble in an ELF environment.In particular, peoplewho redistribute binaries with instructions for their users to setLD_LIBRARY_PATH in their shell startup scripts are unleashing forcesbeyond their control. Experience tells us that such use is destined to endbadly.

This subject has been written about many times by many people.My colleague Rod Evans wrote about this(LD_LIBRARY_PATH - just say no)for one of his first blog entries.

If you need additional convincing on this point, here are some suggestedGoogle searches you might want to try:

LD_LIBRARY_PATH problem
LD_LIBRARY_PATH bad
LD_LIBRARY_PATH evil
LD_LIBRARY_PATH darkest hell

If LD_LIBRARY_PATH is so bad, why does its use persist?Simply because it is the option of last resort, used when everythingelse has failed. We probably can't eliminate it, but we should strive toreduce its use to the bare minimum.

How to Use, and How To Avoid Using LD_LIBRARY_PATH

The best way to use LD_LIBRARY_PATH is interactively, as a short term aidfor testing or development.A developer might use it to point his test program at an alternativeversion of a library. Beyond that, the less you use it, the betteroff you'll be. With that in mind, here is a list of ways to avoidLD_LIBRARY_PATH. The items are ordered from best to worst, withthe best option right at the top:
  • Explicitly set the correct runpath for the objects you build. If you have the ability to relink the object, youcan always do this, and no other workaround is needed.To set a runpath in an object, use the -R compiler/linker option.

    One common problem that people run into with a built in runpathis the use of an absolute path (e.g. /usr/local/lib). Absolutepaths are no problem for the well known system libraries, becausetheir location is fixed by convention as well as by standards.However, theycan be trouble for libraries supplied by third parties and installedonto the system. Usually the user has a choice of where suchapplications are installed, their home directory, or /usr/localbeing two of the more popular places. An application that hardwires the location of user installed libraries cannot handle this.The solution in this case is to use the $ORIGIN tokenin those runpaths.The $ORIGIN token, which refers to the directory in which the usingobject resides, can be used to set a non-absolute runpath that willwork in any location, as long as the desired libraries resideat a known location relative to the using program. Fortunately,this is often the case.

    For example, consider the case of a 32-bitapplication named myapp, which relies on a sharable library namedmylib.so, as well as on the standard system libraries found in/lib and /usr/lib. The -R option to put the runpath into myappthat will look in these places would be:

    -R '$ORIGIN/../lib:/lib:/usr/lib'
    
    This allows myapp and mylib.so to be installed anywhere, as longas they are kept in the same positions relative to each other.

    Even for system libraries, the use of $ORIGIN can be useful.We use it for all of the linker components inthe system. For instance:

    % elfdump -d /usr/bin/ld | grep RUNPATH
           [7]  RUNPATH           0x2e6               $ORIGIN/../../lib
    
    By setting the runpath using $ORIGIN instead of simply hardwiringthe well known location /lib, we make it easier to test a treeof alternative linker components, such as results when we doa full build of the Solaris ON consolidation. We know that whenwe run a test copy of ld, that it will use the related librariesthat were built with it, instead of binding to the installed systemlibraries.

    There is one exception to the advice to make heavy use of$ORIGIN. The runtime linker will not expand tokens like$ORIGIN for secure (setuid) applications. This should not be aproblem in the vast majority of cases.

  • Many times, the problem comes in the form of open source software that explicitly sets the runpath to an incorrect value for Solaris.Can you fix the configuration script and contribute the changeback to the package maintainer? You'll be doing lots of peoplea favor if you do.
  • If you have an object with a bad runpath (or no runpath) and theobject cannot be rebuilt, it may be possible to alter its runpathusing the elfedit command. Using the myapp example from theprevious item:
    elfedit -e 'dyn:runpath $ORIGIN/../lib:/lib:/usr/lib' myapp
    
    For this option to be possible, you need to berunning a recent version of Solaris that has elfedit,and your object has tohave been linked by aversion of Solaris that has the necessary extra room.Quoting from the elfedit manpage:
    • The desired string must already exist in the dynamic string table, or there must be enough reserved space within this section for the new string to be added. If your object has a string table reservation area, the value of the .dynamic DT_SUNW_STRPAD element indicates the size of the area. The following elfedit command can be used to check this:

      % elfedit -r -e 'dyn:tag DT_SUNW_STRPAD' file
    • The dynamic section must already have a runpath element, or there must be an unused dynamic slot available where one can be inserted. To test for the presence of an existing runpath:

      % elfedit -r -e 'dyn:runpath' file

      A dynamic section uses an element of type DT_NULL to terminate the array found in that section. The final DT_NULL cannot be changed, but if there are more than one of these, elfedit can convert one of them into a runpath element. To test for extra dynamic slots:

      % elfedit -r -e 'dyn:tag DT_NULL' file
  • If your application was linked with the -c option to the linker, then you can use the crle command to alter the configuration fileassociated with the application and change the settings forLD_LIBRARY_PATH that are applied for that application. This is apretty good solution, but is limited by its complexity, and by thefact that the person who linked the object needs to have thoughtahead far enough to provide for this option. Odds are that theydidn't. If they had, they might just as well have set therunpath correctly in the first place, eliminating the need foranything else.

    You can use crle with an application that was not linked with-c, either by setting the LD_CONFIG environment variable, orby modifying the global system configuration file. However, bothof these options suffer from the same issues as the LD_LIBRARY_PATHenvironment variable: They are too coarse grained to be appliedto a single application in a targeted way.

  • If none of the above are possible, then you are indeed stuck with LD_LIBRARY_PATH. In this case, the goal should be to minimize thenumber of applications that see this environment variable. You shouldnever set it in your interactive shell environment (via whatever dot file your shell supports: .profile, .login, .cshrc, .basrc, etc...). Instead, put it in a wrapper shell script that you use to run thespecific program.

    The use of a wrapper script is a pretty safe way to useLD_LIBRARY_PATH, but you should be aware of one limitation ofthis approach: If the program being wrapped starts any otherprograms, then thoseprograms will see the LD_LIBRARY_PATH environment variable.Since programs starting other programs is a common Unix technique,this form of leakage can be more common that you might realize.


Technorati Tag:OpenSolaris
Technorati Tag:Solaris

Comments:

"If LD_LIBRARY_PATH is so bad, why does its use persist?"

The problem persists because very few people know how to compile and link binaries and .so libraries properly (i.e. through the front end driver, `cc`, with "-R/opt/abcd/lib" resp. "-R/opt/abcd/lib/64" set).

Linkers and libraries require very good understanding of the link editor, of the Executable and Linking Format (ELF) and of how the whole process works; this is some highly specialized knowledge, and most "developers" today don't have a clue about it. (I don't have a very high opinion of contemporary "developers", can you tell?)

I'm just so happy to have to recompile tons of binaries just so I can clean up somebody's else mess, and link the binary to have the correct link search paths hardcoded in.

Thankfully, `elfedit` should help a lot fixing these broken binaries. It should prove a highly useful tool. Any timelines as to when it will be backported to Solaris 10?

Posted by UX-admin on November 03, 2007 at 05:33 PM MDT #

There's no plan to backport elfedit to Solaris 10 at this moment, but that could change if there was enough pull. There are 2 issues: (1) There were lots of supporting changes, so this is a big move, and (2) The other linker changes that leave the extra room for runpaths would also need to be present, and the entire system rebuilt with that room. I appreciate how useful that would be though. We'll see what happens... Thanks!

Posted by Ali Bahrami on November 04, 2007 at 12:37 AM MDT #


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值