7

I'm trying to override malloc/free functions for the program, that requires setuid/setgid permissions. I use the LD_PRELOAD variable for this purpose. According to the ld documentation, I need to put my library into one of the standard search directories (I chose /usr/lib) and give it setuid/setgid permissions. I've done that. However, I still can't link to my .so file, getting the error:

object 'liballoc.so' from LD_PRELOAD cannot be preloaded: ignored

What can be the possible reasons for that? Tested this .so file on programs that don't have setuid/setgid permissions and all works fine. OS: RedHat 7.0

zlatonick
  • 139
  • 6
  • 2
    @ilkkachu linking to a man page doesn't mean you've read it all or understood every possible ramification of it. I speak from personal experience here. "skim, skim, skim, oh fsck why didn't i notice that paragraph earlier". – cas Nov 26 '21 at 04:46
  • Are you running it as root or as a mortal user? If the latter, then `ld.so` will be in secure execution mode. It would help to show the permission bits on `liballoc.so` to confirm that you've set those correctly (IIRC, you need to set the library's setgid and setuid bits to indicate that you intend it to be preloaded into set?id processes). – Toby Speight Nov 26 '21 at 08:13
  • @cas, well, sure. As for that, just saying "read the man page" also doesn't help, since it doesn't tell what part they missed. – ilkkachu Nov 26 '21 at 09:12

3 Answers3

10

According to the ld documentation, I need to put my library into one of the standard search directories (I chose /usr/lib)

That was the mistake. You should've put it in /usr/lib64 (assuming that your machine is a x86_64).

I've just tried the recipe from the manpage on a Centos 7 VM (which should be ~identical to RHEL 7) and it works:

As root:

cynt# cc -shared -fPIC -xc - <<<'char *setlocale(int c, const char *l){ errx(1, "not today"); }' -o /usr/lib64/liblo.so
cynt# chmod 4755 /usr/lib64/liblo.so

As a regular user with a setuid program:

cynt$ LD_PRELOAD=liblo.so su -
su: not today

Whether it's a good idea to use that feature is a totally different matter (IMHO, it isn't).

Toby Speight
  • 8,460
  • 3
  • 26
  • 50
  • 1
    Perhaps it's worth mentioning how to determine which directories are suitable. On my Debian machines, they are listed in `/etc/ld.so.conf` - I guess that's the same on Red Hat? – Toby Speight Nov 26 '21 at 08:08
6

man ld.so

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

  • The process's real and effective user IDs differ

[...]
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).

If a SUID binary is executed then this situation occurs: real UID and effective UID differ. But if this binary executes a different (non-SUID) binary then the EUID of the parent becomes the RUID and EUID of the child:

sudo sleep 1000 &

ps -o pid,ruid,euid,args --pid $! --ppid $!
  PID  RUID  EUID COMMAND
 7286  1000     0 sudo sleep 1000
 7287     0     0 sleep 1000

So if you want to avoid the LD_PRELOAD restrictions you can call your binary via sudo or create a wrapper SUID binary which calls the actual one.

Hauke Laging
  • 88,146
  • 18
  • 125
  • 174
2

The reason for this is to prevent malicious code elevation. A C program does not start running in main(). Instead, the C Runtime Library is called first, which set up its environment (including the STDIO streams), any global variables that aren't compile-time constants, and then calls into main().

A malicious actor can use LD_PRELOAD= to override the libc.o library with a custom library with a modified startup function that does (for example) - restores LD_PRELOAD, and then invokes /bin/sh. If LD_PRELOAD= wasn't ignored for a SUID process, that user could then run /bin/passwd, and they now have a root shell. From there they can now install a rootkit, etc.

CSM
  • 2,090
  • 1
  • 10
  • 7