7

I use LD_PRELOAD to overwrite the read function. For a minimal test application it works fine, but if I test it with a larger application it does not work anymore. Also LD_DEBUG=all does not show anything at all:

LD_DEBUG=all LD_PRELOAD=./lib.so ./big_app

This just runs ./big_app and LD_PRELOAD has no effect. Is there a way to debug that?

2
  • 1
    Regarding LD_PRELOAD, of course you ensured that real and effective user ids are identical ?
    – MC68020
    Sep 26 at 16:10
  • 2
    Not sure what's the exact difference:) But that just made me question things and I see now that it does not work because of setcap (which is used on the big application) Sep 26 at 16:32

2 Answers 2

19

This answer is only valid for a GNU/Linux environment.

From comments, OP's binary has privilege features added to it: capabilities. This switchs ld.so(8) into secure-execution mode which by default disables most dynamic-linker related environment variables, including LD_PRELOAD and LD_DEBUG.

Secure-execution mode

For security reasons, if the dynamic linker determines that a binary should be run in secure-execution mode, the effects of some environment variables are voided or modified [...]

A binary is executed in secure-execution mode if [...] including:

  • The process's real and effective user IDs differ, or the real and effective group IDs differ. [...]

  • A process with a non-root user ID executed a binary that conferred capabilities to the process.

[...]

However, with root access on the system it's possible to configure it to meet the prerequisites of secure-execution mode for these two parameters when run as non-root, still as described in ld.so(8):

LD_PRELOAD

[...]

In secure-execution mode, preload pathnames containing slashes are ignored. Furthermore, shared objects are preloaded only from the standard search directories and only if they have set-user-ID mode bit enabled (which is not typical).

What are the standard search directories? They are provided with the output of ld.so --help. For example on a Debian amd64/x86_64:

$ ld.so --help
[...]

Shared library search path:
  (libraries located via /etc/ld.so.cache)
  /lib/x86_64-linux-gnu (system search path)
  /usr/lib/x86_64-linux-gnu (system search path)
  /lib (system search path)
  /usr/lib (system search path)

[...]

In the end the shared object file must be in one of these places. From testing it :

  • doesn't have to be owned by root, as long as it has mode u+s set.
  • can be a symlink pointing to the actual u+s file in any place as long as the symlink is in the right place.
  • no path should be present in LD_PRELOAD, only (a) filename(s) without / anywhere.
  • if the binary's capabilities don't grant it arbitrary access to read a file, the shared object can have its mode set so that it allows only a single user or a group (typically chmod o-rwx should be applied and the correct ownership set, then u+s restored). For setuid-root or CAP_DAC_OVERRIDE / CAP_DAC_READ_SEARCH this probably won't prevent the library to be used by any user executing such privileged binary.

LD_DEBUG

[...] Since glibc 2.3.4, LD_DEBUG is ignored in secure-execution mode, unless the file /etc/suid-debug exists (the content of the file is irrelevant).

I didn't find a way to restrict it to only an user or group.

Example (with root access using sudo):

$ sudo touch /etc/suid-debug
$ sudo cp -aiL ./lib.so /usr/lib/lib.so
$ sudo chmod u+s /usr/lib/lib.so

which now allows to run as normal user with both variables taken into account:

LD_DEBUG=all LD_PRELOAD=lib.so ./big_app
1
  • 1
    Thanks a lot for the very detailed and helpful explanations😊 Sep 26 at 20:55
2

You should check whether your executable is statically built or not. If it is, LD env variables won't have any effect.

You can check that with ldd, a utility that will show you shared object dependencies.

If your executable is static, it should print something like:

ldd ./big_app
not a dynamic executable
4
  • Also wonder what it would do with a dynamically linked a.out binary.
    – Joshua
    Sep 27 at 17:47
  • There is no "a.out" binary format AFAIK: a.out is just the default filename when the C compiler produces a binary.
    – U. Windl
    Sep 28 at 7:58
  • 1
    @U.Windl See en.wikipedia.org/wiki/A.out Sep 28 at 15:40
  • I stand corrected.
    – U. Windl
    Sep 29 at 5:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .