Less known Solaris error messages: "open failed: No such file in secure directories"

I just want to write about a error message people see when they try to force a program to use a different library. Sometimes that’s nescessary, because you want to ensure that an application uses a certain variant of your shared library or you want to use preload a library implementing a system call in a more efficient manner. One example is the improved, multi-thread enabled memory allocator libumem. But somehow you don’t get additional performance but just the error/warning message open failed: No such file in secure directories.
But let’s start at the beginning: Let’s assume you need a better memory allocator for your applications, so you follow the tutorials in the internet and you use preloading to force your applications to use the libumem allocator. Alternative memory allocators are provided by libraries. For example you could use the libmtmalloc or the libumem to use a more speed-effcient malloc/free than in the standard libc implementation. You can directly link your applications to them, but mostly you use a simple trick to force your application to use this libraries. It’s called library interposing. It’s done by preloading the library. The man page of ld.so.1 states on this topic:

Provides a list of shared objects, separated by spaces. These objects are loaded after the program being executed but before any other shared objects that the program references. Symbol definitions provided by the preloaded objects interpose on references made by the shared objects that the program references.

So when you have a malloc in the libc as well as in libumem, and you preload the libumem, your program will use the libumem malloc. Let’s check our super business critical applications touch and ping. At first we check what libraries are loaded by touch:

jmoekamp@hivemind:/$ ldd /usr/bin/touch
        libc.so.1 =>     /lib/libc.so.1
        libm.so.2 =>     /lib/libm.so.2

Now set the LD_PRELOAD_32 environment variable and export it:

jmoekamp@hivemind:/$ LD_PRELOAD_32=libumem.so
jmoekamp@hivemind:/$ export LD_PRELOAD_32 

After this expoert, all programms used in this environment will use the libumem library. When you want to know more about library preloading, you can read more about it in the man page for ld.so.1 Okay, let’s check again, which libraries would be used by the application now.

jmoekamp@hivemind:/$ ldd /usr/bin/touch
        libumem.so =>    /lib/libumem.so
        libc.so.1 =>     /lib/libc.so.1
        libm.so.2 =>     /lib/libm.so.2 

The library libumemwill be preloaded, Now we just try it to execute the file.

jmoekamp@hivemind:/$ touch /tmp/test
jmoekamp@hivemind:/$

No problems. Okay, now let’s try another program:

jmoekamp@hivemind:/$ ping 192.168.2.1
ld.so.1: ping: warning: libumem.so: open failed: No such file in secure directories
192.168.2.1 is alive 

Albeit the programm is working - as the libc contains all nescessary functions - we get an error message. The ld.so.1 complains that there is no secure directory. Secure directory? WTF? At first: Why does touch work, but not ping? Well .. that’s easy. ping is a special program. A normal user don’t have enough privileges to send and receive a ping. So the standard procedure is to make a setuid root binary out of it. By doing so a normal user is capable to use ping You can check this by printing the file metadata …

jmoekamp@hivemind:/$ ls -l /usr/sbin/ping
-r-sr-xr-x 1 root bin 55704 2010-01-25 22:43 /usr/sbin/ping

There is an security mechanism in Solaris preventing an application with setuid getting exploited by preloading a malicous library to carry out an dependency substitution or symbol interposition attack. This mechanism kicks in, when an executable uses setuid and it’s not executed by the owner of the file. It’s not that way, that preloading doesn’t work with setuid binaries. To enable the libraries to be preloaded under this conditions, they have to be in directories that were explicitly configured by the admin as safe (or that were configured per default as secure directories in the factory install). So, where are those secure directories, mentioned here:

jmoekamp@hivemind:/$ ldd /usr/sbin/ping | grep "umem"
        libumem.so =>    (file not found in secure directories) 

Okay, let’s unset the LD_PRELOAD_32 at first, to get rid of this annoying warning message for a time:

jmoekamp@hivemind:/$ unset LD_PRELOAD_32 

You can check the directories where ld searches for libraries with the crle tool. This tool configures the runtime linker environment for your system. With this tool you can specify where the runtime linker of Solaris should search for shared libraries an application needs to run. There are separate configurations for 32-bit and 64-bit code.

jmoekamp@hivemind:/$ crle 

Default configuration file (/var/ld/ld.config) not found
  Platform:     32-bit LSB 80386
  Default Library Path (ELF):   /lib:/usr/lib  (system default)
  Trusted Directories (ELF):    /lib/secure:/usr/lib/secure  (system default)
jmoekamp@hivemind:/$ crle -64

Default configuration file (/var/ld/64/ld.config) not found
  Platform:     64-bit LSB AMD64
  Default Library Path (ELF):   /lib/64:/usr/lib/64  (system default)
  Trusted Directories (ELF):    /lib/secure/64:/usr/lib/secure/64  (system default) 

So the trusted directories are /lib/secure,/usr/lib/secure,/lib/secure/64 und /usr/lib/secure/64. The obvious step would be to add the /lib directory to the trusted directory list. But by doing so all libraries in that directory would be trusted ones, as /lib would be considered as a safe directory. There is a more elegant way to do it: We have already such trusted directories, so we just use them and use symbolic links to place the trusted libraries there.

jmoekamp@hivemind:/# ln -s /lib/64/libumem.so* /lib/secure/64/
jmoekamp@hivemind:/# ln -s /lib/libumem.so* /lib/secure/

When we now look, which libraries are loaded by ping, we will recognize or trusted path:

jmoekamp@hivemind:/$ ldd /usr/sbin/ping | grep "umem"
        libumem.so =>    /lib/secure/libumem.so 

Running the program will now run without an error message:

jmoekamp@hivemind:/$ ping 192.168.2.1
192.168.2.1 is alive 

BTW: It’s the same for 64-bit binaries

jmoekamp@hivemind:/$ LD_PRELOAD_64=libumem.so
jmoekamp@hivemind:/$ export LD_PRELOAD_64
jmoekamp@hivemind:/$ ldd /usr/sbin/amd64/whodo 
        libumem.so =>    /lib/secure/64/libumem.so
        libc.so.1 =>     /lib/64/libc.so.1
        libm.so.2 =>     /lib/64/libm.so.2 

With the both symbolic links you was able to get easily rid of this error message and enable setuid binaries to preload libraries to get the advantages those interposing libraries.