2

I want to use an ancient piece of software (Unreal Tournament "Classic" from 1999, also known as UT99). The dynamic library libtxc_dxtn.so is implicitly loaded, probing for optional S3 texture compression (S3TC) support. Unfortunately, upon loading the library, the main application crashes with a segmentation fault (crash also described here). A workaround seems to be removing the texture compression library for Mesa by deleting or moving libtxc_dxtn.so. The application runs perfectly fine without texture compression, but of course other applications which demand texture compression support are now broken. Naturally, I do not want to modify my system for one specific application.

So my question is:
Can I prevent (as in "mask" or "disable") a specific dynamic library from being loaded by a specific application? I hope to find something like the opposite of LD_PRELOAD.

Update: libtxc_dxtn.so is implicitly and indirectly loaded. Modifying the application binary is not feasible.

initialize program: ut-bin
file=libSDL-1.1.so.0 [0];  needed by ut-bin [0]
file=libGL.so.1 [0];  dynamically loaded by libSDL-1.1.so.0 [0]
file=i965_dri.so [0];  dynamically loaded by libGL.so.1 [0]
file=libtxc_dxtn.so [0];  dynamically loaded by i965_dri.so [0]
Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
Hermann
  • 604
  • 7
  • 23
  • What do you mean _indirectly loaded_? `dlopen()`? If yes, perhaps you could `LD_PRELOAD` a `dlopen()` override that won't let `libtxc_dxtn.so` through. – Petr Skocik Dec 02 '17 at 21:12
  • Yes, `dlopen()` is used. Although by "indirectly loaded" I mean "the library is not loaded by the application itself but rather by a shared library which was, in turn, loaded by the application". In my case, it is `application` → `libSDL-1.1.so.0` → `libGL.so.1` → `i965_dri.so` → `libtxc_dxtn.so`. Only the first library is loaded as a dependency, the others are loaded with `dlopen()`. – Hermann Dec 03 '17 at 10:55
  • The `LD_PRELOAD` of a `dlopen` override approach should work (as long as the dependent libraries aren't using `RTLD_LOCAL`, but that's a deprecated nonstandard flag that shouldn't be used anyway). I've updated my answer. – Petr Skocik Dec 03 '17 at 11:16

1 Answers1

4

There's a utility called patchelf which should allow you to remove the DSO dependency from the executable.

Here's an example that removes a libpthread dependency from a dummy executable:

echo 'int main(){}' | 
    gcc -x c - -Wl,--no-as-needed -lpthread && 
    ldd a.out &&
    patchelf --remove-needed libpthread.so.0 a.out && 
    echo ====== && 
    ldd a.out

My output:

    linux-vdso.so.1 =>  (0x00007ffeced67000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f21560f1000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2155d28000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f215630f000)
======
    linux-vdso.so.1 =>  (0x00007fffac536000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6235c0d000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f6235fd6000)

Update:

If libtxc_dxtn.so is loaded with dlopen, you can preload (LD_PRELOAD) a mini-library that provides a dlopen override that'll return NULL if its filename argument is e.g., "libtxc_dxtn.so" (ltrace should help you find what actual filename arguments you need to guard against). Something like:

#define _GNU_SOURCE
#include <dlfcn.h>
#include <string.h>

void *dlopen(char const *Fnm, int Flg)
{
    void *(*real_dlopen)(char const *,  int);
    *(void**)(&real_dlopen) = dlsym(RTLD_NEXT, "dlopen");
    if(0==strcmp("libtxc_dxtn.so", Fnm)){
        return NULL;
    }else{
        return real_dlopen(Fnm, Flg);   
    }

}
Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
  • 1
    I added a check for `Fnm` being NULL, relaying the call to `real_dlopen`, too. Now this works great. I thank you for your very detailed answer. – Hermann Dec 03 '17 at 13:46
  • For the record, https://stackoverflow.com/questions/6083337/overriding-malloc-using-the-ld-preload-mechanism was helpful in this regard, too. – Hermann Dec 03 '17 at 15:46